From 35ff689cd94f4c77f0a411eab59f711832838a0f Mon Sep 17 00:00:00 2001 From: andreas Date: Fri, 22 Oct 2021 13:08:25 +0200 Subject: [PATCH] include ais conversion --- extra_script.py | 7 + lib/nmea2kto0183/N2kToNMEA0183Functions.h | 439 ++++++++++++++++++++-- src/main.cpp | 2 +- 3 files changed, 415 insertions(+), 33 deletions(-) diff --git a/extra_script.py b/extra_script.py index 6d76e79..ffe4d6b 100644 --- a/extra_script.py +++ b/extra_script.py @@ -1,10 +1,17 @@ print("running extra...") import gzip import shutil +import os FILES=['web/index.html'] def compressFile(inFile): outfile=inFile+".gz" + if os.path.exists(outfile): + otime=os.path.getmtime(outfile) + itime=os.path.getmtime(inFile) + if (otime >= itime): + print("%s is newer then %s, no need to recreate"%(outfile,inFile)) + return with open(inFile, 'rb') as f_in: with gzip.open(outfile, 'wb') as f_out: shutil.copyfileobj(f_in, f_out) diff --git a/lib/nmea2kto0183/N2kToNMEA0183Functions.h b/lib/nmea2kto0183/N2kToNMEA0183Functions.h index e4529ce..891db43 100644 --- a/lib/nmea2kto0183/N2kToNMEA0183Functions.h +++ b/lib/nmea2kto0183/N2kToNMEA0183Functions.h @@ -12,9 +12,11 @@ #include "N2kDataToNMEA0183.h" #include #include "NMEA0183AISMessages.h" +#include "NMEA0183AISMsg.h" class N2kToNMEA0183Functions : public N2kDataToNMEA0183 { typedef void (N2kToNMEA0183Functions::*N2KConverter)(const tN2kMsg &N2kMsg); + private: static const unsigned long RMCPeriod = 500; static void setMax(GwBoatItem *maxItem, GwBoatItem *item) @@ -91,40 +93,45 @@ private: unsigned long LastPosSend; unsigned long NextRMCSend; unsigned long lastLoopTime; - class ConverterEntry{ - public: - unsigned long count=0; - N2KConverter converter; - ConverterEntry(N2KConverter cv=NULL){converter=cv;} + class ConverterEntry + { + public: + unsigned long count = 0; + N2KConverter converter; + ConverterEntry(N2KConverter cv = NULL) { converter = cv; } }; - typedef std::map ConverterMap; + typedef std::map ConverterMap; ConverterMap converters; /** * register a n2k message converter * each of the converter functions must be registered in the constructor **/ - void registerConverter(long pgn,N2KConverter converter){ + void registerConverter(long pgn, N2KConverter converter) + { ConverterEntry e(converter); - converters[pgn]=e; + converters[pgn] = e; } - virtual const unsigned long * handledPgns(){ - logger->logString("CONV: # %d handled PGNS",(int)converters.size()); - unsigned long *rt=new unsigned long[converters.size()+1]; - int idx=0; - for (ConverterMap::iterator it=converters.begin(); - it != converters.end();it++){ - rt[idx]=it->first; + virtual const unsigned long *handledPgns() + { + logger->logString("CONV: # %d handled PGNS", (int)converters.size()); + unsigned long *rt = new unsigned long[converters.size() + 1]; + int idx = 0; + for (ConverterMap::iterator it = converters.begin(); + it != converters.end(); it++) + { + rt[idx] = it->first; idx++; } - rt[idx]=0; + rt[idx] = 0; return rt; } virtual void HandleMsg(const tN2kMsg &N2kMsg) { ConverterMap::iterator it; it = converters.find(N2kMsg.PGN); - if (it != converters.end()){ + if (it != converters.end()) + { //logger->logString("CONV: handle PGN %ld",N2kMsg.PGN); (it->second).count++; //call to member function - see e.g. https://isocpp.org/wiki/faq/pointers-to-members @@ -132,12 +139,15 @@ private: return; } } - virtual void toJson(JsonDocument &json){ - for (ConverterMap::iterator it=converters.begin();it != converters.end();it++){ - json["cnv"][String(it->first)]=it->second.count; + virtual void toJson(JsonDocument &json) + { + for (ConverterMap::iterator it = converters.begin(); it != converters.end(); it++) + { + json["cnv"][String(it->first)] = it->second.count; } } - virtual int numPgns(){ + virtual int numPgns() + { return converters.size(); } void SetNextRMCSend() { NextRMCSend = millis() + RMCPeriod; } @@ -479,6 +489,365 @@ private: } } + //***************************************************************************** + // 129038 AIS Class A Position Report (Message 1, 2, 3) + void HandleAISClassAPosReport(const tN2kMsg &N2kMsg) + { + + unsigned char SID; + tN2kAISRepeat _Repeat; + uint32_t _UserID; // MMSI + double _Latitude; + double _Longitude; + bool _Accuracy; + bool _RAIM; + uint8_t _Seconds; + double _COG; + double _SOG; + double _Heading; + double _ROT; + tN2kAISNavStatus _NavStatus; + + uint8_t _MessageType = 1; + tNMEA0183AISMsg NMEA0183AISMsg; + + if (ParseN2kPGN129038(N2kMsg, SID, _Repeat, _UserID, _Latitude, _Longitude, _Accuracy, _RAIM, _Seconds, + _COG, _SOG, _Heading, _ROT, _NavStatus)) + { + +// Debug +#ifdef SERIAL_PRINT_AIS_FIELDS + Serial.println("–––––––––––––––––––––––– Msg 1 ––––––––––––––––––––––––––––––––"); + + const double pi = 3.1415926535897932384626433832795; + const double radToDeg = 180.0 / pi; + const double msTokn = 3600.0 / 1852.0; + const double radsToDegMin = 60 * 360.0 / (2 * pi); // [rad/s -> degree/minute] + Serial.print("Repeat: "); + Serial.println(_Repeat); + Serial.print("UserID: "); + Serial.println(_UserID); + Serial.print("Latitude: "); + Serial.println(_Latitude); + Serial.print("Longitude: "); + Serial.println(_Longitude); + Serial.print("Accuracy: "); + Serial.println(_Accuracy); + Serial.print("RAIM: "); + Serial.println(_RAIM); + Serial.print("Seconds: "); + Serial.println(_Seconds); + Serial.print("COG: "); + Serial.println(_COG * radToDeg); + Serial.print("SOG: "); + Serial.println(_SOG * msTokn); + Serial.print("Heading: "); + Serial.println(_Heading * radToDeg); + Serial.print("ROT: "); + Serial.println(_ROT * radsToDegMin); + Serial.print("NavStatus: "); + Serial.println(_NavStatus); +#endif + + if (SetAISClassABMessage1(NMEA0183AISMsg, _MessageType, _Repeat, _UserID, _Latitude, _Longitude, _Accuracy, + _RAIM, _Seconds, _COG, _SOG, _Heading, _ROT, _NavStatus)) + { + + SendMessage(NMEA0183AISMsg); + +#ifdef SERIAL_PRINT_AIS_NMEA + // Debug Print AIS-NMEA + Serial.print(NMEA0183AISMsg.GetPrefix()); + Serial.print(NMEA0183AISMsg.Sender()); + Serial.print(NMEA0183AISMsg.MessageCode()); + for (int i = 0; i < NMEA0183AISMsg.FieldCount(); i++) + { + Serial.print(","); + Serial.print(NMEA0183AISMsg.Field(i)); + } + char buf[7]; + sprintf(buf, "*%02X\r\n", NMEA0183AISMsg.GetCheckSum()); + Serial.print(buf); +#endif + } + } + } // end 129038 AIS Class A Position Report Message 1/3 + + //***************************************************************************** + // 129039 AIS Class B Position Report -> AIS Message Type 5: Static and Voyage Related Data + void HandleAISClassAMessage5(const tN2kMsg &N2kMsg) + { + uint8_t _MessageID; + tN2kAISRepeat _Repeat; + uint32_t _UserID; // MMSI + uint32_t _IMONumber; + char _Callsign[8]; + char _Name[21]; + uint8_t _VesselType; + double _Length; + double _Beam; + double _PosRefStbd; + double _PosRefBow; + uint16_t _ETAdate; + double _ETAtime; + double _Draught; + char _Destination[21]; + tN2kAISVersion _AISversion; + tN2kGNSStype _GNSStype; + tN2kAISTranceiverInfo _AISinfo; + tN2kAISDTE _DTE; + + tNMEA0183AISMsg NMEA0183AISMsg; + + if (ParseN2kPGN129794(N2kMsg, _MessageID, _Repeat, _UserID, _IMONumber, _Callsign, _Name, _VesselType, + _Length, _Beam, _PosRefStbd, _PosRefBow, _ETAdate, _ETAtime, _Draught, _Destination, + _AISversion, _GNSStype, _DTE, _AISinfo)) + { + +#ifdef SERIAL_PRINT_AIS_FIELDS + // Debug Print N2k Values + Serial.println("––––––––––––––––––––––– Msg 5 –––––––––––––––––––––––––––––––––"); + Serial.print("MessageID: "); + Serial.println(_MessageID); + Serial.print("Repeat: "); + Serial.println(_Repeat); + Serial.print("UserID: "); + Serial.println(_UserID); + Serial.print("IMONumber: "); + Serial.println(_IMONumber); + Serial.print("Callsign: "); + Serial.println(_Callsign); + Serial.print("VesselType: "); + Serial.println(_VesselType); + Serial.print("Name: "); + Serial.println(_Name); + Serial.print("Length: "); + Serial.println(_Length); + Serial.print("Beam: "); + Serial.println(_Beam); + Serial.print("PosRefStbd: "); + Serial.println(_PosRefStbd); + Serial.print("PosRefBow: "); + Serial.println(_PosRefBow); + Serial.print("ETAdate: "); + Serial.println(_ETAdate); + Serial.print("ETAtime: "); + Serial.println(_ETAtime); + Serial.print("Draught: "); + Serial.println(_Draught); + Serial.print("Destination: "); + Serial.println(_Destination); + Serial.print("GNSStype: "); + Serial.println(_GNSStype); + Serial.print("DTE: "); + Serial.println(_DTE); + Serial.println("––––––––––––––––––––––– Msg 5 –––––––––––––––––––––––––––––––––"); +#endif + + if (SetAISClassAMessage5(NMEA0183AISMsg, _MessageID, _Repeat, _UserID, _IMONumber, _Callsign, _Name, _VesselType, + _Length, _Beam, _PosRefStbd, _PosRefBow, _ETAdate, _ETAtime, _Draught, _Destination, + _GNSStype, _DTE)) + { + + SendMessage(NMEA0183AISMsg.BuildMsg5Part1(NMEA0183AISMsg)); + +#ifdef SERIAL_PRINT_AIS_NMEA + // Debug Print AIS-NMEA Message Type 5, Part 1 + char buf[7]; + Serial.print(NMEA0183AISMsg.GetPrefix()); + Serial.print(NMEA0183AISMsg.Sender()); + Serial.print(NMEA0183AISMsg.MessageCode()); + for (int i = 0; i < NMEA0183AISMsg.FieldCount(); i++) + { + Serial.print(","); + Serial.print(NMEA0183AISMsg.Field(i)); + } + sprintf(buf, "*%02X\r\n", NMEA0183AISMsg.GetCheckSum()); + Serial.print(buf); +#endif + + SendMessage(NMEA0183AISMsg.BuildMsg5Part2(NMEA0183AISMsg)); + +#ifdef SERIAL_PRINT_AIS_NMEA + // Print AIS-NMEA Message Type 5, Part 2 + Serial.print(NMEA0183AISMsg.GetPrefix()); + Serial.print(NMEA0183AISMsg.Sender()); + Serial.print(NMEA0183AISMsg.MessageCode()); + for (int i = 0; i < NMEA0183AISMsg.FieldCount(); i++) + { + Serial.print(","); + Serial.print(NMEA0183AISMsg.Field(i)); + } + sprintf(buf, "*%02X\r\n", NMEA0183AISMsg.GetCheckSum()); + Serial.print(buf); +#endif + } + } + } + + // + //***************************************************************************** + // 129039 AIS Class B Position Report (Message 18) + void HandleAISClassBMessage18(const tN2kMsg &N2kMsg) + { + uint8_t _MessageID; + tN2kAISRepeat _Repeat; + uint32_t _UserID; // MMSI + double _Latitude; + double _Longitude; + bool _Accuracy; + bool _RAIM; + uint8_t _Seconds; + double _COG; + double _SOG; + double _Heading; + tN2kAISUnit _Unit; + bool _Display, _DSC, _Band, _Msg22, _State; + tN2kAISMode _Mode; + + if (ParseN2kPGN129039(N2kMsg, _MessageID, _Repeat, _UserID, _Latitude, _Longitude, _Accuracy, _RAIM, + _Seconds, _COG, _SOG, _Heading, _Unit, _Display, _DSC, _Band, _Msg22, _Mode, _State)) + { + + tNMEA0183AISMsg NMEA0183AISMsg; + + if (SetAISClassBMessage18(NMEA0183AISMsg, _MessageID, _Repeat, _UserID, _Latitude, _Longitude, _Accuracy, _RAIM, + _Seconds, _COG, _SOG, _Heading, _Unit, _Display, _DSC, _Band, _Msg22, _Mode, _State)) + { + + SendMessage(NMEA0183AISMsg); + +#ifdef SERIAL_PRINT_AIS_NMEA + // Debug Print AIS-NMEA + Serial.print(NMEA0183AISMsg.GetPrefix()); + Serial.print(NMEA0183AISMsg.Sender()); + Serial.print(NMEA0183AISMsg.MessageCode()); + for (int i = 0; i < NMEA0183AISMsg.FieldCount(); i++) + { + Serial.print(","); + Serial.print(NMEA0183AISMsg.Field(i)); + } + char buf[7]; + sprintf(buf, "*%02X\r\n", NMEA0183AISMsg.GetCheckSum()); + Serial.print(buf); +#endif + } + } + return; + } + + //***************************************************************************** + // PGN 129809 AIS Class B "CS" Static Data Report, Part A + void HandleAISClassBMessage24A(const tN2kMsg &N2kMsg) + { + + uint8_t _MessageID; + tN2kAISRepeat _Repeat; + uint32_t _UserID; // MMSI + char _Name[21]; + + if (ParseN2kPGN129809(N2kMsg, _MessageID, _Repeat, _UserID, _Name)) + { + + tNMEA0183AISMsg NMEA0183AISMsg; + if (SetAISClassBMessage24PartA(NMEA0183AISMsg, _MessageID, _Repeat, _UserID, _Name)) + { + } + } + return; + } + + //***************************************************************************** + // PGN 129810 AIS Class B "CS" Static Data Report, Part B -> AIS Message 24 (2 Parts) + void HandleAISClassBMessage24B(const tN2kMsg &N2kMsg) + { + + uint8_t _MessageID; + tN2kAISRepeat _Repeat; + uint32_t _UserID, _MothershipID; // MMSI + char _Callsign[8]; + char _Vendor[4]; + uint8_t _VesselType; + double _Length; + double _Beam; + double _PosRefStbd; + double _PosRefBow; + + if (ParseN2kPGN129810(N2kMsg, _MessageID, _Repeat, _UserID, _VesselType, _Vendor, _Callsign, + _Length, _Beam, _PosRefStbd, _PosRefBow, _MothershipID)) + { + +// +#ifdef SERIAL_PRINT_AIS_FIELDS + // Debug Print N2k Values + Serial.println("––––––––––––––––––––––– Msg 24 ––––––––––––––––––––––––––––––––"); + Serial.print("MessageID: "); + Serial.println(_MessageID); + Serial.print("Repeat: "); + Serial.println(_Repeat); + Serial.print("UserID: "); + Serial.println(_UserID); + Serial.print("VesselType: "); + Serial.println(_VesselType); + Serial.print("Vendor: "); + Serial.println(_Vendor); + Serial.print("Callsign: "); + Serial.println(_Callsign); + Serial.print("Length: "); + Serial.println(_Length); + Serial.print("Beam: "); + Serial.println(_Beam); + Serial.print("PosRefStbd: "); + Serial.println(_PosRefStbd); + Serial.print("PosRefBow: "); + Serial.println(_PosRefBow); + Serial.print("MothershipID: "); + Serial.println(_MothershipID); + Serial.println("––––––––––––––––––––––– Msg 24 ––––––––––––––––––––––––––––––––"); +#endif + + tNMEA0183AISMsg NMEA0183AISMsg; + + if (SetAISClassBMessage24(NMEA0183AISMsg, _MessageID, _Repeat, _UserID, _VesselType, _Vendor, _Callsign, + _Length, _Beam, _PosRefStbd, _PosRefBow, _MothershipID)) + { + + SendMessage(NMEA0183AISMsg.BuildMsg24PartA(NMEA0183AISMsg)); + +#ifdef SERIAL_PRINT_AIS_NMEA + // Debug Print AIS-NMEA + char buf[7]; + Serial.print(NMEA0183AISMsg.GetPrefix()); + Serial.print(NMEA0183AISMsg.Sender()); + Serial.print(NMEA0183AISMsg.MessageCode()); + for (int i = 0; i < NMEA0183AISMsg.FieldCount(); i++) + { + Serial.print(","); + Serial.print(NMEA0183AISMsg.Field(i)); + } + sprintf(buf, "*%02X\r\n", NMEA0183AISMsg.GetCheckSum()); + Serial.print(buf); +#endif + + SendMessage(NMEA0183AISMsg.BuildMsg24PartB(NMEA0183AISMsg)); + +#ifdef SERIAL_PRINT_AIS_NMEA + Serial.print(NMEA0183AISMsg.GetPrefix()); + Serial.print(NMEA0183AISMsg.Sender()); + Serial.print(NMEA0183AISMsg.MessageCode()); + for (int i = 0; i < NMEA0183AISMsg.FieldCount(); i++) + { + Serial.print(","); + Serial.print(NMEA0183AISMsg.Field(i)); + } + sprintf(buf, "*%02X\r\n", NMEA0183AISMsg.GetCheckSum()); + Serial.print(buf); +#endif + } + } + return; + } + public: N2kToNMEA0183Functions(GwLog *logger, GwBoatData *boatData, tNMEA2000 *NMEA2000, tNMEA0183 *NMEA0183) : N2kDataToNMEA0183(logger, boatData, NMEA2000, NMEA0183) { @@ -516,17 +885,23 @@ public: //and register it here //with this approach we easily have a list of all handled //pgns - registerConverter(127250UL,&N2kToNMEA0183Functions::HandleHeading); - registerConverter(127258UL,&N2kToNMEA0183Functions::HandleVariation); - registerConverter(128259UL,&N2kToNMEA0183Functions::HandleBoatSpeed); - registerConverter(128267UL,&N2kToNMEA0183Functions::HandleDepth); - registerConverter(129025UL,&N2kToNMEA0183Functions::HandlePosition); - registerConverter(129026UL,&N2kToNMEA0183Functions::HandleCOGSOG); - registerConverter(129029UL,&N2kToNMEA0183Functions::HandleGNSS); - registerConverter(130306UL,&N2kToNMEA0183Functions::HandleWind); - registerConverter(128275UL,&N2kToNMEA0183Functions::HandleLog); - registerConverter(127245UL,&N2kToNMEA0183Functions::HandleRudder); - registerConverter(130310UL,&N2kToNMEA0183Functions::HandleWaterTemp); + registerConverter(127250UL, &N2kToNMEA0183Functions::HandleHeading); + registerConverter(127258UL, &N2kToNMEA0183Functions::HandleVariation); + registerConverter(128259UL, &N2kToNMEA0183Functions::HandleBoatSpeed); + registerConverter(128267UL, &N2kToNMEA0183Functions::HandleDepth); + registerConverter(129025UL, &N2kToNMEA0183Functions::HandlePosition); + registerConverter(129026UL, &N2kToNMEA0183Functions::HandleCOGSOG); + registerConverter(129029UL, &N2kToNMEA0183Functions::HandleGNSS); + registerConverter(130306UL, &N2kToNMEA0183Functions::HandleWind); + registerConverter(128275UL, &N2kToNMEA0183Functions::HandleLog); + registerConverter(127245UL, &N2kToNMEA0183Functions::HandleRudder); + registerConverter(130310UL, &N2kToNMEA0183Functions::HandleWaterTemp); + registerConverter(129038UL, &N2kToNMEA0183Functions::HandleAISClassAPosReport); // AIS Class A Position Report, Message Type 1 + registerConverter(129039UL, &N2kToNMEA0183Functions::HandleAISClassBMessage18); // AIS Class B Position Report, Message Type 18 + registerConverter(129794UL, &N2kToNMEA0183Functions::HandleAISClassAMessage5); // AIS Class A Ship Static and Voyage related data, Message Type 5 + registerConverter(129809UL, &N2kToNMEA0183Functions::HandleAISClassBMessage24A); // AIS Class B "CS" Static Data Report, Part A + registerConverter(129810UL, &N2kToNMEA0183Functions::HandleAISClassBMessage24B); // AIS Class B "CS" Static Data Report, Part B + } virtual void loop() { diff --git a/src/main.cpp b/src/main.cpp index 5771b73..7dba46b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -102,7 +102,7 @@ void js_reset() // Wenn "http:///gauge.min.js" aufgerufen wurde void js_status(){ int numPgns=nmea0183Converter->numPgns(); - DynamicJsonDocument status(256*numPgns*30); + DynamicJsonDocument status(256+numPgns*50); status["numcan"]=numCan; status["version"]=VERSION; status["wifiConnected"]=gwWifi.clientConnected();