ttlappalainen / NMEA0183

Library for handling NMEA0183 messages
73 stars 47 forks source link

HDG,HDM,HDT conversion to 127250 (and reverse conversion in N2kDataToNMEA0183) #54

Open dagnall53 opened 11 months ago

dagnall53 commented 11 months ago

Timo, Thanks for your help, and perhaps I can suggest a small contribution.

I find that the heading conversions (HDM HDT and HDG) to N2K and then back to 0183 all resulted in HDG, which to my thinking is incorrect, as it converts a (eg) HDM to a HDG, and thus presents (HDG) data (e.g. previously sent variation), that was not present (and may therefore be incorrect or outdated) when the 0183 HDM was sent.. The 127250 message seems sufficiently well defined to allow the conversion of a HDM or HDT so that a demonstrably N2K>0183 conversion back to HDM or HDT can be made- avoiding conversion to HDG with possibly incorrect saved variation / deviation parameters.

I have placed below my suggested HandleHDT, HandleHDM, HandleHDG functions from NMEA0183Handlers.cpp, and the N2KDataToNMEA0183.cpp "HandleHeading" (I wanted to avoid making a duplicate issue in N2k)..

I tested with these

$IIHDM,310.1,M21 $IIHDT,320.1,T22 $GPHDG,310.1,,,,5D $GPHDG,310.1,,,10.0,E07 $GPHDG,310.1,5.0,E,5.0,E*5D

The third case is one I would not expect in practice as it is HDG without deviation or variation, and I would have expected the instrument to send HDM in this case, and it is not possible (I think) to differentiate this 127250 from one sent with the simpler HDM. The results of 0183>N2K>0183 are shown below. (but change to GP).

$GPHDM,310.1,M36 $GPHDT,320.1,T35 $GPHDM,310.1,M36 $GPHDG,310.1,,,10.0,E07 $GPHDG,310.1,5.0,E,5.0,E*5D

Code shown below.

