From c266bddea3001c526744bddccbe88915a032f7e2 Mon Sep 17 00:00:00 2001 From: andreas Date: Sun, 29 Sep 2024 19:56:39 +0200 Subject: [PATCH] make data store times configurable --- lib/boatData/GwBoatData.cpp | 63 ++++++++++++++-- lib/boatData/GwBoatData.h | 115 +++++++++++++++++------------- lib/xdrmappings/GwXDRMappings.cpp | 8 ++- lib/xdrmappings/GwXDRMappings.h | 10 ++- src/main.cpp | 2 +- web/config.json | 40 +++++++++++ 6 files changed, 176 insertions(+), 62 deletions(-) diff --git a/lib/boatData/GwBoatData.cpp b/lib/boatData/GwBoatData.cpp index df61ddfa..f7be6175 100644 --- a/lib/boatData/GwBoatData.cpp +++ b/lib/boatData/GwBoatData.cpp @@ -1,6 +1,7 @@ #include "GwBoatData.h" #include #include +#include "GWConfig.h" #define GWTYPE_DOUBLE 1 #define GWTYPE_UINT32 2 #define GWTYPE_UINT16 3 @@ -35,6 +36,23 @@ GwBoatItemBase::GwBoatItemBase(String name, String format, unsigned long invalid this->format = format; this->type = 0; this->lastUpdateSource = -1; + this->toType=TOType::user; +} +GwBoatItemBase::GwBoatItemBase(String name, String format, GwBoatItemBase::TOType toType) +{ + lastSet = 0; + this->invalidTime = INVALID_TIME; + this->toType=toType; + this->name = name; + this->format = format; + this->type = 0; + this->lastUpdateSource = -1; + this->toType=TOType::user; +} +void GwBoatItemBase::setInvalidTime(unsigned long it, bool force){ + if (toType != TOType::user || force ){ + invalidTime=it; + } } size_t GwBoatItemBase::getJsonSize() { return JSON_OBJECT_SIZE(10); } #define STRING_SIZE 40 @@ -113,6 +131,16 @@ GwBoatItem::GwBoatItem(String name, String formatInfo, unsigned long invalidT (*map)[name] = this; } } +template +GwBoatItem::GwBoatItem(String name, String formatInfo, GwBoatItemBase::TOType toType, GwBoatItemMap *map) : GwBoatItemBase(name, formatInfo, toType) +{ + T dummy; + this->type = GwBoatItemTypes::getType(dummy); + if (map) + { + (*map)[name] = this; + } +} template bool GwBoatItem::update(T nv, int source) @@ -246,14 +274,13 @@ void GwSatInfoList::houseKeeping(unsigned long ts) sats.end(), [ts, this](const GwSatInfo &info) { - return (info.timestamp + lifeTime) < ts; + return info.validTill < ts; }), sats.end()); } -void GwSatInfoList::update(GwSatInfo entry) +void GwSatInfoList::update(GwSatInfo entry, unsigned long validTill) { - unsigned long now = millis(); - entry.timestamp = now; + entry.validTill = validTill; for (auto it = sats.begin(); it != sats.end(); it++) { if (it->PRN == entry.PRN) @@ -267,7 +294,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, GwBoatItemBase::TOType toType, GwBoatItemMap *map) : GwBoatItem(name, formatInfo, toType, map) {} bool GwBoatDataSatList::update(GwSatInfo info, int source) { @@ -284,7 +311,7 @@ bool GwBoatDataSatList::update(GwSatInfo info, int source) } lastUpdateSource = source; uls(now); - data.update(info); + data.update(info,now+invalidTime); return true; } void GwBoatDataSatList::toJsonDoc(GwJsonDocument *doc, unsigned long minTime) @@ -293,9 +320,31 @@ void GwBoatDataSatList::toJsonDoc(GwJsonDocument *doc, unsigned long minTime) GwBoatItem::toJsonDoc(doc, minTime); } -GwBoatData::GwBoatData(GwLog *logger) +GwBoatData::GwBoatData(GwLog *logger, GwConfigHandler *cfg) { this->logger = logger; + for (auto &&it : values){ + unsigned long timeout=GwBoatItemBase::INVALID_TIME; + switch(it.second->getToType()){ + case GwBoatItemBase::TOType::ais: + timeout=cfg->getInt(GwConfigDefinitions::timoAis); + break; + case GwBoatItemBase::TOType::def: + timeout=cfg->getInt(GwConfigDefinitions::timoDefault); + break; + case GwBoatItemBase::TOType::lng: + timeout=cfg->getInt(GwConfigDefinitions::timoLong); + break; + case GwBoatItemBase::TOType::sensor: + timeout=cfg->getInt(GwConfigDefinitions::timoSensor); + break; + case GwBoatItemBase::TOType::keep: + timeout=0; + break; + } + it.second->setInvalidTime(timeout); + } + } GwBoatData::~GwBoatData() { diff --git a/lib/boatData/GwBoatData.h b/lib/boatData/GwBoatData.h index f5af8e89..1c4394c2 100644 --- a/lib/boatData/GwBoatData.h +++ b/lib/boatData/GwBoatData.h @@ -2,6 +2,7 @@ #define _GWBOATDATA_H #include "GwLog.h" +#include "GWConfig.h" #include #include #include @@ -15,6 +16,14 @@ class GwJsonDocument; class GwBoatItemBase{ public: + using TOType=enum{ + def=1, + ais=2, + sensor=3, + lng=4, + user=5, + keep=6 + }; class StringWriter{ uint8_t *buffer =NULL; uint8_t *wp=NULL; @@ -31,7 +40,7 @@ class GwBoatItemBase{ bool baseFilled(); void reset(); }; - static const unsigned long INVALID_TIME=60000; + static const long INVALID_TIME=60000; //the formatter names that must be known in js GWSC(formatCourse); GWSC(formatKnots); @@ -51,10 +60,11 @@ class GwBoatItemBase{ protected: int type; unsigned long lastSet=0; - unsigned long invalidTime=INVALID_TIME; + long invalidTime=INVALID_TIME; String name; String format; StringWriter writer; + TOType toType=TOType::def; void uls(unsigned long ts=0){ if (ts) lastSet=ts; else lastSet=millis(); @@ -65,7 +75,8 @@ class GwBoatItemBase{ int getCurrentType(){return type;} unsigned long getLastSet() const {return lastSet;} bool isValid(unsigned long now=0) const ; - GwBoatItemBase(String name,String format,unsigned long invalidTime=INVALID_TIME); + GwBoatItemBase(String name,String format,TOType toType); + GwBoatItemBase(String name,String format,unsigned long invalidTime); virtual ~GwBoatItemBase(){} void invalidate(){ lastSet=0; @@ -82,6 +93,8 @@ class GwBoatItemBase{ virtual double getDoubleValue()=0; String getName(){return name;} const String & getFormat() const{return format;} + virtual void setInvalidTime(unsigned long it, bool force=true); + TOType getToType(){return toType;} }; class GwBoatData; template class GwBoatItem : public GwBoatItemBase{ @@ -90,6 +103,7 @@ template class GwBoatItem : public GwBoatItemBase{ bool lastStringValid=false; public: GwBoatItem(String name,String formatInfo,unsigned long invalidTime=INVALID_TIME,GwBoatItemMap *map=NULL); + GwBoatItem(String name,String formatInfo,TOType toType,GwBoatItemMap *map=NULL); virtual ~GwBoatItem(){} bool update(T nv, int source=-1); bool updateMax(T nv,int sourceId=-1); @@ -118,14 +132,14 @@ class GwSatInfo{ uint32_t Elevation; uint32_t Azimut; uint32_t SNR; - unsigned long timestamp; + unsigned long validTill; }; class GwSatInfoList{ public: - static const unsigned long lifeTime=32000; + static const GwBoatItemBase::TOType toType=GwBoatItemBase::TOType::lng; std::vector sats; void houseKeeping(unsigned long ts=0); - void update(GwSatInfo entry); + void update(GwSatInfo entry, unsigned long validTill); int getNumSats() const{ return sats.size(); } @@ -139,7 +153,7 @@ class GwSatInfoList{ class GwBoatDataSatList : public GwBoatItem { public: - GwBoatDataSatList(String name, String formatInfo, unsigned long invalidTime = INVALID_TIME, GwBoatItemMap *map = NULL); + GwBoatDataSatList(String name, String formatInfo, GwBoatItemBase::TOType toType, GwBoatItemMap *map = NULL); bool update(GwSatInfo info, int source); virtual void toJsonDoc(GwJsonDocument *doc, unsigned long minTime); GwSatInfo *getAt(int idx){ @@ -164,56 +178,59 @@ class GwBoatItemNameProvider virtual unsigned long getInvalidTime(){ return GwBoatItemBase::INVALID_TIME;} virtual ~GwBoatItemNameProvider() {} }; -#define GWBOATDATA(type,name,time,fmt) \ +#define GWBOATDATAT(type,name,toType,fmt) \ static constexpr const char* _##name=#name; \ - GwBoatItem *name=new GwBoatItem(#name,GwBoatItemBase::fmt,time,&values) ; -#define GWSPECBOATDATA(clazz,name,time,fmt) \ - clazz *name=new clazz(#name,GwBoatItemBase::fmt,time,&values) ; + GwBoatItem *name=new GwBoatItem(#name,GwBoatItemBase::fmt,toType,&values) ; +#define GWBOATDATA(type,name,fmt) GWBOATDATAT(type,name,GwBoatItemBase::TOType::def,fmt) +#define GWSPECBOATDATA(clazz,name,toType,fmt) \ + clazz *name=new clazz(#name,GwBoatItemBase::fmt,toType,&values) ; class GwBoatData{ + static const unsigned long DEF_TIME=4000; private: GwLog *logger; GwBoatItemBase::GwBoatItemMap values; public: - GWBOATDATA(double,COG,4000,formatCourse) // course over ground - GWBOATDATA(double,SOG,4000,formatKnots) // speed over ground - GWBOATDATA(double,HDT,4000,formatCourse) // true heading - GWBOATDATA(double,HDM,4000,formatCourse) // magnetic heading - GWBOATDATA(double,STW,4000,formatKnots) // water speed - GWBOATDATA(double,VAR,4000,formatWind) // variation - GWBOATDATA(double,DEV,4000,formatWind) // deviation - GWBOATDATA(double,AWA,4000,formatWind) // apparent wind ANGLE - GWBOATDATA(double,AWS,4000,formatKnots) // apparent wind speed - GWBOATDATA(double,MaxAws,0,formatKnots) - GWBOATDATA(double,TWD,4000,formatCourse) // true wind DIRECTION - GWBOATDATA(double,TWA,4000,formatWind) // true wind ANGLE - GWBOATDATA(double,TWS,4000,formatKnots) // true wind speed - GWBOATDATA(double,MaxTws,0,formatKnots) - GWBOATDATA(double,ROT,4000,formatRot) // rate of turn - GWBOATDATA(double,RPOS,4000,formatWind) // rudder position - GWBOATDATA(double,PRPOS,4000,formatWind) // secondary rudder position - GWBOATDATA(double,LAT,4000,formatLatitude) - GWBOATDATA(double,LON,4000,formatLongitude) - GWBOATDATA(double,ALT,4000,formatFixed0) //altitude - GWBOATDATA(double,HDOP,4000,formatDop) - GWBOATDATA(double,PDOP,4000,formatDop) - GWBOATDATA(double,VDOP,4000,formatDop) - GWBOATDATA(double,DBS,4000,formatDepth) //waterDepth (below surface) - GWBOATDATA(double,DBT,4000,formatDepth) //DepthTransducer - GWBOATDATA(double,GPST,4000,formatTime) // GPS time (seconds of day) - GWBOATDATA(uint32_t,GPSD,4000,formatDate) // GPS date (days since 1979-01-01) - GWBOATDATA(int16_t,TZ,8000,formatFixed0) - GWBOATDATA(double,WTemp,4000,kelvinToC) - GWBOATDATA(uint32_t,Log,16000,mtr2nm) - GWBOATDATA(uint32_t,TripLog,16000,mtr2nm) - GWBOATDATA(double,DTW,4000,mtr2nm) // distance to waypoint - GWBOATDATA(double,BTW,4000,formatCourse) // bearing to waypoint - GWBOATDATA(double,XTE,4000,formatXte) // cross track error - GWBOATDATA(double,WPLat,4000,formatLatitude) // waypoint latitude - GWBOATDATA(double,WPLon,4000,formatLongitude) // waypoint longitude - GWSPECBOATDATA(GwBoatDataSatList,SatInfo,GwSatInfoList::lifeTime,formatFixed0); + GWBOATDATA(double,COG,formatCourse) // course over ground + GWBOATDATA(double,SOG,formatKnots) // speed over ground + GWBOATDATA(double,HDT,formatCourse) // true heading + GWBOATDATA(double,HDM,formatCourse) // magnetic heading + GWBOATDATA(double,STW,formatKnots) // water speed + GWBOATDATA(double,VAR,formatWind) // variation + GWBOATDATA(double,DEV,formatWind) // deviation + GWBOATDATA(double,AWA,formatWind) // apparent wind ANGLE + GWBOATDATA(double,AWS,formatKnots) // apparent wind speed + GWBOATDATAT(double,MaxAws,GwBoatItemBase::TOType::keep,formatKnots) + GWBOATDATA(double,TWD,formatCourse) // true wind DIRECTION + GWBOATDATA(double,TWA,formatWind) // true wind ANGLE + GWBOATDATA(double,TWS,formatKnots) // true wind speed + + GWBOATDATAT(double,MaxTws,GwBoatItemBase::TOType::keep,formatKnots) + GWBOATDATA(double,ROT,formatRot) // rate of turn + GWBOATDATA(double,RPOS,formatWind) // rudder position + GWBOATDATA(double,PRPOS,formatWind) // secondary rudder position + GWBOATDATA(double,LAT,formatLatitude) + GWBOATDATA(double,LON,formatLongitude) + GWBOATDATA(double,ALT,formatFixed0) //altitude + GWBOATDATA(double,HDOP,formatDop) + GWBOATDATA(double,PDOP,formatDop) + GWBOATDATA(double,VDOP,formatDop) + GWBOATDATA(double,DBS,formatDepth) //waterDepth (below surface) + GWBOATDATA(double,DBT,formatDepth) //DepthTransducer + GWBOATDATA(double,GPST,formatTime) // GPS time (seconds of day) + GWBOATDATA(uint32_t,GPSD,formatDate) // GPS date (days since 1979-01-01) + GWBOATDATAT(int16_t,TZ,GwBoatItemBase::TOType::lng,formatFixed0) + GWBOATDATA(double,WTemp,kelvinToC) + GWBOATDATAT(uint32_t,Log,GwBoatItemBase::TOType::lng,mtr2nm) + GWBOATDATAT(uint32_t,TripLog,GwBoatItemBase::TOType::lng,mtr2nm) + GWBOATDATA(double,DTW,mtr2nm) // distance to waypoint + GWBOATDATA(double,BTW,formatCourse) // bearing to waypoint + GWBOATDATA(double,XTE,formatXte) // cross track error + GWBOATDATA(double,WPLat,formatLatitude) // waypoint latitude + GWBOATDATA(double,WPLon,formatLongitude) // waypoint longitude + GWSPECBOATDATA(GwBoatDataSatList,SatInfo,GwSatInfoList::toType,formatFixed0); public: - GwBoatData(GwLog *logger); + GwBoatData(GwLog *logger, GwConfigHandler *cfg); ~GwBoatData(); template GwBoatItem *getOrCreate(T initial,GwBoatItemNameProvider *provider); template bool update(T value,int source,GwBoatItemNameProvider *provider); diff --git a/lib/xdrmappings/GwXDRMappings.cpp b/lib/xdrmappings/GwXDRMappings.cpp index b2eb0c2f..ad26bc89 100644 --- a/lib/xdrmappings/GwXDRMappings.cpp +++ b/lib/xdrmappings/GwXDRMappings.cpp @@ -355,6 +355,7 @@ void GwXDRMappings::begin() GwXDRFoundMapping GwXDRMappings::selectMapping(GwXDRMapping::MappingList *list, int instance, const char *key) { GwXDRMapping *candidate = NULL; + unsigned long invalidTime=config->getInt(GwConfigDefinitions::timoSensor); for (auto mit = list->begin(); mit != list->end(); mit++) { GwXDRMappingDef *def = (*mit)->definition; @@ -369,7 +370,7 @@ GwXDRFoundMapping GwXDRMappings::selectMapping(GwXDRMapping::MappingList *list, { LOG_DEBUG(GwLog::DEBUG + 1, "selected mapping %s for %s, i=%d", def->toString().c_str(), key, instance); - return GwXDRFoundMapping(*mit, instance); + return GwXDRFoundMapping(*mit,invalidTime, instance); } if (instance < 0) { @@ -393,7 +394,7 @@ GwXDRFoundMapping GwXDRMappings::selectMapping(GwXDRMapping::MappingList *list, { LOG_DEBUG(GwLog::DEBUG + 1, "selected mapping %s for %s, i=%d", candidate->definition->toString().c_str(), key, instance); - return GwXDRFoundMapping(candidate, instance>=0?instance:candidate->definition->instanceId); + return GwXDRFoundMapping(candidate, invalidTime,instance>=0?instance:candidate->definition->instanceId); } LOG_DEBUG(GwLog::DEBUG + 1, "no instance mapping found for key=%s, i=%d", key, instance); return GwXDRFoundMapping(); @@ -472,8 +473,9 @@ String GwXDRMappings::getXdrEntry(String mapping, double value,int instance){ } GwXDRType *type = findType(code, &typeIndex); bool first=true; + unsigned long invalidTime=config->getInt(GwConfigDefinitions::timoSensor); while (type){ - GwXDRFoundMapping found(def,type); + GwXDRFoundMapping found(def,type,invalidTime); found.instanceId=instance; if (first) first=false; else rt+=","; diff --git a/lib/xdrmappings/GwXDRMappings.h b/lib/xdrmappings/GwXDRMappings.h index 246ade51..7643bee6 100644 --- a/lib/xdrmappings/GwXDRMappings.h +++ b/lib/xdrmappings/GwXDRMappings.h @@ -167,15 +167,18 @@ class GwXDRFoundMapping : public GwBoatItemNameProvider{ GwXDRType *type=NULL; int instanceId=-1; bool empty=true; - GwXDRFoundMapping(GwXDRMappingDef *definition,GwXDRType *type){ + unsigned long timeout=0; + GwXDRFoundMapping(GwXDRMappingDef *definition,GwXDRType *type, unsigned long timeout){ this->definition=definition; this->type=type; + this->timeout=timeout; empty=false; } - GwXDRFoundMapping(GwXDRMapping* mapping,int instance=0){ + GwXDRFoundMapping(GwXDRMapping* mapping,unsigned long timeout,int instance){ this->definition=mapping->definition; this->type=mapping->type; this->instanceId=instance; + this->timeout=timeout; empty=false; } GwXDRFoundMapping(){} @@ -195,6 +198,9 @@ class GwXDRFoundMapping : public GwBoatItemNameProvider{ return "formatXdr:"+type->xdrtype+":"+type->boatDataUnit; }; virtual ~GwXDRFoundMapping(){} + virtual unsigned long getInvalidTime() override{ + return timeout; + } }; //the class GwXDRMappings is not intended to be deleted diff --git a/src/main.cpp b/src/main.cpp index 599b3409..17d2fa1d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -138,7 +138,7 @@ bool fixedApPass=true; #endif GwWifi gwWifi(&config,&logger,fixedApPass); GwChannelList channels(&logger,&config); -GwBoatData boatData(&logger); +GwBoatData boatData(&logger,&config); GwXDRMappings xdrMappings(&logger,&config); bool sendOutN2k=true; diff --git a/web/config.json b/web/config.json index ebc5a272..7dad6ca2 100644 --- a/web/config.json +++ b/web/config.json @@ -250,6 +250,46 @@ "description": "the n2k instance to be used as port rudder 0...253, -1 to disable", "category": "converter" }, + { + "name": "timeouts", + "type": "array", + "replace":[ + { + "n":"Default", + "d":"4000", + "l": "default", + "t": "NMEA" + }, + { + "n":"Sensor", + "d":"60000", + "l": "sensor", + "t": "sensor" + }, + { + "n":"Long", + "d":"32000", + "l": "long", + "t": "special NMEA" + }, + { + "n":"Ais", + "d":"120000", + "l": "ais", + "t": "ais" + } + ], + "children":[ + { + "name":"timo$n", + "label":"timeout $l", + "default": "$d", + "type": "number", + "description": "data timeouts(ms) for $t data", + "category": "converter" + } + ] + }, { "name": "usbActisense", "label": "USB mode",