From de04e5443b9cd02c1886122de891d4a451796020 Mon Sep 17 00:00:00 2001 From: wellenvogel Date: Sun, 12 Dec 2021 11:47:56 +0100 Subject: [PATCH] optimize boat data string handling --- lib/boatData/GwBoatData.cpp | 348 ++++++++++++++++++++-------------- lib/boatData/GwBoatData.h | 3 + lib/statistics/GwStatistics.h | 2 +- web/index.js | 8 +- 4 files changed, 216 insertions(+), 145 deletions(-) diff --git a/lib/boatData/GwBoatData.cpp b/lib/boatData/GwBoatData.cpp index 80ea23d..91d1bc2 100644 --- a/lib/boatData/GwBoatData.cpp +++ b/lib/boatData/GwBoatData.cpp @@ -7,14 +7,14 @@ #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;} +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 @@ -34,63 +34,84 @@ GwBoatItemBase::GwBoatItemBase(String name, String format, unsigned long invalid this->name = name; this->format = format; this->type = 0; - this->lastUpdateSource=-1; + this->lastUpdateSource = -1; } -size_t GwBoatItemBase::getJsonSize(){return JSON_OBJECT_SIZE(10);} +size_t GwBoatItemBase::getJsonSize() { return JSON_OBJECT_SIZE(10); } #define STRING_SIZE 40 -GwBoatItemBase::StringWriter::StringWriter(){ - buffer=new uint8_t[STRING_SIZE]; - wp=buffer; - bufferSize=STRING_SIZE; - buffer [0]=0; +GwBoatItemBase::StringWriter::StringWriter() +{ + buffer = new uint8_t[STRING_SIZE]; + wp = buffer; + bufferSize = STRING_SIZE; + buffer[0] = 0; }; -const char *GwBoatItemBase::StringWriter::c_str() const{ +const char *GwBoatItemBase::StringWriter::c_str() const +{ return (const char *)buffer; } -int GwBoatItemBase::StringWriter::getSize() const{ - return wp-buffer; +int GwBoatItemBase::StringWriter::getSize() const +{ + int rt=wp - buffer; + if (rt >= baseOffset) rt-=baseOffset; + return rt; } -void GwBoatItemBase::StringWriter::reset(){ - wp=buffer; - *wp=0; +void GwBoatItemBase::StringWriter::setBase() +{ + baseOffset = wp - buffer; } -void GwBoatItemBase::StringWriter::ensure(size_t size){ - size_t fill=wp-buffer; - size_t newSize=bufferSize; - while ((fill+size) >= (newSize-1) ){ - newSize+=STRING_SIZE; +bool GwBoatItemBase::StringWriter::baseFilled() +{ + return baseOffset != 0; +} +void GwBoatItemBase::StringWriter::reset() +{ + wp = buffer + baseOffset; + *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; + 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; + buffer = newBuffer; + wp = newBuffer + fill; + bufferSize = newSize; } } -size_t GwBoatItemBase::StringWriter::write(uint8_t c){ +size_t GwBoatItemBase::StringWriter::write(uint8_t c) +{ ensure(1); - *wp=c; + *wp = c; wp++; - *wp=0; + *wp = 0; return 1; } -size_t GwBoatItemBase::StringWriter::write(const uint8_t* s, size_t n){ +size_t GwBoatItemBase::StringWriter::write(const uint8_t *s, size_t n) +{ ensure(n); - memcpy(wp,s,n); - wp+=n; - *wp=0; + 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; - this->type=GwBoatItemTypes::getType(dummy); - if (map){ - (*map)[name]=this; - } +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; + } } template @@ -140,59 +161,76 @@ void GwBoatItem::toJsonDoc(GwJsonDocument *doc, unsigned long minTime) o[F("format")] = format; } +class WriterWrapper +{ + GwBoatItemBase::StringWriter *writer = NULL; -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); - } +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){ +static void writeToString(GwTextWriter *writer, const double &value) +{ writer->writeFloat(value); } -static void writeToString(GwTextWriter *writer,const uint16_t &value){ +static void writeToString(GwTextWriter *writer, const uint16_t &value) +{ writer->writeInteger(value); } -static void writeToString(GwTextWriter *writer,const uint32_t &value){ +static void writeToString(GwTextWriter *writer, const uint32_t &value) +{ writer->writeInteger(value); } -static void writeToString(GwTextWriter *writer,const int16_t &value){ +static void writeToString(GwTextWriter *writer, const int16_t &value) +{ writer->writeInteger(value); } -static void writeToString(GwTextWriter *writer,GwSatInfoList &value){ +static void writeToString(GwTextWriter *writer, GwSatInfoList &value) +{ writer->writeInteger(value.getNumSats()); } template -void GwBoatItem::fillString(){ - bool valid=isValid(); - if (writer.getSize() && (valid == lastStringValid)) return; - lastStringValid=valid; +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(valid?1:0); + if (!writer.baseFilled()) + { + stringWriter.writeRaw(name.c_str()); + stringWriter.writeChar(','); + stringWriter.writeRaw(format.c_str()); + stringWriter.writeChar(','); + writer.setBase(); + } + stringWriter.writeInteger(valid ? 1 : 0); stringWriter.writeChar(','); stringWriter.writeInteger(lastSet); stringWriter.writeChar(','); stringWriter.writeInteger(lastUpdateSource); stringWriter.writeChar(','); - stringWriter.writeRaw(format.c_str()); - stringWriter.writeChar(','); - writeToString(&stringWriter,data); + writeToString(&stringWriter, data); } template class GwBoatItem; @@ -229,8 +267,7 @@ void GwSatInfoList::update(GwSatInfo entry) sats.push_back(entry); } -GwBoatDataSatList::GwBoatDataSatList(String name, String formatInfo, unsigned long invalidTime , GwBoatItemMap *map) : - GwBoatItem(name, formatInfo, invalidTime, map) {} +GwBoatDataSatList::GwBoatDataSatList(String name, String formatInfo, unsigned long invalidTime, GwBoatItemMap *map) : GwBoatItem(name, formatInfo, invalidTime, map) {} bool GwBoatDataSatList::update(GwSatInfo info, int source) { @@ -256,93 +293,119 @@ void GwBoatDataSatList::toJsonDoc(GwJsonDocument *doc, unsigned long minTime) GwBoatItem::toJsonDoc(doc, minTime); } -GwBoatData::GwBoatData(GwLog *logger){ - this->logger=logger; +GwBoatData::GwBoatData(GwLog *logger) +{ + this->logger = logger; } -GwBoatData::~GwBoatData(){ +GwBoatData::~GwBoatData() +{ GwBoatItemBase::GwBoatItemMap::iterator it; - for (it=values.begin() ; it != values.end();it++){ + for (it = values.begin(); it != values.end(); it++) + { delete it->second; } } -template GwBoatItem *GwBoatData::getOrCreate(T initial, GwBoatItemNameProvider *provider) +template +GwBoatItem *GwBoatData::getOrCreate(T initial, GwBoatItemNameProvider *provider) { - String name=provider->getBoatItemName(); - auto it=values.find(name); - if (it != values.end()) { - int expectedType=GwBoatItemTypes::getType(initial); - if (expectedType != it->second->getCurrentType()){ - LOG_DEBUG(GwLog::DEBUG,"invalid type for boat item %s, expected %d, got %d", - name.c_str(),expectedType,it->second->getCurrentType()); + String name = provider->getBoatItemName(); + auto it = values.find(name); + if (it != values.end()) + { + int expectedType = GwBoatItemTypes::getType(initial); + if (expectedType != it->second->getCurrentType()) + { + LOG_DEBUG(GwLog::DEBUG, "invalid type for boat item %s, expected %d, got %d", + name.c_str(), expectedType, it->second->getCurrentType()); return NULL; } - return (GwBoatItem*)(it->second); + return (GwBoatItem *)(it->second); } - GwBoatItem *rt=new GwBoatItem(name, - provider->getBoatItemFormat(), - provider->getInvalidTime(), - &values); + GwBoatItem *rt = new GwBoatItem(name, + provider->getBoatItemFormat(), + provider->getInvalidTime(), + &values); rt->update(initial); - LOG_DEBUG(GwLog::LOG,"creating boatItem %s, type %d", - name.c_str(),rt->getCurrentType()); + LOG_DEBUG(GwLog::LOG, "creating boatItem %s, type %d", + name.c_str(), rt->getCurrentType()); return rt; } -template bool GwBoatData::update(const T value,int source,GwBoatItemNameProvider *provider){ - GwBoatItem *item=getOrCreate(value,provider); - if (! item) return false; - return item->update(value,source); +template +bool GwBoatData::update(const T value, int source, GwBoatItemNameProvider *provider) +{ + GwBoatItem *item = getOrCreate(value, provider); + if (!item) + return false; + return item->update(value, source); } -template bool GwBoatData::update(double value,int source,GwBoatItemNameProvider *provider); -template T GwBoatData::getDataWithDefault(T defaultv, GwBoatItemNameProvider *provider){ - auto it=values.find(provider->getBoatItemName()); - if (it == values.end()) return defaultv; - int expectedType=GwBoatItemTypes::getType(defaultv); - if (expectedType != it->second->getCurrentType()) return defaultv; +template bool GwBoatData::update(double value, int source, GwBoatItemNameProvider *provider); +template +T GwBoatData::getDataWithDefault(T defaultv, GwBoatItemNameProvider *provider) +{ + auto it = values.find(provider->getBoatItemName()); + if (it == values.end()) + return defaultv; + int expectedType = GwBoatItemTypes::getType(defaultv); + if (expectedType != it->second->getCurrentType()) + return defaultv; return ((GwBoatItem *)(it->second))->getDataWithDefault(defaultv); } template double GwBoatData::getDataWithDefault(double defaultv, GwBoatItemNameProvider *provider); -String GwBoatData::toJson() const { - unsigned long minTime=millis(); +String GwBoatData::toJson() const +{ + unsigned long minTime = millis(); GwBoatItemBase::GwBoatItemMap::const_iterator it; - size_t count=0; - size_t elementSizes=0; - for (it=values.begin() ; it != values.end();it++){ + size_t count = 0; + size_t elementSizes = 0; + for (it = values.begin(); it != values.end(); it++) + { count++; - elementSizes+=it->second->getJsonSize(); + elementSizes += it->second->getJsonSize(); } - int sz=JSON_OBJECT_SIZE(count)+elementSizes+10; - LOG_DEBUG(GwLog::DEBUG,"size for boatData: %d",sz); + int sz = JSON_OBJECT_SIZE(count) + elementSizes + 10; + LOG_DEBUG(GwLog::DEBUG, "size for boatData: %d", sz); GwJsonDocument json(sz); - for (it=values.begin() ; it != values.end();it++){ - it->second->toJsonDoc(&json,minTime); + for (it = values.begin(); it != values.end(); it++) + { + it->second->toJsonDoc(&json, minTime); } String buf; - serializeJson(json,buf); + serializeJson(json, buf); return buf; } -String GwBoatData::toString(){ +String GwBoatData::toString() +{ String rt; - for (auto it=values.begin() ; it != values.end();it++){ - rt+=it->second->getDataString(); - rt+="\n"; + rt.reserve(values.size() * 80); + for (auto it = values.begin(); it != values.end(); it++) + { + rt += it->second->getDataString(); + rt += "\n"; } return rt; } -bool GwBoatData::isValid(String name){ - auto it=values.find(name); - if (it == values.end()) return false; +bool GwBoatData::isValid(String name) +{ + auto it = values.find(name); + if (it == values.end()) + return false; return it->second->isValid(); } -GwBoatItemBase* GwBoatData::getBase(String name){ - auto it=values.find(name); - if (it == values.end()) return NULL; +GwBoatItemBase *GwBoatData::getBase(String name) +{ + auto it = values.find(name); + if (it == values.end()) + return NULL; return it->second; } -double GwBoatData::getDoubleValue(String name,double defaultv){ - auto it=values.find(name); - if (it == values.end()) return defaultv; - if (! it->second->isValid()) return defaultv; +double GwBoatData::getDoubleValue(String name, double defaultv) +{ + auto it = values.find(name); + if (it == values.end()) + return defaultv; + if (!it->second->isValid()) + return defaultv; return it->second->getDoubleValue(); } double formatCourse(double cv) @@ -354,8 +417,9 @@ double formatCourse(double cv) rt += 360; return rt; } -double formatDegToRad(double deg){ - return deg/180.0 * M_PI; +double formatDegToRad(double deg) +{ + return deg / 180.0 * M_PI; } double formatWind(double cv) { @@ -378,20 +442,24 @@ double mtr2nm(double m) return m / 1852.0; } -bool convertToJson(const GwSatInfoList &si,JsonVariant &variant){ +bool convertToJson(const GwSatInfoList &si, JsonVariant &variant) +{ return variant.set(si.getNumSats()); } #ifdef _UNDEF #include -class XWriter{ - public: - void write(uint8_t c) { +class XWriter +{ +public: + void write(uint8_t c) + { } - void write(const uint8_t* s, size_t n) { - } + void write(const uint8_t *s, size_t n) + { + } }; static XWriter xwriter; ARDUINOJSON_NAMESPACE::TextFormatter testWriter(xwriter); diff --git a/lib/boatData/GwBoatData.h b/lib/boatData/GwBoatData.h index 855491d..8f6adb6 100644 --- a/lib/boatData/GwBoatData.h +++ b/lib/boatData/GwBoatData.h @@ -14,6 +14,7 @@ class GwBoatItemBase{ uint8_t *buffer =NULL; uint8_t *wp=NULL; size_t bufferSize=0; + size_t baseOffset=0; void ensure(size_t size); public: StringWriter(); @@ -21,6 +22,8 @@ class GwBoatItemBase{ size_t write(const uint8_t* s, size_t n); const char * c_str() const; int getSize() const; + void setBase(); + bool baseFilled(); void reset(); }; static const unsigned long INVALID_TIME=60000; diff --git a/lib/statistics/GwStatistics.h b/lib/statistics/GwStatistics.h index 2feb232..b2efec8 100644 --- a/lib/statistics/GwStatistics.h +++ b/lib/statistics/GwStatistics.h @@ -119,6 +119,6 @@ class TimeMonitor{ current[index]=now; int64_t currentv=now-sv; if ((now-start) > max) max=now-start; - times[index-1]->add(currentv); + times[index]->add(currentv); } }; diff --git a/web/index.js b/web/index.js index bc627ca..afd1ecb 100644 --- a/web/index.js +++ b/web/index.js @@ -1205,10 +1205,10 @@ 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.valid=parts[2] === '1'; + rt.update=parseInt(parts[3]); + rt.source=parseInt(parts[4]); + rt.format=parts[1]; rt.value=parts[5]; return rt; }