diff --git a/lib/config/GwConverterConfig.h b/lib/config/GwConverterConfig.h index d0dbc6a8..4a93a71b 100644 --- a/lib/config/GwConverterConfig.h +++ b/lib/config/GwConverterConfig.h @@ -71,9 +71,12 @@ class GwConverterConfig{ int rmcInterval=1000; int rmcCheckTime=4000; int winst312=256; + bool unmappedXdr=false; + unsigned long xdrTimeout=60000; std::vector windMappings; void init(GwConfigHandler *config, GwLog*logger){ minXdrInterval=config->getInt(GwConfigDefinitions::minXdrInterval,100); + xdrTimeout=config->getInt(GwConfigDefinitions::timoSensor); starboardRudderInstance=config->getInt(GwConfigDefinitions::stbRudderI,0); portRudderInstance=config->getInt(GwConfigDefinitions::portRudderI,-1); min2KInterval=config->getInt(GwConfigDefinitions::min2KInterval,50); @@ -83,6 +86,7 @@ class GwConverterConfig{ rmcInterval=config->getInt(GwConfigDefinitions::sendRMCi,1000); if (rmcInterval < 0) rmcInterval=0; if (rmcInterval > 0 && rmcInterval <100) rmcInterval=100; + unmappedXdr=config->getBool(GwConfigDefinitions::unknownXdr); winst312=config->getInt(GwConfigDefinitions::winst312,256); for (auto && it:windConfigs){ String cfg=config->getString(it.second); diff --git a/lib/gwwifi/GwWifi.cpp b/lib/gwwifi/GwWifi.cpp index 69715d24..6cd7f722 100644 --- a/lib/gwwifi/GwWifi.cpp +++ b/lib/gwwifi/GwWifi.cpp @@ -108,7 +108,7 @@ void GwWifi::loop(){ } else{ if (! clientIsConnected){ - LOG_DEBUG(GwLog::LOG,"wifiClient %s now connected to",wifiSSID->asCString()); + LOG_DEBUG(GwLog::LOG,"wifiClient now connected to %s at %s",wifiSSID->asCString(),WiFi.localIP().toString().c_str()); clientIsConnected=true; } } diff --git a/lib/nmea0183ton2k/NMEA0183DataToN2K.cpp b/lib/nmea0183ton2k/NMEA0183DataToN2K.cpp index bd593d5f..cf335dfc 100644 --- a/lib/nmea0183ton2k/NMEA0183DataToN2K.cpp +++ b/lib/nmea0183ton2k/NMEA0183DataToN2K.cpp @@ -189,6 +189,7 @@ class NMEA0183DataToN2KFunctions : public NMEA0183DataToN2K if (N2kIsNA(v)) return N2kInt8NA; return v; } + void convertXDR(const SNMEA0183Msg &msg){ XdrMappingList foundMappings; for (int offset=0;offset <= (msg.FieldCount()-4);offset+=4){ @@ -199,7 +200,19 @@ class NMEA0183DataToN2KFunctions : public NMEA0183DataToN2K String unit=msg.Field(offset+2); String transducerName=msg.Field(offset+3); GwXDRFoundMapping found=xdrMappings->getMapping(transducerName,type,unit); - if (found.empty) continue; + if (found.empty) { + if (config.unmappedXdr){ + const GwXDRType *typeDef=xdrMappings->findType(type,unit); + GwXdrUnknownMapping mapping(transducerName,unit,typeDef,config.xdrTimeout); + value=mapping.valueFromXdr(value); + if (boatData->update(value,msg.sourceId,&mapping)){ + //TODO: potentially update the format + LOG_DEBUG(GwLog::DEBUG+1,"found unmapped XDR %s:%s, value %f", + transducerName.c_str(),mapping.getBoatItemFormat().c_str(),value); + } + } + continue; + } value=found.valueFromXdr(value); if (!boatData->update(value,msg.sourceId,&found)) continue; LOG_DEBUG(GwLog::DEBUG+1,"found mapped XDR %s:%s, value %f", @@ -307,7 +320,7 @@ class NMEA0183DataToN2KFunctions : public NMEA0183DataToN2K return; } tN2kMsg n2kMsg; - if (boatData->XTE->update(rmb.xte,msg.sourceId)){ + if (updateDouble(boatData->XTE,rmb.xte,msg.sourceId)){ tN2kXTEMode mode=N2kxtem_Autonomous; if (msg.FieldCount() > 13){ const char *modeChar=msg.Field(13); @@ -318,10 +331,10 @@ class NMEA0183DataToN2KFunctions : public NMEA0183DataToN2K } uint8_t destinationId=getWaypointId(rmb.destID); uint8_t sourceId=getWaypointId(rmb.originID); - if (boatData->DTW->update(rmb.dtw,msg.sourceId) - && boatData->BTW->update(rmb.btw,msg.sourceId) - && boatData->WPLat->update(rmb.latitude,msg.sourceId) - && boatData->WPLon->update(rmb.longitude,msg.sourceId) + if (updateDouble(boatData->DTW,rmb.dtw,msg.sourceId) + && updateDouble(boatData->BTW,rmb.btw,msg.sourceId) + && updateDouble(boatData->WPLat,rmb.latitude,msg.sourceId) + && updateDouble(boatData->WPLon,rmb.longitude,msg.sourceId) ){ SetN2kNavigationInfo(n2kMsg,1,rmb.dtw,N2khr_true, false, diff --git a/lib/usercode/GwUserCode.cpp b/lib/usercode/GwUserCode.cpp index 1b007f8e..86f2f134 100644 --- a/lib/usercode/GwUserCode.cpp +++ b/lib/usercode/GwUserCode.cpp @@ -90,6 +90,7 @@ class TaskInterfacesStorage{ return true; } GwApi::TaskInterfaces::Ptr get(const String &name, int &result){ + GWSYNCHRONIZED(lock); GWSYNCHRONIZED(lock); auto it = values.find(name); if (it == values.end()) @@ -161,6 +162,7 @@ class TaskApi : public GwApiInternal GwApiInternal *api=nullptr; int sourceId; SemaphoreHandle_t mainLock; + SemaphoreHandle_t mainLock; SemaphoreHandle_t localLock; std::map> counter; std::map webHandlers; @@ -243,6 +245,7 @@ class TaskApi : public GwApiInternal } }; virtual int getJsonSize(){ + GWSYNCHRONIZED(localLock); GWSYNCHRONIZED(localLock); if (! counterUsed) return 0; int rt=0; @@ -252,6 +255,7 @@ class TaskApi : public GwApiInternal return rt; }; virtual void increment(int idx,const String &name,bool failed=false){ + GWSYNCHRONIZED(localLock); GWSYNCHRONIZED(localLock); counterUsed=true; auto it=counter.find(idx); diff --git a/lib/xdrmappings/GwXDRMappings.cpp b/lib/xdrmappings/GwXDRMappings.cpp index ad26bc89..28f88c2b 100644 --- a/lib/xdrmappings/GwXDRMappings.cpp +++ b/lib/xdrmappings/GwXDRMappings.cpp @@ -58,6 +58,7 @@ GwXDRType *types[] = { new GwXDRType(GwXDRType::DISPLACEMENTD, "A", "D",DegToRad,RadToDeg,"rd"), new GwXDRType(GwXDRType::RPM,"T","R") }; +static GwXDRType genericType(GwXDRType::GENERIC, "G", ""); template int GetArrLength(T(&)[size]){return size;} static GwXDRType *findType(GwXDRType::TypeCode type, int *start = NULL) @@ -82,6 +83,19 @@ static GwXDRType *findType(GwXDRType::TypeCode type, int *start = NULL) return NULL; } +static GwXDRType *findType(const String &typeString, const String &unitString) +{ + int len=GetArrLength(types); + for (int i=0; i< len; i++) + { + if (types[i]->xdrtype == typeString && types[i]->xdrunit == unitString) + { + return types[i]; + } + } + return &genericType; +} + #include "GwXdrTypeMappings.h" static GwXDRType::TypeCode findTypeMapping(GwXDRCategory category, int field) @@ -199,7 +213,7 @@ GwXDRMappingDef *GwXDRMappingDef::fromString(String s) } return rt; } -String GwXDRMappingDef::getTransducerName(int instance) +String GwXDRMappingDef::getTransducerName(int instance) const { String name = xdrName; if (instanceMode == GwXDRMappingDef::IS_AUTO) @@ -257,7 +271,7 @@ bool GwXDRMappings::addMapping(GwXDRMappingDef *def) LOG_DEBUG(GwLog::ERROR, "no type mapping for %s", def->toString().c_str()); return false; } - GwXDRType *type = findType(code, &typeIndex); + GwXDRType *type = ::findType(code, &typeIndex); if (!type) { LOG_DEBUG(GwLog::ERROR, "no type definition for %s", def->toString().c_str()); @@ -298,7 +312,7 @@ bool GwXDRMappings::addMapping(GwXDRMappingDef *def) LOG_DEBUG(GwLog::LOG, "append mapping with n183key %s", n183key.c_str()); it->second.push_back(mapping); } - type = findType(code, &typeIndex); + type = ::findType(code, &typeIndex); if (!type) break; mapping = new GwXDRMapping(def, type); @@ -471,7 +485,7 @@ String GwXDRMappings::getXdrEntry(String mapping, double value,int instance){ { return rt; } - GwXDRType *type = findType(code, &typeIndex); + GwXDRType *type = ::findType(code, &typeIndex); bool first=true; unsigned long invalidTime=config->getInt(GwConfigDefinitions::timoSensor); while (type){ @@ -480,8 +494,12 @@ String GwXDRMappings::getXdrEntry(String mapping, double value,int instance){ if (first) first=false; else rt+=","; rt+=found.buildXdrEntry(value).entry; - type = findType(code, &typeIndex); + type = ::findType(code, &typeIndex); } delete def; return rt; } + +const GwXDRType * GwXDRMappings::findType(const String &typeString, const String &unitString) const{ + return ::findType(typeString,unitString); +} \ No newline at end of file diff --git a/lib/xdrmappings/GwXDRMappings.h b/lib/xdrmappings/GwXDRMappings.h index 7643bee6..198a7291 100644 --- a/lib/xdrmappings/GwXDRMappings.h +++ b/lib/xdrmappings/GwXDRMappings.h @@ -140,7 +140,7 @@ class GwXDRMappingDef{ rt += xdrUnit; return rt; } - String getTransducerName(int instance); + String getTransducerName(int instance) const; private: static bool handleToken(String tok,int index,GwXDRMappingDef *def); }; @@ -163,12 +163,12 @@ class GwXDRFoundMapping : public GwBoatItemNameProvider{ String entry; String transducer; }; - GwXDRMappingDef *definition=NULL; - GwXDRType *type=NULL; + const GwXDRMappingDef *definition=NULL; + const GwXDRType *type=NULL; int instanceId=-1; bool empty=true; unsigned long timeout=0; - GwXDRFoundMapping(GwXDRMappingDef *definition,GwXDRType *type, unsigned long timeout){ + GwXDRFoundMapping(const GwXDRMappingDef *definition,const GwXDRType *type, unsigned long timeout){ this->definition=definition; this->type=type; this->timeout=timeout; @@ -182,7 +182,7 @@ class GwXDRFoundMapping : public GwBoatItemNameProvider{ empty=false; } GwXDRFoundMapping(){} - String getTransducerName(){ + virtual String getTransducerName(){ return definition->getTransducerName(instanceId); } double valueFromXdr(double value){ @@ -203,6 +203,24 @@ class GwXDRFoundMapping : public GwBoatItemNameProvider{ } }; +class GwXdrUnknownMapping : public GwXDRFoundMapping{ + String name; + String unit; + public: + GwXdrUnknownMapping(const String &xdrName, const String &xdrUnit,const GwXDRType *type,unsigned long timeout): + name(xdrName),unit(xdrUnit), GwXDRFoundMapping(nullptr,type,timeout){ + + } + virtual String getTransducerName(){ + return name; + } + virtual String getBoatItemFormat(){ + String rt=GwXDRFoundMapping::getBoatItemFormat(); + if (type->xdrunit.isEmpty()) rt+=unit; + return rt; + } +}; + //the class GwXDRMappings is not intended to be deleted //the deletion will leave memory leaks! class GwConfigHandler; @@ -229,6 +247,7 @@ class GwXDRMappings{ GwXDRFoundMapping getMapping(GwXDRCategory category,int selector,int field=0,int instance=-1); String getXdrEntry(String mapping, double value,int instance=0); const char * getUnMapped(); + const GwXDRType * findType(const String &typeString, const String &unitString) const; }; diff --git a/web/config.json b/web/config.json index 0b75d272..26d3166d 100644 --- a/web/config.json +++ b/web/config.json @@ -210,6 +210,14 @@ "description":"send out the converted data on the NMEA2000 bus\nIf set to off the converted data will still be shown at the data tab.", "category":"converter" }, + { + "name":"unknownXdr", + "label":"show unknown XDR", + "type":"boolean", + "default":"false", + "description":"show received XDR transducer values in data display if there is no XDR mapping for them", + "category":"converter" + }, { "name":"sendRMCi", "label":"send RMC interval", diff --git a/web/index.js b/web/index.js index 538a51a2..bbc96e3b 100644 --- a/web/index.js +++ b/web/index.js @@ -1578,7 +1578,7 @@ if (isNaN(x)) return '-----'; return formatLonLatsDecimal(x, 'lat'); }, - u: '°' + u: '' }, formatLongitude: { f: function (v) { @@ -1798,7 +1798,7 @@ let id = el.getAttribute('id'); if (id) { if (!names[id.replace(/^frame_/, '')]) { - el.parentElement.remove(); + el.remove(); } } });