optimize boat data string handling

This commit is contained in:
wellenvogel 2021-12-12 11:47:56 +01:00
parent e08bcf1009
commit de04e5443b
4 changed files with 216 additions and 145 deletions

View File

@ -7,14 +7,14 @@
#define GWTYPE_INT16 4 #define GWTYPE_INT16 4
#define GWTYPE_USER 100 #define GWTYPE_USER 100
class GwBoatItemTypes
class GwBoatItemTypes{ {
public: public:
static int getType(const uint32_t &x){return GWTYPE_UINT32;} static int getType(const uint32_t &x) { return GWTYPE_UINT32; }
static int getType(const uint16_t &x){return GWTYPE_UINT16;} static int getType(const uint16_t &x) { return GWTYPE_UINT16; }
static int getType(const int16_t &x){return GWTYPE_INT16;} static int getType(const int16_t &x) { return GWTYPE_INT16; }
static int getType(const double &x){return GWTYPE_DOUBLE;} static int getType(const double &x) { return GWTYPE_DOUBLE; }
static int getType(const GwSatInfoList &x){ return GWTYPE_USER+1;} static int getType(const GwSatInfoList &x) { return GWTYPE_USER + 1; }
}; };
bool GwBoatItemBase::isValid(unsigned long now) const bool GwBoatItemBase::isValid(unsigned long now) const
@ -34,63 +34,84 @@ GwBoatItemBase::GwBoatItemBase(String name, String format, unsigned long invalid
this->name = name; this->name = name;
this->format = format; this->format = format;
this->type = 0; 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 #define STRING_SIZE 40
GwBoatItemBase::StringWriter::StringWriter(){ GwBoatItemBase::StringWriter::StringWriter()
buffer=new uint8_t[STRING_SIZE]; {
wp=buffer; buffer = new uint8_t[STRING_SIZE];
bufferSize=STRING_SIZE; wp = buffer;
buffer [0]=0; bufferSize = STRING_SIZE;
buffer[0] = 0;
}; };
const char *GwBoatItemBase::StringWriter::c_str() const{ const char *GwBoatItemBase::StringWriter::c_str() const
{
return (const char *)buffer; return (const char *)buffer;
} }
int GwBoatItemBase::StringWriter::getSize() const{ int GwBoatItemBase::StringWriter::getSize() const
return wp-buffer; {
int rt=wp - buffer;
if (rt >= baseOffset) rt-=baseOffset;
return rt;
} }
void GwBoatItemBase::StringWriter::reset(){ void GwBoatItemBase::StringWriter::setBase()
wp=buffer; {
*wp=0; baseOffset = wp - buffer;
} }
void GwBoatItemBase::StringWriter::ensure(size_t size){ bool GwBoatItemBase::StringWriter::baseFilled()
size_t fill=wp-buffer; {
size_t newSize=bufferSize; return baseOffset != 0;
while ((fill+size) >= (newSize-1) ){ }
newSize+=STRING_SIZE; 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){ if (newSize != bufferSize)
uint8_t *newBuffer=new uint8_t[newSize]; {
memcpy(newBuffer,buffer,fill); uint8_t *newBuffer = new uint8_t[newSize];
newBuffer[fill]=0; memcpy(newBuffer, buffer, fill);
newBuffer[fill] = 0;
delete buffer; delete buffer;
buffer=newBuffer; buffer = newBuffer;
wp=newBuffer+fill; wp = newBuffer + fill;
bufferSize=newSize; bufferSize = newSize;
} }
} }
size_t GwBoatItemBase::StringWriter::write(uint8_t c){ size_t GwBoatItemBase::StringWriter::write(uint8_t c)
{
ensure(1); ensure(1);
*wp=c; *wp = c;
wp++; wp++;
*wp=0; *wp = 0;
return 1; 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); ensure(n);
memcpy(wp,s,n); memcpy(wp, s, n);
wp+=n; wp += n;
*wp=0; *wp = 0;
return n; return n;
} }
template<class T> GwBoatItem<T>::GwBoatItem(String name,String formatInfo,unsigned long invalidTime,GwBoatItemMap *map): template <class T>
GwBoatItemBase(name,formatInfo,invalidTime){ GwBoatItem<T>::GwBoatItem(String name, String formatInfo, unsigned long invalidTime, GwBoatItemMap *map) : GwBoatItemBase(name, formatInfo, invalidTime)
T dummy; {
this->type=GwBoatItemTypes::getType(dummy); T dummy;
if (map){ this->type = GwBoatItemTypes::getType(dummy);
(*map)[name]=this; if (map)
} {
(*map)[name] = this;
}
} }
template <class T> template <class T>
@ -140,59 +161,76 @@ void GwBoatItem<T>::toJsonDoc(GwJsonDocument *doc, unsigned long minTime)
o[F("format")] = format; o[F("format")] = format;
} }
class WriterWrapper
{
GwBoatItemBase::StringWriter *writer = NULL;
class WriterWrapper{ public:
GwBoatItemBase::StringWriter *writer=NULL; WriterWrapper(GwBoatItemBase::StringWriter *w)
public: {
WriterWrapper(GwBoatItemBase::StringWriter *w){ writer = w;
writer=w; }
} size_t write(uint8_t c)
size_t write(uint8_t c){ {
if (! writer) return 0; if (!writer)
return writer->write(c); return 0;
} return writer->write(c);
size_t write(const uint8_t* s, size_t n){ }
if (! writer) return 0; size_t write(const uint8_t *s, size_t n)
return writer->write(s,n); {
} if (!writer)
return 0;
return writer->write(s, n);
}
}; };
typedef ARDUINOJSON_NAMESPACE::TextFormatter<WriterWrapper> GwTextWriter; typedef ARDUINOJSON_NAMESPACE::TextFormatter<WriterWrapper> GwTextWriter;
static void writeToString(GwTextWriter *writer,const double &value){ static void writeToString(GwTextWriter *writer, const double &value)
{
writer->writeFloat(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); writer->writeInteger(value);
} }
static void writeToString(GwTextWriter *writer,const uint32_t &value){ static void writeToString(GwTextWriter *writer, const uint32_t &value)
{
writer->writeInteger(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); writer->writeInteger(value);
} }
static void writeToString(GwTextWriter *writer,GwSatInfoList &value){ static void writeToString(GwTextWriter *writer, GwSatInfoList &value)
{
writer->writeInteger(value.getNumSats()); writer->writeInteger(value.getNumSats());
} }
template <class T> template <class T>
void GwBoatItem<T>::fillString(){ void GwBoatItem<T>::fillString()
bool valid=isValid(); {
if (writer.getSize() && (valid == lastStringValid)) return; bool valid = isValid();
lastStringValid=valid; if (writer.getSize() && (valid == lastStringValid))
return;
lastStringValid = valid;
writer.reset(); writer.reset();
WriterWrapper wrapper(&writer); WriterWrapper wrapper(&writer);
GwTextWriter stringWriter(wrapper); GwTextWriter stringWriter(wrapper);
stringWriter.writeRaw(name.c_str()); if (!writer.baseFilled())
stringWriter.writeChar(','); {
stringWriter.writeInteger(valid?1:0); stringWriter.writeRaw(name.c_str());
stringWriter.writeChar(',');
stringWriter.writeRaw(format.c_str());
stringWriter.writeChar(',');
writer.setBase();
}
stringWriter.writeInteger(valid ? 1 : 0);
stringWriter.writeChar(','); stringWriter.writeChar(',');
stringWriter.writeInteger(lastSet); stringWriter.writeInteger(lastSet);
stringWriter.writeChar(','); stringWriter.writeChar(',');
stringWriter.writeInteger(lastUpdateSource); stringWriter.writeInteger(lastUpdateSource);
stringWriter.writeChar(','); stringWriter.writeChar(',');
stringWriter.writeRaw(format.c_str()); writeToString(&stringWriter, data);
stringWriter.writeChar(',');
writeToString(&stringWriter,data);
} }
template class GwBoatItem<double>; template class GwBoatItem<double>;
@ -229,8 +267,7 @@ void GwSatInfoList::update(GwSatInfo entry)
sats.push_back(entry); sats.push_back(entry);
} }
GwBoatDataSatList::GwBoatDataSatList(String name, String formatInfo, unsigned long invalidTime , GwBoatItemMap *map) : GwBoatDataSatList::GwBoatDataSatList(String name, String formatInfo, unsigned long invalidTime, GwBoatItemMap *map) : GwBoatItem<GwSatInfoList>(name, formatInfo, invalidTime, map) {}
GwBoatItem<GwSatInfoList>(name, formatInfo, invalidTime, map) {}
bool GwBoatDataSatList::update(GwSatInfo info, int source) bool GwBoatDataSatList::update(GwSatInfo info, int source)
{ {
@ -256,93 +293,119 @@ void GwBoatDataSatList::toJsonDoc(GwJsonDocument *doc, unsigned long minTime)
GwBoatItem<GwSatInfoList>::toJsonDoc(doc, minTime); GwBoatItem<GwSatInfoList>::toJsonDoc(doc, minTime);
} }
GwBoatData::GwBoatData(GwLog *logger){ GwBoatData::GwBoatData(GwLog *logger)
this->logger=logger; {
this->logger = logger;
} }
GwBoatData::~GwBoatData(){ GwBoatData::~GwBoatData()
{
GwBoatItemBase::GwBoatItemMap::iterator it; GwBoatItemBase::GwBoatItemMap::iterator it;
for (it=values.begin() ; it != values.end();it++){ for (it = values.begin(); it != values.end(); it++)
{
delete it->second; delete it->second;
} }
} }
template<class T> GwBoatItem<T> *GwBoatData::getOrCreate(T initial, GwBoatItemNameProvider *provider) template <class T>
GwBoatItem<T> *GwBoatData::getOrCreate(T initial, GwBoatItemNameProvider *provider)
{ {
String name=provider->getBoatItemName(); String name = provider->getBoatItemName();
auto it=values.find(name); auto it = values.find(name);
if (it != values.end()) { if (it != values.end())
int expectedType=GwBoatItemTypes::getType(initial); {
if (expectedType != it->second->getCurrentType()){ int expectedType = GwBoatItemTypes::getType(initial);
LOG_DEBUG(GwLog::DEBUG,"invalid type for boat item %s, expected %d, got %d", if (expectedType != it->second->getCurrentType())
name.c_str(),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 NULL;
} }
return (GwBoatItem<T>*)(it->second); return (GwBoatItem<T> *)(it->second);
} }
GwBoatItem<T> *rt=new GwBoatItem<T>(name, GwBoatItem<T> *rt = new GwBoatItem<T>(name,
provider->getBoatItemFormat(), provider->getBoatItemFormat(),
provider->getInvalidTime(), provider->getInvalidTime(),
&values); &values);
rt->update(initial); rt->update(initial);
LOG_DEBUG(GwLog::LOG,"creating boatItem %s, type %d", LOG_DEBUG(GwLog::LOG, "creating boatItem %s, type %d",
name.c_str(),rt->getCurrentType()); name.c_str(), rt->getCurrentType());
return rt; return rt;
} }
template<class T> bool GwBoatData::update(const T value,int source,GwBoatItemNameProvider *provider){ template <class T>
GwBoatItem<T> *item=getOrCreate(value,provider); bool GwBoatData::update(const T value, int source, GwBoatItemNameProvider *provider)
if (! item) return false; {
return item->update(value,source); GwBoatItem<T> *item = getOrCreate(value, provider);
if (!item)
return false;
return item->update(value, source);
} }
template bool GwBoatData::update<double>(double value,int source,GwBoatItemNameProvider *provider); template bool GwBoatData::update<double>(double value, int source, GwBoatItemNameProvider *provider);
template<class T> T GwBoatData::getDataWithDefault(T defaultv, GwBoatItemNameProvider *provider){ template <class T>
auto it=values.find(provider->getBoatItemName()); T GwBoatData::getDataWithDefault(T defaultv, GwBoatItemNameProvider *provider)
if (it == values.end()) return defaultv; {
int expectedType=GwBoatItemTypes::getType(defaultv); auto it = values.find(provider->getBoatItemName());
if (expectedType != it->second->getCurrentType()) return defaultv; if (it == values.end())
return defaultv;
int expectedType = GwBoatItemTypes::getType(defaultv);
if (expectedType != it->second->getCurrentType())
return defaultv;
return ((GwBoatItem<T> *)(it->second))->getDataWithDefault(defaultv); return ((GwBoatItem<T> *)(it->second))->getDataWithDefault(defaultv);
} }
template double GwBoatData::getDataWithDefault<double>(double defaultv, GwBoatItemNameProvider *provider); template double GwBoatData::getDataWithDefault<double>(double defaultv, GwBoatItemNameProvider *provider);
String GwBoatData::toJson() const { String GwBoatData::toJson() const
unsigned long minTime=millis(); {
unsigned long minTime = millis();
GwBoatItemBase::GwBoatItemMap::const_iterator it; GwBoatItemBase::GwBoatItemMap::const_iterator it;
size_t count=0; size_t count = 0;
size_t elementSizes=0; size_t elementSizes = 0;
for (it=values.begin() ; it != values.end();it++){ for (it = values.begin(); it != values.end(); it++)
{
count++; count++;
elementSizes+=it->second->getJsonSize(); elementSizes += it->second->getJsonSize();
} }
int sz=JSON_OBJECT_SIZE(count)+elementSizes+10; int sz = JSON_OBJECT_SIZE(count) + elementSizes + 10;
LOG_DEBUG(GwLog::DEBUG,"size for boatData: %d",sz); LOG_DEBUG(GwLog::DEBUG, "size for boatData: %d", sz);
GwJsonDocument json(sz); GwJsonDocument json(sz);
for (it=values.begin() ; it != values.end();it++){ for (it = values.begin(); it != values.end(); it++)
it->second->toJsonDoc(&json,minTime); {
it->second->toJsonDoc(&json, minTime);
} }
String buf; String buf;
serializeJson(json,buf); serializeJson(json, buf);
return buf; return buf;
} }
String GwBoatData::toString(){ String GwBoatData::toString()
{
String rt; String rt;
for (auto it=values.begin() ; it != values.end();it++){ rt.reserve(values.size() * 80);
rt+=it->second->getDataString(); for (auto it = values.begin(); it != values.end(); it++)
rt+="\n"; {
rt += it->second->getDataString();
rt += "\n";
} }
return rt; return rt;
} }
bool GwBoatData::isValid(String name){ bool GwBoatData::isValid(String name)
auto it=values.find(name); {
if (it == values.end()) return false; auto it = values.find(name);
if (it == values.end())
return false;
return it->second->isValid(); return it->second->isValid();
} }
GwBoatItemBase* GwBoatData::getBase(String name){ GwBoatItemBase *GwBoatData::getBase(String name)
auto it=values.find(name); {
if (it == values.end()) return NULL; auto it = values.find(name);
if (it == values.end())
return NULL;
return it->second; return it->second;
} }
double GwBoatData::getDoubleValue(String name,double defaultv){ double GwBoatData::getDoubleValue(String name, double defaultv)
auto it=values.find(name); {
if (it == values.end()) return defaultv; auto it = values.find(name);
if (! it->second->isValid()) return defaultv; if (it == values.end())
return defaultv;
if (!it->second->isValid())
return defaultv;
return it->second->getDoubleValue(); return it->second->getDoubleValue();
} }
double formatCourse(double cv) double formatCourse(double cv)
@ -354,8 +417,9 @@ double formatCourse(double cv)
rt += 360; rt += 360;
return rt; return rt;
} }
double formatDegToRad(double deg){ double formatDegToRad(double deg)
return deg/180.0 * M_PI; {
return deg / 180.0 * M_PI;
} }
double formatWind(double cv) double formatWind(double cv)
{ {
@ -378,20 +442,24 @@ double mtr2nm(double m)
return m / 1852.0; return m / 1852.0;
} }
bool convertToJson(const GwSatInfoList &si,JsonVariant &variant){ bool convertToJson(const GwSatInfoList &si, JsonVariant &variant)
{
return variant.set(si.getNumSats()); return variant.set(si.getNumSats());
} }
#ifdef _UNDEF #ifdef _UNDEF
#include <ArduinoJson/Json/TextFormatter.hpp> #include <ArduinoJson/Json/TextFormatter.hpp>
class XWriter{ class XWriter
public: {
void write(uint8_t c) { 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; static XWriter xwriter;
ARDUINOJSON_NAMESPACE::TextFormatter<XWriter> testWriter(xwriter); ARDUINOJSON_NAMESPACE::TextFormatter<XWriter> testWriter(xwriter);

View File

@ -14,6 +14,7 @@ class GwBoatItemBase{
uint8_t *buffer =NULL; uint8_t *buffer =NULL;
uint8_t *wp=NULL; uint8_t *wp=NULL;
size_t bufferSize=0; size_t bufferSize=0;
size_t baseOffset=0;
void ensure(size_t size); void ensure(size_t size);
public: public:
StringWriter(); StringWriter();
@ -21,6 +22,8 @@ class GwBoatItemBase{
size_t write(const uint8_t* s, size_t n); size_t write(const uint8_t* s, size_t n);
const char * c_str() const; const char * c_str() const;
int getSize() const; int getSize() const;
void setBase();
bool baseFilled();
void reset(); void reset();
}; };
static const unsigned long INVALID_TIME=60000; static const unsigned long INVALID_TIME=60000;

View File

@ -119,6 +119,6 @@ class TimeMonitor{
current[index]=now; current[index]=now;
int64_t currentv=now-sv; int64_t currentv=now-sv;
if ((now-start) > max) max=now-start; if ((now-start) > max) max=now-start;
times[index-1]->add(currentv); times[index]->add(currentv);
} }
}; };

View File

@ -1205,10 +1205,10 @@ function parseBoatDataLine(line){
let rt={}; let rt={};
let parts=line.split(','); let parts=line.split(',');
rt.name=parts[0]; rt.name=parts[0];
rt.valid=parts[1] === '1'; rt.valid=parts[2] === '1';
rt.update=parseInt(parts[2]); rt.update=parseInt(parts[3]);
rt.source=parseInt(parts[3]); rt.source=parseInt(parts[4]);
rt.format=parts[4]; rt.format=parts[1];
rt.value=parts[5]; rt.value=parts[5];
return rt; return rt;
} }