`void HandleHDT(const tNMEA0183Msg &NMEA0183Msg) { // HDT to PGN 127250 if (pBD == 0) { return; }; if (NMEA0183ParseHDT_nc(NMEA0183Msg, pBD->TrueHeading)) { // get value if (pNMEA2000 != 0) { SID = SID + 1; if (SID >= 100) { SID = 1; } // increment SID to differentiate this "set" of NAV data from any previous "sets" tN2kMsg N2kMsg; if (NMEA0183ParseHDT_nc(NMEA0183Msg, pBD->TrueHeading)) { //Use library Parse to get the TRUE heading into the boat data and do the next if that suceeds SetN2kPGN127250(N2kMsg, SID, pBD->TrueHeading, NMEA0183DoubleNA, NMEA0183DoubleNA, N2khr_true); SendMessageOnceBuilt(N2kMsg); } } } } void HandleHDM(const tNMEA0183Msg &NMEA0183Msg) { // HDM to PGN 127250
if (pBD == 0) {return;} if (pNMEA2000 != 0) { tN2kMsg N2kMsg; SID = SID + 1; if (SID >= 100) { SID = 1; } // increment SID to differentiate this "set" of NAV data from any previous "sets" if (NMEA0183ParseHDM_nc(NMEA0183Msg, pBD->MagneticHeading)) { //NOTE do not use saved variation.. we only got a HDM, so send it "honsestly" SetN2kPGN127250(N2kMsg, SID, pBD->MagneticHeading, NMEA0183DoubleNA, NMEA0183DoubleNA, N2khr_magnetic); SendMessageOnceBuilt(N2kMsg); } } } void HandleHDG(const tNMEA0183Msg &NMEA0183Msg) { // HDG to PGN 127250 Save MAGHeading (and variation if received) in boat data. Deviation is just local if (pBD == 0) return; if (pNMEA2000 != 0) { tN2kMsg N2kMsg; SID = SID + 1; if (SID >= 100) { SID = 1; } // increment SID to differentiate this "set" of NAV data from any previous "sets" //Get HDG data (in degrees) double heading = NMEA0183GetDouble(NMEA0183Msg.Field(0)); pBD->MagneticHeading = DegToRad(heading); double deviation = NMEA0183GetDouble(NMEA0183Msg.Field(1)); double variation = NMEA0183GetDouble(NMEA0183Msg.Field(3)); // Correct for Deviation and Variation if available to give heading in N2000 format for PGN127250 if ((NMEA0183GetDouble(NMEA0183Msg.Field(1)) != NMEA0183DoubleNA) && (NMEA0183GetDouble(NMEA0183Msg.Field(2)) != NMEA0183DoubleNA)) { // we have deviation data. if (NMEA0183Msg.Field(2)[0] == 'W') { deviation = -deviation; } heading = heading + deviation; //Update heading(deg) with Deviation(deg) deviation = DegToRad(deviation); } if ((NMEA0183GetDouble(NMEA0183Msg.Field(3)) != NMEA0183DoubleNA) && (NMEA0183GetDouble(NMEA0183Msg.Field(4)) != NMEA0183DoubleNA)) { // we have deviation data. if (NMEA0183Msg.Field(4)[0] == 'W') { variation = -variation; } heading = heading + variation; //Update heading(deg) with Variation(deg) pBD->Variation = DegToRad(variation); //Save for other functions to use. } // NB if No variation was sent, do not use an old and potentially incorrect one ! pBD->TrueHeading = DegToRad(heading); //Save for other functions to use. // N2000 uses Radians SetN2kPGN127250(N2kMsg, SID, pBD->TrueHeading, deviation, DegToRad(variation), N2khr_magnetic); // set N2khr_magnetic but do NOT send pBD->Variation unless we received it! as this MAY be old. SendMessageOnceBuilt(N2kMsg); } }

void tN2kDataToNMEA0183::HandleHeading(const tN2kMsg &N2kMsg) { / 1 Sequence ID 2 Heading Sensor Reading 3 Deviation 4 Variation 5 Heading Sensor Reference 6 NMEA Reserved {"Vessel Heading", https://github.com/canboat/canboat/blob/master/analyzer/pgn.h 127250, PACKET_COMPLETE, PACKET_SINGLE, {UINT8_FIELD("SID"), ANGLE_U16_FIELD("Heading", NULL), ANGLE_I16_FIELD("Deviation", NULL), ANGLE_I16_FIELD("Variation", NULL), LOOKUP_FIELD("Reference", 2, DIRECTION_REFERENCE), RESERVED_FIELD(6), END_OF_FIELDS}, .interval = 100} / unsigned char SID; tN2kHeadingReference ref; double Deviation = 0; // not used in other places ? double _Deviation = 0; double _Variation; tNMEA0183Msg NMEA0183Msg; //Select which message to send! depending on type of data received: If N2khr_magnetic -- send HDG or HDM depending on if DEV/Var were seen. //if N2khr_true send HDT! bool SendHDM = true; if (ParseN2kHeading(N2kMsg, SID, Heading, _Deviation, _Variation, ref)) { LastHeadingTime = millis(); if (ref == N2khr_magnetic) { if (!N2kIsNA(_Deviation)) { // Update Deviation, Send HDG Deviation = _Deviation; SendHDM = false; }
if (!N2kIsNA(_Variation)) { // Update Variation, Send HDG Variation = _Variation; SendHDM = false; }
if (!N2kIsNA(Heading) && !N2kIsNA(_Deviation)) { Heading -= Deviation; } if (!N2kIsNA(Heading) && !N2kIsNA(_Variation)) { Heading -= Variation; } if (SendHDM) { if (NMEA0183SetHDM(NMEA0183Msg, Heading)) { SendMessage(NMEA0183Msg); } } else { //data included Deviation and/or Variation so send as HDG if (NMEA0183SetHDG(NMEA0183Msg, Heading, _Deviation, Variation)) { SendMessage(NMEA0183Msg); } } } else { // data was "true" so send as HDT! if (NMEA0183SetHDT(NMEA0183Msg, Heading)) { SendMessage(NMEA0183Msg); } } } }`