From 3cd9c5cea6f2f13aabf1e83c6e6a9fed5103afeb Mon Sep 17 00:00:00 2001 From: andreas Date: Thu, 11 Nov 2021 18:53:59 +0100 Subject: [PATCH] send/receive zda --- lib/boatData/GwBoatData.h | 1 + lib/nmea0183ton2k/NMEA0183DataToN2K.cpp | 58 ++++++++++++++++++------ lib/nmea2kto0183/N2kDataToNMEA0183.cpp | 59 +++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 14 deletions(-) diff --git a/lib/boatData/GwBoatData.h b/lib/boatData/GwBoatData.h index 830b95e..2fc9f18 100644 --- a/lib/boatData/GwBoatData.h +++ b/lib/boatData/GwBoatData.h @@ -144,6 +144,7 @@ class GwBoatData{ GWBOATDATA(uint32_t,Log,0,mtr2nm) GWBOATDATA(uint32_t,TripLog,0,mtr2nm) GWBOATDATA(uint32_t,DaysSince1970,4000,formatFixed0) + GWBOATDATA(int16_t,Timezone,8000,formatFixed0) public: GwBoatData(GwLog *logger); ~GwBoatData(); diff --git a/lib/nmea0183ton2k/NMEA0183DataToN2K.cpp b/lib/nmea0183ton2k/NMEA0183DataToN2K.cpp index 84d5221..2c43c4c 100644 --- a/lib/nmea0183ton2k/NMEA0183DataToN2K.cpp +++ b/lib/nmea0183ton2k/NMEA0183DataToN2K.cpp @@ -133,7 +133,7 @@ private: LOG_DEBUG(GwLog::DEBUG + 1, "convert RMB"); tRMB rmb; if (! NMEA0183ParseRMB_nc(msg,rmb)){ - logger->logDebug(GwLog::DEBUG, "failed to parse RMC %s", msg.line); + LOG_DEBUG(GwLog::DEBUG, "failed to parse RMC %s", msg.line); return; } tN2kMsg n2kMsg; @@ -197,7 +197,7 @@ private: char status; if (!NMEA0183ParseRMC_nc(msg, SecondsSinceMidnight, status, Latitude, Longitude, COG, SOG, DaysSince1970, Variation, &DateTime)) { - logger->logDebug(GwLog::DEBUG, "failed to parse RMC %s", msg.line); + LOG_DEBUG(GwLog::DEBUG, "failed to parse RMC %s", msg.line); return; } tN2kMsg n2kMsg; @@ -235,7 +235,7 @@ private: if (!NMEA0183ParseMWV_nc(msg, WindAngle, Reference,WindSpeed)) { - logger->logDebug(GwLog::DEBUG, "failed to parse MWV %s", msg.line); + LOG_DEBUG(GwLog::DEBUG, "failed to parse MWV %s", msg.line); return; } tN2kMsg n2kMsg; @@ -266,7 +266,7 @@ private: double WindAngle = NMEA0183DoubleNA, WindSpeed = NMEA0183DoubleNA; if (msg.FieldCount() < 8 || msg.FieldLen(0) < 1) { - logger->logDebug(GwLog::DEBUG, "failed to parse VWR %s", msg.line); + LOG_DEBUG(GwLog::DEBUG, "failed to parse VWR %s", msg.line); return; } WindAngle = atof(msg.Field(0)); @@ -308,7 +308,7 @@ private: WindSpeed = NMEA0183DoubleNA; if (msg.FieldCount() < 8 ) { - logger->logDebug(GwLog::DEBUG, "failed to parse MWD %s", msg.line); + LOG_DEBUG(GwLog::DEBUG, "failed to parse MWD %s", msg.line); return; } if (msg.FieldLen(0) > 0 && msg.Field(1)[0] == 'T') @@ -353,7 +353,7 @@ private: double MagneticHeading=NMEA0183DoubleNA; if (!NMEA0183ParseHDM_nc(msg, MagneticHeading)) { - logger->logDebug(GwLog::DEBUG, "failed to parse HDM %s", msg.line); + LOG_DEBUG(GwLog::DEBUG, "failed to parse HDM %s", msg.line); return; } if (! UD(MagneticHeading)) return; @@ -369,7 +369,7 @@ private: double Heading=NMEA0183DoubleNA; if (!NMEA0183ParseHDT_nc(msg, Heading)) { - logger->logDebug(GwLog::DEBUG, "failed to parse HDT %s", msg.line); + LOG_DEBUG(GwLog::DEBUG, "failed to parse HDT %s", msg.line); return; } if (! UD(Heading)) return; @@ -383,7 +383,7 @@ private: double Deviation=NMEA0183DoubleNA; if (msg.FieldCount() < 5) { - logger->logDebug(GwLog::DEBUG, "failed to parse HDG %s", msg.line); + LOG_DEBUG(GwLog::DEBUG, "failed to parse HDG %s", msg.line); return; } if (msg.FieldLen(0)>0){ @@ -414,7 +414,7 @@ private: double Offset=NMEA0183DoubleNA; if (msg.FieldCount() < 2) { - logger->logDebug(GwLog::DEBUG, "failed to parse DPT %s", msg.line); + LOG_DEBUG(GwLog::DEBUG, "failed to parse DPT %s", msg.line); return; } if (msg.FieldLen(0)>0){ @@ -445,7 +445,7 @@ private: double Depth=NMEA0183DoubleNA; if (msg.FieldCount() < 6) { - logger->logDebug(GwLog::DEBUG, "failed to parse DBK/DBS %s", msg.line); + LOG_DEBUG(GwLog::DEBUG, "failed to parse DBK/DBS %s", msg.line); return; } for (int i=0;i< 3;i++){ @@ -507,7 +507,7 @@ private: double RudderPosition=NMEA0183DoubleNA; if (msg.FieldCount() < 4) { - logger->logDebug(GwLog::DEBUG, "failed to parse RSA %s", msg.line); + LOG_DEBUG(GwLog::DEBUG, "failed to parse RSA %s", msg.line); return; } if (msg.FieldLen(0)>0){ @@ -525,7 +525,7 @@ private: double MagneticHeading=NMEA0183DoubleNA; double STW=NMEA0183DoubleNA; if (! NMEA0183ParseVHW_nc(msg,TrueHeading,MagneticHeading,STW)){ - logger->logDebug(GwLog::DEBUG, "failed to parse VHW %s", msg.line); + LOG_DEBUG(GwLog::DEBUG, "failed to parse VHW %s", msg.line); return; } if (! updateDouble(boatData->STW,STW,msg.sourceId)) return; @@ -541,7 +541,7 @@ private: double SOG=NMEA0183DoubleNA; double MCOG=NMEA0183DoubleNA; if (! NMEA0183ParseVTG_nc(msg,COG,MCOG,SOG)){ - logger->logDebug(GwLog::DEBUG, "failed to parse VTG %s", msg.line); + LOG_DEBUG(GwLog::DEBUG, "failed to parse VTG %s", msg.line); return; } if (! UD(COG)) return; @@ -551,6 +551,33 @@ private: SetN2kCOGSOGRapid(n2kMsg,1,N2khr_true,COG,SOG); send(n2kMsg); } + void convertZDA(const SNMEA0183Msg &msg){ + time_t DateTime; + long Timezone; + if (! NMEA0183ParseZDA(msg,DateTime,Timezone)){ + LOG_DEBUG(GwLog::DEBUG, "failed to parse ZDA %s", msg.line); + return; + } + uint32_t DaysSince1970=tNMEA0183Msg::elapsedDaysSince1970(DateTime); + tmElements_t parts; + tNMEA0183Msg::breakTime(DateTime,parts); + double SecondsSinceMidnight=parts.tm_sec+60*parts.tm_min+3600*parts.tm_hour; + if (! boatData->DaysSince1970->update(DaysSince1970,msg.sourceId)) return; + if (! boatData->SecondsSinceMidnight->update(SecondsSinceMidnight,msg.sourceId)) return; + bool timezoneValid=false; + if (msg.FieldLen(4) > 0 && msg.FieldLen(5)>0){ + Timezone=Timezone/60; //N2K has offset in minutes + if (! boatData->Timezone->update(Timezone,msg.sourceId)) return; + timezoneValid=true; + } + tN2kMsg n2kMsg; + if (timezoneValid){ + SetN2kLocalOffset(n2kMsg,DaysSince1970,SecondsSinceMidnight,Timezone); + send(n2kMsg); + } + SetN2kSystemTime(n2kMsg,1,DaysSince1970,SecondsSinceMidnight); + send(n2kMsg); + } //shortcut for lambda converters #define CVL [](const SNMEA0183Msg &msg, NMEA0183DataToN2KFunctions *p) -> void @@ -599,7 +626,10 @@ private: String(F("VHW")), &NMEA0183DataToN2KFunctions::convertVHW); converters.registerConverter( 129026UL, - String(F("VTG")), &NMEA0183DataToN2KFunctions::convertVTG); + String(F("VTG")), &NMEA0183DataToN2KFunctions::convertVTG); + converters.registerConverter( + 129033UL,126992UL, + String(F("ZDA")), &NMEA0183DataToN2KFunctions::convertZDA); unsigned long *aispgns=new unsigned long[7]{129810UL,129809UL,129040UL,129039UL,129802UL,129794UL,129038UL}; converters.registerConverter(7,&aispgns[0], String(F("AIVDM")),&NMEA0183DataToN2KFunctions::convertAIVDX); diff --git a/lib/nmea2kto0183/N2kDataToNMEA0183.cpp b/lib/nmea2kto0183/N2kDataToNMEA0183.cpp index 22bab19..8ab2e0f 100644 --- a/lib/nmea2kto0183/N2kDataToNMEA0183.cpp +++ b/lib/nmea2kto0183/N2kDataToNMEA0183.cpp @@ -104,6 +104,9 @@ private: if (! rt){ LOG_DEBUG(GwLog::DEBUG+1,"no handler for %ld",N2kMsg.PGN); } + else{ + //LOG_DEBUG(GwLog::DEBUG+1,"handled %ld",N2kMsg.PGN); + } } virtual void toJson(JsonDocument &json) { @@ -860,6 +863,60 @@ private: return; } + void HandleSystemTime(const tN2kMsg &msg){ + unsigned char sid=-1; + uint16_t DaysSince1970=N2kUInt16NA; + double SecondsSinceMidnight=N2kDoubleNA; + tN2kTimeSource TimeSource; + + if (! ParseN2kSystemTime(msg,sid,DaysSince1970,SecondsSinceMidnight,TimeSource)){ + LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN); + return; + } + updateDouble(boatData->SecondsSinceMidnight,SecondsSinceMidnight); + if (DaysSince1970 != N2kUInt16NA) boatData->DaysSince1970->update(DaysSince1970,sourceId); + if (boatData->DaysSince1970->isValid() && boatData->SecondsSinceMidnight->isValid()){ + tNMEA0183Msg nmeaMsg; + nmeaMsg.Init("ZDA",talkerId); + char utc[7]; + double seconds=boatData->SecondsSinceMidnight->getData(); + int hours=floor(seconds/3600.0); + int minutes=floor(seconds/60) - hours *60; + int sec=floor(seconds)-60*minutes-3600*hours; + snprintf(utc,7,"%02d%02d%02d",hours,minutes,sec); + nmeaMsg.AddStrField(utc); + tmElements_t timeParts; + tNMEA0183Msg::breakTime(tNMEA0183Msg::daysToTime_t(boatData->DaysSince1970->getData()),timeParts); + nmeaMsg.AddUInt32Field(tNMEA0183Msg::GetDay(timeParts)); + nmeaMsg.AddUInt32Field(tNMEA0183Msg::GetMonth(timeParts)); + nmeaMsg.AddUInt32Field(tNMEA0183Msg::GetYear(timeParts)); + if (boatData->Timezone->isValid()){ + int hours=boatData->Timezone->getData()/60; + int minutes=boatData->Timezone->getData() - 60 *hours; + nmeaMsg.AddDoubleField(hours,1,"%02.0f"); + nmeaMsg.AddDoubleField(minutes,1,"%02.0f"); + } + else{ + nmeaMsg.AddEmptyField(); + nmeaMsg.AddEmptyField(); + } + SendMessage(nmeaMsg); + } + } + + void HandleTimeOffset(const tN2kMsg &msg){ + uint16_t DaysSince1970 =N2kUInt16NA; + double SecondsSinceMidnight=N2kDoubleNA; + int16_t LocalOffset=N2kInt16NA; + if (!ParseN2kLocalOffset(msg,DaysSince1970,SecondsSinceMidnight,LocalOffset)){ + LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN); + return; + } + updateDouble(boatData->SecondsSinceMidnight,SecondsSinceMidnight); + if (DaysSince1970 != N2kUInt16NA) boatData->DaysSince1970->update(DaysSince1970,sourceId); + if (LocalOffset != N2kInt16NA) boatData->Timezone->update(LocalOffset,sourceId); + } + void registerConverters() { @@ -879,6 +936,8 @@ private: converters.registerConverter(128275UL, &N2kToNMEA0183Functions::HandleLog); converters.registerConverter(127245UL, &N2kToNMEA0183Functions::HandleRudder); converters.registerConverter(130310UL, &N2kToNMEA0183Functions::HandleWaterTemp); + converters.registerConverter(126992UL, &N2kToNMEA0183Functions::HandleSystemTime); + converters.registerConverter(129033UL, &N2kToNMEA0183Functions::HandleTimeOffset); #define HANDLE_AIS #ifdef HANDLE_AIS converters.registerConverter(129038UL, &N2kToNMEA0183Functions::HandleAISClassAPosReport); // AIS Class A Position Report, Message Type 1