From 3944735190db184478f389800e677c0134313824 Mon Sep 17 00:00:00 2001 From: wellenvogel Date: Thu, 25 Nov 2021 14:31:31 +0100 Subject: [PATCH 1/3] intermediate: reorganize boatData code --- lib/boatData/GwBoatData.cpp | 168 +++++++++++++++++++++++++++++++++++- lib/boatData/GwBoatData.h | 131 +++------------------------- 2 files changed, 179 insertions(+), 120 deletions(-) diff --git a/lib/boatData/GwBoatData.cpp b/lib/boatData/GwBoatData.cpp index 467d71b..585b6d7 100644 --- a/lib/boatData/GwBoatData.cpp +++ b/lib/boatData/GwBoatData.cpp @@ -1,4 +1,153 @@ #include "GwBoatData.h" +#define GWTYPE_DOUBLE 1 +#define GWTYPE_UINT32 2 +#define GWTYPE_UINT16 3 +#define GWTYPE_INT16 4 +#define GWTYPE_USER 100 +class GwBoatItemTypes{ + public: + static int getType(const uint32_t &x){return GWTYPE_UINT32;} + static int getType(const uint16_t &x){return GWTYPE_UINT16;} + static int getType(const int16_t &x){return GWTYPE_INT16;} + static int getType(const double &x){return GWTYPE_DOUBLE;} + static int getType(const GwSatInfoList &x){ return GWTYPE_USER+1;} +}; + +bool GwBoatItemBase::isValid(unsigned long now) const +{ + if (lastSet == 0) + return false; + if (invalidTime == 0) + return true; + if (now == 0) + now = millis(); + return (lastSet + invalidTime) >= now; +} +GwBoatItemBase::GwBoatItemBase(String name, String format, unsigned long invalidTime) +{ + lastSet = 0; + this->invalidTime = invalidTime; + this->name = name; + this->format = format; + this->type = 0; +} + +template GwBoatItem::GwBoatItem(String name,String formatInfo,unsigned long invalidTime,GwBoatItemMap *map): + GwBoatItemBase(name,formatInfo,invalidTime){ + T dummy; + this->type=GwBoatItemTypes::getType(dummy); + if (map){ + (*map)[name]=this; + } + lastUpdateSource=-1; +} + +template +bool GwBoatItem::update(T nv, int source) +{ + unsigned long now = millis(); + if (isValid(now)) + { + //priority handling + //sources with lower ids will win + //and we will not overwrite their value + if (lastUpdateSource < source && lastUpdateSource >= 0) + { + return false; + } + } + data = nv; + lastUpdateSource = source; + uls(now); + return true; +} +template +bool GwBoatItem::updateMax(T nv, int sourceId) +{ + unsigned long now = millis(); + if (!isValid(now)) + { + return update(nv, sourceId); + } + if (getData() < nv) + { + data = nv; + lastUpdateSource = sourceId; + uls(now); + return true; + } + return false; +} +template +void GwBoatItem::toJsonDoc(JsonDocument *doc, unsigned long minTime) +{ + JsonObject o = doc->createNestedObject(name); + o[F("value")] = getData(); + o[F("update")] = minTime - lastSet; + o[F("source")] = lastUpdateSource; + o[F("valid")] = isValid(minTime); + o[F("format")] = format; +} +template class GwBoatItem; +template class GwBoatItem; +template class GwBoatItem; +template class GwBoatItem; +void GwSatInfoList::houseKeeping(unsigned long ts) +{ + if (ts == 0) + ts = millis(); + sats.erase(std::remove_if( + sats.begin(), + sats.end(), + [ts, this](const GwSatInfo &info) + { + return (info.timestamp + lifeTime) < ts; + }), + sats.end()); +} +void GwSatInfoList::update(GwSatInfo entry) +{ + unsigned long now = millis(); + entry.timestamp = now; + for (auto it = sats.begin(); it != sats.end(); it++) + { + if (it->PRN == entry.PRN) + { + *it = entry; + houseKeeping(); + return; + } + } + houseKeeping(); + sats.push_back(entry); +} + +GwBoatDataSatList::GwBoatDataSatList(String name, String formatInfo, unsigned long invalidTime , GwBoatItemMap *map) : + GwBoatItem(name, formatInfo, invalidTime, map) {} + +bool GwBoatDataSatList::update(GwSatInfo info, int source) +{ + unsigned long now = millis(); + if (isValid(now)) + { + //priority handling + //sources with lower ids will win + //and we will not overwrite their value + if (lastUpdateSource < source) + { + return false; + } + } + lastUpdateSource = source; + uls(now); + data.update(info); + return true; +} +void GwBoatDataSatList::toJsonDoc(JsonDocument *doc, unsigned long minTime) +{ + data.houseKeeping(); + GwBoatItem::toJsonDoc(doc, minTime); +} GwBoatData::GwBoatData(GwLog *logger){ this->logger=logger; @@ -23,7 +172,7 @@ template GwBoatItem *GwBoatData::getOrCreate(T initial, GwBoatItemNa } return (GwBoatItem*)(it->second); } - GwBoatItem *rt=new GwBoatItem(GwBoatItemTypes::getType(initial), name, + GwBoatItem *rt=new GwBoatItem(name, provider->getBoatItemFormat(), provider->getInvalidTime(), &values); @@ -101,4 +250,19 @@ double mtr2nm(double m) bool convertToJson(const GwSatInfoList &si,JsonVariant &variant){ return variant.set(si.getNumSats()); -} \ No newline at end of file +} + +#ifdef _UNDEF +#include + +class XWriter{ + public: + void write(uint8_t c) { + } + + void write(const uint8_t* s, size_t n) { + } +}; +static XWriter xwriter; +ARDUINOJSON_NAMESPACE::TextFormatter testWriter(xwriter); +#endif \ No newline at end of file diff --git a/lib/boatData/GwBoatData.h b/lib/boatData/GwBoatData.h index 866d086..4ddf7a9 100644 --- a/lib/boatData/GwBoatData.h +++ b/lib/boatData/GwBoatData.h @@ -7,18 +7,7 @@ #include #define GW_BOAT_VALUE_LEN 32 #define GWSC(name) static constexpr const __FlashStringHelper* name=F(#name) -#define GWTYPE_DOUBLE 1 -#define GWTYPE_UINT32 2 -#define GWTYPE_UINT16 3 -#define GWTYPE_INT16 4 -#define GWTYPE_USER 100 -class GwBoatItemTypes{ - public: - static int getType(const uint32_t &x){return GWTYPE_UINT32;} - static int getType(const uint16_t &x){return GWTYPE_UINT16;} - static int getType(const int16_t &x){return GWTYPE_INT16;} - static int getType(const double &x){return GWTYPE_DOUBLE;} -}; + class GwBoatItemBase{ public: static const unsigned long INVALID_TIME=60000; @@ -49,19 +38,8 @@ class GwBoatItemBase{ public: int getCurrentType(){return type;} unsigned long getLastSet() const {return lastSet;} - bool isValid(unsigned long now=0) const { - if (lastSet == 0) return false; - if (invalidTime == 0) return true; - if (now == 0) now=millis(); - return (lastSet + invalidTime) >= now; - } - GwBoatItemBase(String name,String format,unsigned long invalidTime=INVALID_TIME){ - lastSet=0; - this->invalidTime=invalidTime; - this->name=name; - this->format=format; - this->type=0; - } + bool isValid(unsigned long now=0) const ; + GwBoatItemBase(String name,String format,unsigned long invalidTime=INVALID_TIME); virtual ~GwBoatItemBase(){} void invalidate(){ lastSet=0; @@ -78,43 +56,10 @@ template class GwBoatItem : public GwBoatItemBase{ T data; int lastUpdateSource; public: - GwBoatItem(int type,String name,String formatInfo,unsigned long invalidTime=INVALID_TIME,GwBoatItemMap *map=NULL): - GwBoatItemBase(name,formatInfo,invalidTime){ - this->type=type; - if (map){ - (*map)[name]=this; - } - lastUpdateSource=-1; - } + GwBoatItem(String name,String formatInfo,unsigned long invalidTime=INVALID_TIME,GwBoatItemMap *map=NULL); virtual ~GwBoatItem(){} - bool update(T nv, int source=-1){ - unsigned long now=millis(); - if (isValid(now)){ - //priority handling - //sources with lower ids will win - //and we will not overwrite their value - if (lastUpdateSource < source && lastUpdateSource >= 0){ - return false; - } - } - data=nv; - lastUpdateSource=source; - uls(now); - return true; - } - bool updateMax(T nv,int sourceId=-1){ - unsigned long now=millis(); - if (! isValid(now)){ - return update(nv,sourceId); - } - if (getData() < nv){ - data=nv; - lastUpdateSource=sourceId; - uls(now); - return true; - } - return false; - } + bool update(T nv, int source=-1); + bool updateMax(T nv,int sourceId=-1); T getData(){ return data; } @@ -122,14 +67,7 @@ template class GwBoatItem : public GwBoatItemBase{ if (! isValid(millis())) return defaultv; return data; } - virtual void toJsonDoc(JsonDocument *doc, unsigned long minTime){ - JsonObject o=doc->createNestedObject(name); - o[F("value")]=getData(); - o[F("update")]=minTime-lastSet; - o[F("source")]=lastUpdateSource; - o[F("valid")]=isValid(minTime); - o[F("format")]=format; - } + virtual void toJsonDoc(JsonDocument *doc, unsigned long minTime); virtual int getLastSource(){return lastUpdateSource;} }; double formatCourse(double cv); @@ -151,29 +89,8 @@ class GwSatInfoList{ public: static const unsigned long lifeTime=32000; std::vector sats; - void houseKeeping(unsigned long ts=0){ - if (ts == 0) ts=millis(); - sats.erase(std::remove_if( - sats.begin(), - sats.end(), - [ts,this](const GwSatInfo &info){ - return (info.timestamp + lifeTime) < ts; - } - ),sats.end()); - } - void update(GwSatInfo entry){ - unsigned long now=millis(); - entry.timestamp=now; - for (auto it=sats.begin();it!=sats.end();it++){ - if (it->PRN == entry.PRN){ - *it=entry; - houseKeeping(); - return; - } - } - houseKeeping(); - sats.push_back(entry); - } + void houseKeeping(unsigned long ts=0); + void update(GwSatInfo entry); int getNumSats() const{ return sats.size(); } @@ -183,34 +100,12 @@ class GwSatInfoList{ } }; -bool convertToJson(const GwSatInfoList &si,JsonVariant &variant); class GwBoatDataSatList : public GwBoatItem { public: - GwBoatDataSatList(String name, String formatInfo, unsigned long invalidTime = INVALID_TIME, GwBoatItemMap *map = NULL) : - GwBoatItem(GWTYPE_USER+1, name, formatInfo, invalidTime, map) {} - bool update(GwSatInfo info, int source) - { - unsigned long now = millis(); - if (isValid(now)) - { - //priority handling - //sources with lower ids will win - //and we will not overwrite their value - if (lastUpdateSource < source) - { - return false; - } - } - lastUpdateSource = source; - uls(now); - data.update(info); - return true; - } - virtual void toJsonDoc(JsonDocument *doc, unsigned long minTime){ - data.houseKeeping(); - GwBoatItem::toJsonDoc(doc,minTime); - } + GwBoatDataSatList(String name, String formatInfo, unsigned long invalidTime = INVALID_TIME, GwBoatItemMap *map = NULL); + bool update(GwSatInfo info, int source); + virtual void toJsonDoc(JsonDocument *doc, unsigned long minTime); GwSatInfo *getAt(int idx){ if (! isValid()) return NULL; return data.getAt(idx); @@ -231,7 +126,7 @@ public: virtual ~GwBoatItemNameProvider() {} }; #define GWBOATDATA(type,name,time,fmt) \ - GwBoatItem *name=new GwBoatItem(GwBoatItemTypes::getType((type)0),F(#name),GwBoatItemBase::fmt,time,&values) ; + GwBoatItem *name=new GwBoatItem(F(#name),GwBoatItemBase::fmt,time,&values) ; #define GWSPECBOATDATA(clazz,name,time,fmt) \ clazz *name=new clazz(F(#name),GwBoatItemBase::fmt,time,&values) ; class GwBoatData{ From aae16531ff04714a2e7668b79e30fa94efc35906 Mon Sep 17 00:00:00 2001 From: wellenvogel Date: Thu, 25 Nov 2021 16:43:13 +0100 Subject: [PATCH 2/3] use new api boatDataString for the UI --- lib/boatData/GwBoatData.cpp | 113 +++++++++++++++++++++++++++++++++++- lib/boatData/GwBoatData.h | 25 +++++++- src/main.cpp | 13 +++++ web/index.js | 56 ++++++++++++------ 4 files changed, 183 insertions(+), 24 deletions(-) diff --git a/lib/boatData/GwBoatData.cpp b/lib/boatData/GwBoatData.cpp index 585b6d7..ee7e003 100644 --- a/lib/boatData/GwBoatData.cpp +++ b/lib/boatData/GwBoatData.cpp @@ -1,4 +1,5 @@ #include "GwBoatData.h" +#include #define GWTYPE_DOUBLE 1 #define GWTYPE_UINT32 2 #define GWTYPE_UINT16 3 @@ -30,8 +31,55 @@ GwBoatItemBase::GwBoatItemBase(String name, String format, unsigned long invalid this->name = name; this->format = format; this->type = 0; + this->lastUpdateSource=-1; +} +#define STRING_SIZE 40 +GwBoatItemBase::StringWriter::StringWriter(){ + buffer=new uint8_t[STRING_SIZE]; + wp=buffer; + bufferSize=STRING_SIZE; + buffer [0]=0; +}; +const char *GwBoatItemBase::StringWriter::c_str() const{ + return (const char *)buffer; +} +int GwBoatItemBase::StringWriter::getSize() const{ + return wp-buffer; +} +void GwBoatItemBase::StringWriter::reset(){ + wp=buffer; + *wp=0; +} +void GwBoatItemBase::StringWriter::ensure(size_t size){ + size_t fill=wp-buffer; + size_t newSize=bufferSize; + while ((fill+size) >= (newSize-1) ){ + newSize+=STRING_SIZE; + } + if (newSize != bufferSize){ + uint8_t *newBuffer=new uint8_t[newSize]; + memcpy(newBuffer,buffer,fill); + newBuffer[fill]=0; + delete buffer; + buffer=newBuffer; + wp=newBuffer+fill; + bufferSize=newSize; + } +} +size_t GwBoatItemBase::StringWriter::write(uint8_t c){ + ensure(1); + *wp=c; + wp++; + *wp=0; + return 1; +} +size_t GwBoatItemBase::StringWriter::write(const uint8_t* s, size_t n){ + ensure(n); + memcpy(wp,s,n); + wp+=n; + *wp=0; + return n; } - template GwBoatItem::GwBoatItem(String name,String formatInfo,unsigned long invalidTime,GwBoatItemMap *map): GwBoatItemBase(name,formatInfo,invalidTime){ T dummy; @@ -39,7 +87,6 @@ template GwBoatItem::GwBoatItem(String name,String formatInfo,unsign if (map){ (*map)[name]=this; } - lastUpdateSource=-1; } template @@ -88,6 +135,59 @@ void GwBoatItem::toJsonDoc(JsonDocument *doc, unsigned long minTime) o[F("valid")] = isValid(minTime); o[F("format")] = format; } + + +class WriterWrapper{ + GwBoatItemBase::StringWriter *writer=NULL; + public: + WriterWrapper(GwBoatItemBase::StringWriter *w){ + writer=w; + } + size_t write(uint8_t c){ + if (! writer) return 0; + return writer->write(c); + } + size_t write(const uint8_t* s, size_t n){ + if (! writer) return 0; + return writer->write(s,n); + } +}; +typedef ARDUINOJSON_NAMESPACE::TextFormatter GwTextWriter; + +static void writeToString(GwTextWriter *writer,const double &value){ + writer->writeFloat(value); +} +static void writeToString(GwTextWriter *writer,const uint16_t &value){ + writer->writeInteger(value); +} +static void writeToString(GwTextWriter *writer,const uint32_t &value){ + writer->writeInteger(value); +} +static void writeToString(GwTextWriter *writer,const int16_t &value){ + writer->writeInteger(value); +} +static void writeToString(GwTextWriter *writer,GwSatInfoList &value){ + writer->writeInteger(value.getNumSats()); +} + +template +void GwBoatItem::fillString(){ + writer.reset(); + WriterWrapper wrapper(&writer); + GwTextWriter stringWriter(wrapper); + stringWriter.writeRaw(name.c_str()); + stringWriter.writeChar(','); + stringWriter.writeInteger(isValid()?1:0); + stringWriter.writeChar(','); + stringWriter.writeInteger(lastSet); + stringWriter.writeChar(','); + stringWriter.writeInteger(lastUpdateSource); + stringWriter.writeChar(','); + stringWriter.writeRaw(format.c_str()); + stringWriter.writeChar(','); + writeToString(&stringWriter,data); +} + template class GwBoatItem; template class GwBoatItem; template class GwBoatItem; @@ -214,7 +314,14 @@ String GwBoatData::toJson() const { serializeJson(json,buf); return buf; } - +String GwBoatData::toString(){ + String rt; + for (auto it=values.begin() ; it != values.end();it++){ + rt+=it->second->getDataString(); + rt+="\n"; + } + return rt; +} double formatCourse(double cv) { double rt = cv * 180.0 / M_PI; diff --git a/lib/boatData/GwBoatData.h b/lib/boatData/GwBoatData.h index 4ddf7a9..ba0ec7c 100644 --- a/lib/boatData/GwBoatData.h +++ b/lib/boatData/GwBoatData.h @@ -10,6 +10,19 @@ class GwBoatItemBase{ public: + class StringWriter{ + uint8_t *buffer =NULL; + uint8_t *wp=NULL; + size_t bufferSize=0; + void ensure(size_t size); + public: + StringWriter(); + size_t write(uint8_t c); + size_t write(const uint8_t* s, size_t n); + const char * c_str() const; + int getSize() const; + void reset(); + }; static const unsigned long INVALID_TIME=60000; //the formatter names that must be known in js GWSC(formatCourse); @@ -31,10 +44,12 @@ class GwBoatItemBase{ unsigned long invalidTime=INVALID_TIME; String name; String format; + StringWriter writer; void uls(unsigned long ts=0){ if (ts) lastSet=ts; else lastSet=millis(); } + int lastUpdateSource; public: int getCurrentType(){return type;} unsigned long getLastSet() const {return lastSet;} @@ -44,9 +59,14 @@ class GwBoatItemBase{ void invalidate(){ lastSet=0; } + const char *getDataString(){ + fillString(); + return writer.c_str(); + } + virtual void fillString()=0; virtual void toJsonDoc(JsonDocument *doc, unsigned long minTime)=0; virtual size_t getJsonSize(){return JSON_OBJECT_SIZE(10);} - virtual int getLastSource()=0; + virtual int getLastSource(){return lastUpdateSource;} virtual void refresh(unsigned long ts=0){uls(ts);} String getName(){return name;} }; @@ -54,7 +74,6 @@ class GwBoatData; template class GwBoatItem : public GwBoatItemBase{ protected: T data; - int lastUpdateSource; public: GwBoatItem(String name,String formatInfo,unsigned long invalidTime=INVALID_TIME,GwBoatItemMap *map=NULL); virtual ~GwBoatItem(){} @@ -67,6 +86,7 @@ template class GwBoatItem : public GwBoatItemBase{ if (! isValid(millis())) return defaultv; return data; } + virtual void fillString(); virtual void toJsonDoc(JsonDocument *doc, unsigned long minTime); virtual int getLastSource(){return lastUpdateSource;} }; @@ -178,6 +198,7 @@ class GwBoatData{ template bool update(T value,int source,GwBoatItemNameProvider *provider); template T getDataWithDefault(T defaultv, GwBoatItemNameProvider *provider); String toJson() const; + String toString(); }; diff --git a/src/main.cpp b/src/main.cpp index a2fa2e0..dc73a54 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -420,6 +420,17 @@ protected: result = boatData.toJson(); } }; +class BoatDataStringRequest : public GwRequestMessage +{ +public: + BoatDataStringRequest() : GwRequestMessage(F("text/plain"),F("boatDataString")){}; + +protected: + virtual void processRequest() + { + result = boatData.toString(); + } +}; class XdrExampleRequest : public GwRequestMessage { @@ -562,6 +573,8 @@ void setup() { { return new ResetConfigRequest(); }); webserver.registerMainHandler("/api/boatData", [](AsyncWebServerRequest *request)->GwRequestMessage * { return new BoatDataRequest(); }); + webserver.registerMainHandler("/api/boatDataString", [](AsyncWebServerRequest *request)->GwRequestMessage * + { return new BoatDataStringRequest(); }); webserver.registerMainHandler("/api/xdrExample", [](AsyncWebServerRequest *request)->GwRequestMessage * { String mapping=request->arg("mapping"); diff --git a/web/index.js b/web/index.js index 2b76e50..231acab 100644 --- a/web/index.js +++ b/web/index.js @@ -1035,6 +1035,7 @@ function resizeFont(el,reset,maxIt){ } } function createDashboardItem(name, def, parent) { + if (! def.name) return; let frame = addEl('div', 'dash', parent); let title = addEl('span', 'dashTitle', frame, name); let value = addEl('span', 'dashValue', frame); @@ -1044,22 +1045,35 @@ function createDashboardItem(name, def, parent) { let footer = addEl('div','footer',frame); let src= addEl('span','source',footer); src.setAttribute('id','source_'+name); - let u=fmt?fmt.u:''; - if (! fmt && def.format.match(/formatXdr/)){ + let u=fmt?fmt.u:' '; + if (! fmt && def.format && def.format.match(/formatXdr/)){ u=def.format.replace(/formatXdr/,''); } addEl('span','unit',footer,u); return value; } +function parseBoatDataLine(line){ + let rt={}; + let parts=line.split(','); + rt.name=parts[0]; + rt.valid=parts[1] === '1'; + rt.update=parseInt(parts[2]); + rt.source=parseInt(parts[3]); + rt.format=parts[4]; + rt.value=parts[5]; + return rt; +} function createDashboard() { let frame = document.getElementById('dashboardPage'); if (!frame) return; - getJson("api/boatData").then(function (json) { + getText("api/boatDataString").then(function (txt) { frame.innerHTML = ''; - for (let n in json) { - createDashboardItem(n, json[n], frame); + let values=txt.split('\n'); + for (let n in values) { + let def=parseBoatDataLine(values[n]); + createDashboardItem(def.name, def, frame); } - updateDashboard(json); + updateDashboard(values); }); } function sourceName(v){ @@ -1071,30 +1085,34 @@ function sourceName(v){ } function updateDashboard(data) { let frame = document.getElementById('dashboardPage'); + let names={}; for (let n in data) { - let de = document.getElementById('data_' + n); + let current=parseBoatDataLine(data[n]); + if (! current.name) return; + names[current.name]=true; + let de = document.getElementById('data_' + current.name); if (! de && frame){ - de=createDashboardItem(n,data[n],frame); + de=createDashboardItem(current.name,current,frame); } if (de) { let newContent='----'; - if (data[n].valid) { + if (current.valid) { let formatter; - if (data[n].format && data[n].format != "NULL") { - let key = data[n].format.replace(/^\&/, ''); + if (current.format && current.format != "NULL") { + let key = current.format.replace(/^\&/, ''); formatter = valueFormatters[key]; } if (formatter) { - newContent = formatter.f(data[n].value); + newContent = formatter.f(current.value); } else { - let v = parseFloat(data[n].value); + let v = parseFloat(current.value); if (!isNaN(v)) { v = v.toFixed(3) newContent = v; } else { - newContent = data[n].value; + newContent = current.value; } } } @@ -1104,15 +1122,15 @@ function updateDashboard(data) { resizeFont(de,true); } } - let src=document.getElementById('source_'+n); + let src=document.getElementById('source_'+current.name); if (src){ - src.textContent=sourceName(data[n].source); + src.textContent=sourceName(current.source); } } forEl('.dashValue',function(el){ let id=el.getAttribute('id'); if (id){ - if (! data[id.replace(/^data_/,'')]){ + if (! names[id.replace(/^data_/,'')]){ el.parentElement.remove(); } } @@ -1123,8 +1141,8 @@ window.setInterval(update, 1000); window.setInterval(function () { let dp = document.getElementById('dashboardPage'); if (dp.classList.contains('hidden')) return; - getJson('api/boatData').then(function (data) { - updateDashboard(data); + getText('api/boatDataString').then(function (data) { + updateDashboard(data.split('\n')); }); }, 1000); window.addEventListener('load', function () { From 5b39145e4fb8ebba99d4f93e5379c0763576381d Mon Sep 17 00:00:00 2001 From: wellenvogel Date: Thu, 25 Nov 2021 17:02:42 +0100 Subject: [PATCH 3/3] only recreate value string in boatData if changed --- lib/boatData/GwBoatData.cpp | 5 ++++- lib/boatData/GwBoatData.h | 2 ++ web/index.js | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/boatData/GwBoatData.cpp b/lib/boatData/GwBoatData.cpp index ee7e003..65ba442 100644 --- a/lib/boatData/GwBoatData.cpp +++ b/lib/boatData/GwBoatData.cpp @@ -172,12 +172,15 @@ static void writeToString(GwTextWriter *writer,GwSatInfoList &value){ template void GwBoatItem::fillString(){ + bool valid=isValid(); + if (writer.getSize() && (valid == lastStringValid)) return; + lastStringValid=valid; writer.reset(); WriterWrapper wrapper(&writer); GwTextWriter stringWriter(wrapper); stringWriter.writeRaw(name.c_str()); stringWriter.writeChar(','); - stringWriter.writeInteger(isValid()?1:0); + stringWriter.writeInteger(valid?1:0); stringWriter.writeChar(','); stringWriter.writeInteger(lastSet); stringWriter.writeChar(','); diff --git a/lib/boatData/GwBoatData.h b/lib/boatData/GwBoatData.h index ba0ec7c..c2e68d6 100644 --- a/lib/boatData/GwBoatData.h +++ b/lib/boatData/GwBoatData.h @@ -48,6 +48,7 @@ class GwBoatItemBase{ void uls(unsigned long ts=0){ if (ts) lastSet=ts; else lastSet=millis(); + writer.reset(); //value has changed } int lastUpdateSource; public: @@ -74,6 +75,7 @@ class GwBoatData; template class GwBoatItem : public GwBoatItemBase{ protected: T data; + bool lastStringValid=false; public: GwBoatItem(String name,String formatInfo,unsigned long invalidTime=INVALID_TIME,GwBoatItemMap *map=NULL); virtual ~GwBoatItem(){} diff --git a/web/index.js b/web/index.js index 231acab..697431a 100644 --- a/web/index.js +++ b/web/index.js @@ -1088,7 +1088,7 @@ function updateDashboard(data) { let names={}; for (let n in data) { let current=parseBoatDataLine(data[n]); - if (! current.name) return; + if (! current.name) continue; names[current.name]=true; let de = document.getElementById('data_' + current.name); if (! de && frame){ @@ -1127,6 +1127,7 @@ function updateDashboard(data) { src.textContent=sourceName(current.source); } } + console.log("update"); forEl('.dashValue',function(el){ let id=el.getAttribute('id'); if (id){