From 15ca1b9e17772eee91e02245708e23506271a1bc Mon Sep 17 00:00:00 2001 From: wellenvogel Date: Sat, 20 Nov 2021 17:53:02 +0100 Subject: [PATCH] xdrmappings: map 130314 --- extra_script.py | 4 +- lib/log/GWLog.cpp | 6 ++- lib/nmea2kto0183/N2kDataToNMEA0183.cpp | 69 ++++++++++++++++++++++++-- lib/nmea2kto0183/N2kDataToNMEA0183.h | 7 ++- lib/xdrmappings/GwXDRMappings.cpp | 44 +++++++++++++--- lib/xdrmappings/GwXDRMappings.h | 19 ++++--- src/main.cpp | 11 ++-- web/config.json | 16 ++++++ 8 files changed, 151 insertions(+), 25 deletions(-) diff --git a/extra_script.py b/extra_script.py index 5c1bca7..d490eb2 100644 --- a/extra_script.py +++ b/extra_script.py @@ -118,7 +118,7 @@ def generateXdrMappings(): first=False else: oh.write(",\n") - oh.write(" new GwXDRTypeMapping(%d,%d,0)"%(cid,tc)) + oh.write(" new GwXDRTypeMapping(%d,%d,0) /*%s*/"%(cid,tc,cat)) fields=item.get('fields') if fields is None: continue @@ -138,7 +138,7 @@ def generateXdrMappings(): first=False else: oh.write(",\n") - oh.write(" new GwXDRTypeMapping(%d,%d,%d) /*%s*/"%(cid,tc,id,l)) + oh.write(" new GwXDRTypeMapping(%d,%d,%d) /*%s:%s*/"%(cid,tc,cat,id,l)) oh.write("\n") oh.write("};\n") except Exception as e: diff --git a/lib/log/GWLog.cpp b/lib/log/GWLog.cpp index 0a62eb3..e6e6501 100644 --- a/lib/log/GWLog.cpp +++ b/lib/log/GWLog.cpp @@ -22,7 +22,11 @@ void GwLog::logString(const char *fmt,...){ va_start(args,fmt); xSemaphoreTake(locker, portMAX_DELAY); vsnprintf(buffer,99,fmt,args); - if (! writer) return; + buffer[99]=0; + if (! writer) { + xSemaphoreGive(locker); + return; + } writer->write(prefix.c_str()); writer->write(buffer); writer->write("\n"); diff --git a/lib/nmea2kto0183/N2kDataToNMEA0183.cpp b/lib/nmea2kto0183/N2kDataToNMEA0183.cpp index 0244b86..627a4a1 100644 --- a/lib/nmea2kto0183/N2kDataToNMEA0183.cpp +++ b/lib/nmea2kto0183/N2kDataToNMEA0183.cpp @@ -64,8 +64,52 @@ class N2kToNMEA0183Functions : public N2kDataToNMEA0183 { private: + GwXDRMappings *xdrMappings; ConverterList converters; static const unsigned long RMCPeriod = 500; + tNMEA0183Msg xdrMessage; + bool xdrOpened=false; + + String buildXdrEntry(GwXDRFoundMapping &mapping,double value){ + char buffer[40]; + String name=mapping.definition->xdrName; + if (mapping.definition->instanceMode == GwXDRMappingDef::IS_AUTO || + mapping.definition->instanceMode == GwXDRMappingDef::IS_SINGLE + ){ + name+="#"; + name+=String(mapping.instanceId); + } + if (mapping.type->tonmea){ + value=(* (mapping.type->tonmea))(value); + } + snprintf(buffer,39,"%s,%.3f,%s,%s", + mapping.type->xdrtype.c_str(), + value, + mapping.type->xdrunit.c_str(), + name); + buffer[39]=0; + return String(buffer); + } + bool addToXdr(String entry){ + if (! xdrOpened){ + xdrMessage.Init("XDR",talkerId); + xdrOpened=true; + } + int len=entry.length(); + if (! xdrMessage.AddStrField(entry.c_str())){ + SendMessage(xdrMessage); + xdrMessage.Init("XDR",talkerId); + xdrMessage.AddStrField(entry.c_str()); + } + return true; + } + bool finalizeXdr(){ + if (! xdrOpened) return false; + SendMessage(xdrMessage); + xdrOpened=false; + return true; + } + void setMax(GwBoatItem *maxItem, GwBoatItem *item) { unsigned long now = millis(); @@ -1152,6 +1196,23 @@ private: SendMessage(nmeaMsg); } + void Handle130314(const tN2kMsg &msg){ + unsigned char SID=-1; + unsigned char PressureInstance=0; + tN2kPressureSource PressureSource; + double ActualPressure; + if (! ParseN2kPGN130314(msg,SID, PressureInstance, + PressureSource, ActualPressure)){ + LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN); + return; + } + GwXDRFoundMapping mapping=xdrMappings->getMapping(XDRPRESSURE,(int)PressureSource,0,PressureInstance); + if (mapping.empty) return; + LOG_DEBUG(GwLog::DEBUG,"found pressure mapping %s",mapping.definition->toString().c_str()); + addToXdr(buildXdrEntry(mapping,ActualPressure)); + finalizeXdr(); + } + void registerConverters() { @@ -1178,6 +1239,7 @@ private: converters.registerConverter(127251UL, &N2kToNMEA0183Functions::HandleROT); converters.registerConverter(129283UL, &N2kToNMEA0183Functions::HandleXTE); converters.registerConverter(129284UL, &N2kToNMEA0183Functions::HandleNavigation); + converters.registerConverter(130314UL, &N2kToNMEA0183Functions::Handle130314); #define HANDLE_AIS #ifdef HANDLE_AIS converters.registerConverter(129038UL, &N2kToNMEA0183Functions::HandleAISClassAPosReport); // AIS Class A Position Report, Message Type 1 @@ -1191,7 +1253,7 @@ private: public: N2kToNMEA0183Functions(GwLog *logger, GwBoatData *boatData, tNMEA2000 *NMEA2000, tSendNMEA0183MessageCallback callback, int sourceId, - String talkerId) + String talkerId, GwXDRMappings *xdrMappings) : N2kDataToNMEA0183(logger, boatData, NMEA2000, callback,sourceId,talkerId) { LastPosSend = 0; @@ -1200,6 +1262,7 @@ private: this->logger = logger; this->boatData = boatData; + this->xdrMappings=xdrMappings; registerConverters(); } virtual void loop() @@ -1215,8 +1278,8 @@ private: N2kDataToNMEA0183* N2kDataToNMEA0183::create(GwLog *logger, GwBoatData *boatData, tNMEA2000 *NMEA2000, - tSendNMEA0183MessageCallback callback, int sourceId,String talkerId){ + tSendNMEA0183MessageCallback callback, int sourceId,String talkerId, GwXDRMappings *xdrMappings){ LOG_DEBUG(GwLog::LOG,"creating N2kToNMEA0183"); - return new N2kToNMEA0183Functions(logger,boatData,NMEA2000,callback, sourceId,talkerId); + return new N2kToNMEA0183Functions(logger,boatData,NMEA2000,callback, sourceId,talkerId,xdrMappings); } //***************************************************************************** diff --git a/lib/nmea2kto0183/N2kDataToNMEA0183.h b/lib/nmea2kto0183/N2kDataToNMEA0183.h index 4ece985..a1f3ba0 100644 --- a/lib/nmea2kto0183/N2kDataToNMEA0183.h +++ b/lib/nmea2kto0183/N2kDataToNMEA0183.h @@ -28,6 +28,7 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include +#include //------------------------------------------------------------------------------ class N2kDataToNMEA0183 : public tNMEA2000::tMsgHandler @@ -42,10 +43,12 @@ protected: char talkerId[3]; tSendNMEA0183MessageCallback SendNMEA0183MessageCallback; void SendMessage(const tNMEA0183Msg &NMEA0183Msg); - N2kDataToNMEA0183(GwLog *logger, GwBoatData *boatData, tNMEA2000 *NMEA2000, tSendNMEA0183MessageCallback callback, int sourceId,String talkerId); + N2kDataToNMEA0183(GwLog *logger, GwBoatData *boatData, tNMEA2000 *NMEA2000, + tSendNMEA0183MessageCallback callback, int sourceId,String talkerId); public: - static N2kDataToNMEA0183* create(GwLog *logger, GwBoatData *boatData, tNMEA2000 *NMEA2000, tSendNMEA0183MessageCallback callback, int sourceId,String talkerId); + static N2kDataToNMEA0183* create(GwLog *logger, GwBoatData *boatData, tNMEA2000 *NMEA2000, tSendNMEA0183MessageCallback callback, + int sourceId,String talkerId, GwXDRMappings *xdrMappings); virtual void HandleMsg(const tN2kMsg &N2kMsg) = 0; virtual void loop(); virtual ~N2kDataToNMEA0183(){} diff --git a/lib/xdrmappings/GwXDRMappings.cpp b/lib/xdrmappings/GwXDRMappings.cpp index 725ca53..8607792 100644 --- a/lib/xdrmappings/GwXDRMappings.cpp +++ b/lib/xdrmappings/GwXDRMappings.cpp @@ -90,7 +90,7 @@ static GwXDRType::TypeCode findTypeMapping(GwXDRCategory category, int field) } return GwXDRType::UNKNOWN; } - +//category,direction,selector,field,instanceMode,instance,name String GwXDRMappingDef::toString() { String rt = ""; @@ -105,6 +105,8 @@ String GwXDRMappingDef::toString() rt += String(instanceMode); rt += ","; rt += String(instanceId); + rt += ","; + rt += xdrName; return rt; } bool GwXDRMappingDef::handleToken(String tok, int index, GwXDRMappingDef *def) @@ -151,10 +153,13 @@ bool GwXDRMappingDef::handleToken(String tok, int index, GwXDRMappingDef *def) i = tok.toInt(); def->instanceId = i; return true; + case 6: + def->xdrName=tok; + return true; default: break; } - return false; + return true; //ignore unknown trailing stuff } GwXDRMappingDef *GwXDRMappingDef::fromString(String s) { @@ -216,7 +221,8 @@ void GwXDRMappings::begin() if (def) { int typeIndex = 0; - LOG_DEBUG(GwLog::DEBUG, "read xdr mapping %s", def->toString().c_str()); + LOG_DEBUG(GwLog::DEBUG, "read xdr mapping %s from %s", + def->toString().c_str(),namebuf); //n2k: find first matching type mapping GwXDRType::TypeCode code = findTypeMapping(def->category, def->field); if (code == GwXDRType::UNKNOWN) @@ -271,6 +277,9 @@ void GwXDRMappings::begin() mapping=new GwXDRMapping(def,type); } } + else{ + LOG_DEBUG(GwLog::DEBUG,"unable to parse mapping %s",cfg->asCString()); + } } } } @@ -279,7 +288,7 @@ void GwXDRMappings::begin() * select the best matching mapping * depending on the instance id */ -GwXDRFoundMapping GwXDRMappings::selectMapping(GwXDRMapping::MappingList *list,int instance){ +GwXDRFoundMapping GwXDRMappings::selectMapping(GwXDRMapping::MappingList *list,int instance,unsigned long key){ GwXDRMapping *candidate=NULL; for (auto mit=list->begin();mit != list->end();mit++){ GwXDRMappingDef *def=(*mit)->definition; @@ -300,6 +309,10 @@ GwXDRFoundMapping GwXDRMappings::selectMapping(GwXDRMapping::MappingList *list,i case GwXDRMappingDef::IS_AUTO: candidate=*mit; break; + case GwXDRMappingDef::IS_IGNORE: + if (candidate == NULL) candidate=*mit; + break; + default: break; } @@ -309,6 +322,7 @@ GwXDRFoundMapping GwXDRMappings::selectMapping(GwXDRMapping::MappingList *list,i LOG_DEBUG(GwLog::DEBUG,"found mapping %s",candidate->definition->toString().c_str()); return GwXDRFoundMapping(candidate,instance); } + LOG_DEBUG(GwLog::DEBUG,"no instance mapping found for key=%lu, i=%d",key,instance); return GwXDRFoundMapping(); } GwXDRFoundMapping GwXDRMappings::getMapping(String xName,String xType,String xUnit){ @@ -330,12 +344,30 @@ GwXDRFoundMapping GwXDRMappings::getMapping(String xName,String xType,String xUn return selectMapping(&(it->second),instance); } GwXDRFoundMapping GwXDRMappings::getMapping(GwXDRCategory category,int selector,int field,int instance){ - long n2kKey=GwXDRMappingDef::n2kKey(category,selector,field); + unsigned long n2kKey=GwXDRMappingDef::n2kKey(category,selector,field); auto it=n2kMap.find(n2kKey); if (it == n2kMap.end()){ LOG_DEBUG(GwLog::DEBUG,"find n2kmapping for c=%d,s=%d,f=%d,i=%d - nothing found", (int)category,selector,field,instance); + addUnknown(category,selector,field,instance); return GwXDRFoundMapping(); } - return selectMapping(&(it->second),instance); + GwXDRFoundMapping rt=selectMapping(&(it->second),instance); + if (rt.empty){ + addUnknown(category,selector,field,instance); + } + return rt; +} +#define MAX_UNKNOWN 200 +bool GwXDRMappings::addUnknown(GwXDRCategory category,int selector,int field,int instance){ + if (unknown.size() >= 200) return false; + unsigned long uk=((int)category) &0x7f; + if (selector < 0) selector=0; + uk=(uk<<7) + (selector &0x7f); + if (field < 0) field=0; + uk=(uk<<7) + (field & 0x7f); + if (instance < 0 || instance > 255) instance=256; //unknown + uk=(uk << 9) + (instance & 0x1ff); + unknown.push_back(uk); + return true; } \ No newline at end of file diff --git a/lib/xdrmappings/GwXDRMappings.h b/lib/xdrmappings/GwXDRMappings.h index a53eea8..cf66b10 100644 --- a/lib/xdrmappings/GwXDRMappings.h +++ b/lib/xdrmappings/GwXDRMappings.h @@ -9,7 +9,7 @@ typedef enum { XDRTEMP=0, XDRHUMIDITY=1, - XDRPRSSURE=2, + XDRPRESSURE=2, XDRTIME=3, //unused XDRFLUID=4, XDRDCTYPE=5, //unused @@ -79,7 +79,7 @@ class GwXDRMappingDef{ String xdrName; GwXDRCategory category; int selector=-1; - int field=-1; + int field=0; InstanceMode instanceMode=IS_AUTO; int instanceId=-1; Direction direction=M_BOTH; @@ -97,21 +97,22 @@ class GwXDRMappingDef{ GwXDRMappingDef(){ category=XDRTEMP; } + //category,direction,selector,field,instanceMode,instance,name String toString(); static GwXDRMappingDef *fromString(String s); //we allow 100 entities of code,selector and field nid - static long n2kKey(GwXDRCategory category, int selector, int field) + static unsigned long n2kKey(GwXDRCategory category, int selector, int field) { - long rt = (int)category; + long rt = ((int)category)&0xff; if (selector < 0) selector = 0; - rt = rt * 100 + selector; + rt = (rt<<8) + (selector & 0xff); if (field < 0) field = 0; - rt = rt * 100 * field; + rt = (rt <<8) + (field & 0xff); return rt; } - long n2kKey(){ + unsigned long n2kKey(){ return n2kKey(category,selector,field); } static String n183key(String xdrName, String xdrType, String xdrUnit) @@ -136,7 +137,7 @@ class GwXDRMapping{ } typedef std::vector MappingList; typedef std::map N138Map; - typedef std::map N2KMap; + typedef std::map N2KMap; }; class GwXDRFoundMapping{ public: @@ -164,7 +165,9 @@ class GwXDRMappings{ GwConfigHandler *config; GwXDRMapping::N138Map n183Map; GwXDRMapping::N2KMap n2kMap; + std::vector unknown; GwXDRFoundMapping selectMapping(GwXDRMapping::MappingList *list,int instance); + bool addUnknown(GwXDRCategory category,int selector,int field=0,int instance=-1); public: GwXDRMappings(GwLog *logger,GwConfigHandler *config); void begin(); diff --git a/src/main.cpp b/src/main.cpp index d265651..5aed3c5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -85,6 +85,7 @@ bool fixedApPass=true; GwWifi gwWifi(&config,&logger,fixedApPass); GwSocketServer socketServer(&config,&logger,MIN_TCP_CHANNEL_ID); GwBoatData boatData(&logger); +GwXDRMappings xdrMappings(&logger,&config); int NodeAddress; // To store last Node Address @@ -249,7 +250,7 @@ bool delayedRestart(){ void startAddOnTask(TaskFunction_t task,int sourceId){ ApiImpl* api=new ApiImpl(sourceId); - xTaskCreate(task,"user",1000,api,3,NULL); + xTaskCreate(task,"user",2000,api,3,NULL); } #define JSON_OK "{\"status\":\"OK\"}" @@ -525,9 +526,11 @@ void setup() { { return new BoatDataRequest(); }); webserver.begin(); + xdrMappings.begin(); + logger.flush(); nmea0183Converter= N2kDataToNMEA0183::create(&logger, &boatData,&NMEA2000, - SendNMEA0183Message, N2K_CHANNEL_ID,config.getString(config.talkerId,String("GP"))); + SendNMEA0183Message, N2K_CHANNEL_ID,config.getString(config.talkerId,String("GP")),&xdrMappings); toN2KConverter= NMEA0183DataToN2K::create(&logger,&boatData,[](const tN2kMsg &msg)->bool{ logger.logDebug(GwLog::DEBUG+2,"send N2K %ld",msg.PGN); @@ -591,10 +594,12 @@ void setup() { nmea0183Converter->HandleMsg(n2kMsg); }); NMEA2000.Open(); + logger.logDebug(GwLog::LOG,"starting addon tasks"); + logger.flush(); startAddOnTask(handleButtons,100); setLedMode(LED_GREEN); startAddOnTask(handleLeds,101); - + logger.logDebug(GwLog::LOG,"setup done"); } //***************************************************************************** diff --git a/web/config.json b/web/config.json index 885d9f0..873dafa 100644 --- a/web/config.json +++ b/web/config.json @@ -237,6 +237,22 @@ "check": "checkSSID", "description": "the SSID for an external WIFI network", "category":"wifi client" + }, + { + "name": "XDR1", + "label": "XDR1", + "type": "xdr", + "default": "", + "check": "checkXDR", + "category":"xdr" + }, + { + "name": "XDR2", + "label": "XDR2", + "type": "xdr", + "default": "", + "check": "checkXDR", + "category":"xdr" }