34#include "rapidjson/document.h"
39#include "model/geodesic.h"
42bool CommDecoder::ParsePosition(
const LATLONG&
Position,
double& lat,
45 double llt =
Position.Latitude.Latitude;
47 if (!std::isnan(llt)) {
48 int lat_deg_int = (int)(llt / 100);
49 double lat_deg = lat_deg_int;
50 double lat_min = llt - (lat_deg * 100);
52 lat = lat_deg + (lat_min / 60.);
53 if (
Position.Latitude.Northing == South) lat = -lat;
57 double lln =
Position.Longitude.Longitude;
58 if (!std::isnan(lln)) {
59 int lon_deg_int = (int)(lln / 100);
60 double lon_deg = lon_deg_int;
61 double lon_min = lln - (lon_deg * 100);
63 lon = lon_deg + (lon_min / 60.);
64 if (
Position.Longitude.Easting == West) lon = -lon;
71bool CommDecoder::DecodeRMC(std::string s,
NavData& temp_data) {
72 wxString sentence(s.c_str());
74 m_NMEA0183 << sentence3;
76 if (!m_NMEA0183.PreParse())
return false;
77 if (!m_NMEA0183.Parse())
return false;
79 if (m_NMEA0183.Rmc.IsDataValid == NTrue) {
81 if (ParsePosition(m_NMEA0183.Rmc.Position, tlat, tlon)) {
82 temp_data.gLat = tlat;
83 temp_data.gLon = tlon;
87 if (!std::isnan(m_NMEA0183.Rmc.SpeedOverGroundKnots)) {
88 temp_data.gSog = m_NMEA0183.Rmc.SpeedOverGroundKnots;
90 if (!std::isnan(temp_data.gSog) && (temp_data.gSog > 0.05)) {
91 temp_data.gCog = m_NMEA0183.Rmc.TrackMadeGoodDegreesTrue;
99 if ((!std::isnan(m_NMEA0183.Rmc.MagneticVariation)) &&
100 0.0 != m_NMEA0183.Rmc.MagneticVariation) {
101 if (m_NMEA0183.Rmc.MagneticVariationDirection == East)
102 temp_data.gVar = m_NMEA0183.Rmc.MagneticVariation;
103 else if (m_NMEA0183.Rmc.MagneticVariationDirection == West)
104 temp_data.gVar = -m_NMEA0183.Rmc.MagneticVariation;
109 gRmcTime = m_NMEA0183.Rmc.UTCTime;
110 gRmcDate = m_NMEA0183.Rmc.Date;
117bool CommDecoder::DecodeHDM(std::string s,
NavData& temp_data) {
118 wxString sentence(s.c_str());
120 m_NMEA0183 << sentence3;
122 if (!m_NMEA0183.PreParse())
return false;
123 if (!m_NMEA0183.Parse())
return false;
125 temp_data.gHdm = m_NMEA0183.Hdm.DegreesMagnetic;
130bool CommDecoder::DecodeTHS(std::string s,
NavData& temp_data) {
131 wxString sentence(s.c_str());
133 m_NMEA0183 << sentence3;
135 if (!m_NMEA0183.PreParse())
return false;
136 if (!m_NMEA0183.Parse())
return false;
139 if (!(m_NMEA0183.Ths.ModeInd ==
"A"))
return false;
140 temp_data.gHdt = m_NMEA0183.Ths.TrueHeading;
145bool CommDecoder::DecodeHDT(std::string s,
NavData& temp_data) {
146 wxString sentence(s.c_str());
148 m_NMEA0183 << sentence3;
150 if (!m_NMEA0183.PreParse())
return false;
151 if (!m_NMEA0183.Parse())
return false;
153 temp_data.gHdt = m_NMEA0183.Hdt.DegreesTrue;
158bool CommDecoder::DecodeHDG(std::string s,
NavData& temp_data) {
159 wxString sentence(s.c_str());
161 m_NMEA0183 << sentence3;
163 if (!m_NMEA0183.PreParse())
return false;
164 if (!m_NMEA0183.Parse())
return false;
166 temp_data.gHdm = m_NMEA0183.Hdg.MagneticSensorHeadingDegrees;
171 if ((!std::isnan(m_NMEA0183.Hdg.MagneticVariationDegrees)) &&
172 0.0 != m_NMEA0183.Hdg.MagneticVariationDegrees) {
173 if (m_NMEA0183.Hdg.MagneticVariationDirection == East)
174 temp_data.gVar = m_NMEA0183.Hdg.MagneticVariationDegrees;
175 else if (m_NMEA0183.Hdg.MagneticVariationDirection == West)
176 temp_data.gVar = -m_NMEA0183.Hdg.MagneticVariationDegrees;
184bool CommDecoder::DecodeHVD(std::string s,
NavData& temp_data) {
185 wxString sentence(s.c_str());
187 m_NMEA0183 << sentence3;
189 if (!m_NMEA0183.PreParse())
return false;
190 if (!m_NMEA0183.Parse())
return false;
195 if ((!std::isnan(m_NMEA0183.Hvd.MagneticVariationDegrees)) &&
196 0.0 != m_NMEA0183.Hvd.MagneticVariationDegrees) {
197 if (m_NMEA0183.Hvd.MagneticVariationDirection == East)
198 temp_data.gVar = m_NMEA0183.Hvd.MagneticVariationDegrees;
199 else if (m_NMEA0183.Hvd.MagneticVariationDirection == West)
200 temp_data.gVar = -m_NMEA0183.Hvd.MagneticVariationDegrees;
208bool CommDecoder::DecodeVTG(std::string s,
NavData& temp_data) {
209 wxString sentence(s.c_str());
211 m_NMEA0183 << sentence3;
213 if (!m_NMEA0183.PreParse())
return false;
214 if (!m_NMEA0183.Parse())
return false;
216 if (!std::isnan(m_NMEA0183.Vtg.SpeedKnots))
217 temp_data.gSog = m_NMEA0183.Vtg.SpeedKnots;
219 if (!std::isnan(m_NMEA0183.Vtg.SpeedKnots) &&
220 !std::isnan(m_NMEA0183.Vtg.TrackDegreesTrue)) {
221 temp_data.gCog = m_NMEA0183.Vtg.TrackDegreesTrue;
226 if (!std::isnan(m_NMEA0183.Vtg.SpeedKnots) &&
227 !std::isnan(m_NMEA0183.Vtg.TrackDegreesMagnetic)) {
229 if (std::isnan(
gVar) && (g_UserVar != 0.0))
gVar = g_UserVar;
231 double cogt = m_NMEA0183.Vtg.TrackDegreesMagnetic +
gVar;
232 if (!std::isnan(cogt)) {
235 else if (cogt >= 360)
237 temp_data.gCog = cogt;
243bool CommDecoder::DecodeGLL(std::string s,
NavData& temp_data) {
244 wxString sentence(s.c_str());
246 m_NMEA0183 << sentence3;
248 if (!m_NMEA0183.PreParse())
return false;
249 if (!m_NMEA0183.Parse())
return false;
251 if (m_NMEA0183.Gll.IsDataValid == NTrue) {
253 if (ParsePosition(m_NMEA0183.Gll.Position, tlat, tlon)) {
254 temp_data.gLat = tlat;
255 temp_data.gLon = tlon;
264bool CommDecoder::DecodeGSV(std::string s,
NavData& temp_data) {
265 wxString sentence(s.c_str());
267 m_NMEA0183 << sentence3;
269 if (!m_NMEA0183.PreParse())
return false;
270 if (!m_NMEA0183.Parse())
return false;
272 if (m_NMEA0183.Gsv.MessageNumber == 1)
273 temp_data.n_satellites = m_NMEA0183.Gsv.SatsInView;
278bool CommDecoder::DecodeGGA(std::string s,
NavData& temp_data) {
279 wxString sentence(s.c_str());
281 m_NMEA0183 << sentence3;
283 if (!m_NMEA0183.PreParse())
return false;
284 if (!m_NMEA0183.Parse())
return false;
286 if (m_NMEA0183.Gga.GPSQuality > 0) {
288 if (ParsePosition(m_NMEA0183.Gga.Position, tlat, tlon)) {
289 temp_data.gLat = tlat;
290 temp_data.gLon = tlon;
294 temp_data.n_satellites = m_NMEA0183.Gga.NumberOfSatellitesInUse;
306bool CommDecoder::DecodePGN129026(std::vector<unsigned char> v,
309 tN2kHeadingReference ref;
312 if (ParseN2kPGN129026(v, SID, ref, COG, SOG)) {
313 temp_data.gCog = COG;
314 temp_data.gSog = SOG;
322bool CommDecoder::DecodePGN129029(std::vector<unsigned char> v,
325 uint16_t DaysSince1970;
326 double SecondsSinceMidnight;
327 double Latitude, Longitude, Altitude;
328 tN2kGNSStype GNSStype;
329 tN2kGNSSmethod GNSSmethod;
330 unsigned char nSatellites;
331 double HDOP, PDOP, GeoidalSeparation;
332 unsigned char nReferenceStations;
333 tN2kGNSStype ReferenceStationType;
334 uint16_t ReferenceSationID;
335 double AgeOfCorrection;
337 if (ParseN2kPGN129029(v, SID, DaysSince1970, SecondsSinceMidnight, Latitude,
338 Longitude, Altitude, GNSStype, GNSSmethod, nSatellites,
339 HDOP, PDOP, GeoidalSeparation, nReferenceStations,
340 ReferenceStationType, ReferenceSationID,
342 temp_data.gLat = Latitude;
343 temp_data.gLon = Longitude;
350 if ((GNSSmethod == N2kGNSSm_GNSSfix) || (GNSSmethod == N2kGNSSm_DGNSS) ||
351 (GNSSmethod == N2kGNSSm_PreciseGNSS)) {
352 if (nSatellites > 0) temp_data.n_satellites = nSatellites;
361bool CommDecoder::DecodePGN127250(std::vector<unsigned char> v,
364 double Heading, Deviation, Variation;
365 tN2kHeadingReference ref;
367 if (ParseN2kPGN127250(v, SID, Heading, Deviation, Variation, ref)) {
368 temp_data.gHdt = N2kDoubleNA;
369 temp_data.gHdm = N2kDoubleNA;
370 if (ref == tN2kHeadingReference::N2khr_true)
371 temp_data.gHdt = Heading;
372 else if (ref == tN2kHeadingReference::N2khr_magnetic)
373 temp_data.gHdm = Heading;
375 temp_data.gVar = Variation;
383bool CommDecoder::DecodePGN127258(std::vector<unsigned char> v,
386 tN2kMagneticVariation Source;
387 uint16_t DaysSince1970;
389 tN2kHeadingReference ref;
391 if (ParseN2kPGN127258(v, SID, Source, DaysSince1970, Variation)) {
392 temp_data.gVar = Variation;
401bool CommDecoder::DecodePGN129025(std::vector<unsigned char> v,
403 double Latitude, Longitude;
405 if (ParseN2kPGN129025(v, Latitude, Longitude)) {
406 temp_data.gLat = Latitude;
407 temp_data.gLon = Longitude;
414bool CommDecoder::DecodePGN129540(std::vector<unsigned char> v,
419 tN2kRangeResidualMode Mode;
421 if (ParseN2kPGN129540(v, SID, Mode, NumberOfSVs)) {
422 temp_data.n_satellites = NumberOfSVs;
430bool CommDecoder::DecodeSignalK(std::string s,
NavData& temp_data) {
431 rapidjson::Document root;
434 if (root.HasParseError())
return false;
436 if (root.HasMember(
"updates") && root[
"updates"].IsArray()) {
437 for (rapidjson::Value::ConstValueIterator itr = root[
"updates"].Begin();
438 itr != root[
"updates"].End(); ++itr) {
439 handleUpdate(*itr, temp_data);
446void CommDecoder::handleUpdate(
const rapidjson::Value& update,
448 wxString sfixtime =
"";
450 if (update.HasMember(
"timestamp")) {
451 sfixtime = update[
"timestamp"].GetString();
453 if (update.HasMember(
"source") && update[
"source"].HasMember(
"src")) {
454 src_string = update[
"source"][
"src"].GetString();
457 if (update.HasMember(
"values") && update[
"values"].IsArray()) {
458 for (rapidjson::Value::ConstValueIterator itr = update[
"values"].Begin();
459 itr != update[
"values"].End(); ++itr) {
460 updateItem(*itr, sfixtime, temp_data);
465void CommDecoder::updateItem(
const rapidjson::Value& item, wxString& sfixtime,
467 bool bposValid =
false;
468 if (item.HasMember(
"path") && item.HasMember(
"value")) {
469 const wxString& update_path = item[
"path"].GetString();
471 if (update_path ==
"navigation.gnss.methodQuality") {
473 if (src_string.size()) {
474 if (item[
"value"] ==
"no GPS") {
475 GNSS_quality_map[src_string] = 0;
477 GNSS_quality_map[src_string] = 1;
482 if (update_path ==
"navigation.position" && !item[
"value"].IsNull()) {
483 bposValid = updateNavigationPosition(item[
"value"], sfixtime, temp_data);
487 if (GNSS_quality_map.find(src_string) != GNSS_quality_map.end()) {
488 if (GNSS_quality_map[src_string] == 0) {
489 temp_data.gLat = NAN;
493 }
else if (update_path ==
"navigation.speedOverGround" &&
494 !item[
"value"].IsNull()) {
495 updateNavigationSpeedOverGround(item[
"value"], sfixtime, temp_data);
499 if (GNSS_quality_map.find(src_string) != GNSS_quality_map.end()) {
500 if (GNSS_quality_map[src_string] == 0) {
505 }
else if (update_path ==
"navigation.courseOverGroundTrue" &&
506 !item[
"value"].IsNull()) {
507 updateNavigationCourseOverGround(item[
"value"], sfixtime, temp_data);
508 }
else if (update_path ==
"navigation.courseOverGroundMagnetic") {
509 }
else if (update_path ==
510 "navigation.gnss.satellites")
512 updateGnssSatellites(item[
"value"], sfixtime, temp_data);
513 }
else if (update_path ==
514 "navigation.gnss.satellitesInView")
516 updateGnssSatellites(item[
"value"], sfixtime, temp_data);
517 }
else if (update_path ==
"navigation.headingTrue") {
518 if (!item[
"value"].IsNull())
519 updateHeadingTrue(item[
"value"], sfixtime, temp_data);
520 }
else if (update_path ==
"navigation.headingMagnetic") {
521 if (!item[
"value"].IsNull())
522 updateHeadingMagnetic(item[
"value"], sfixtime, temp_data);
523 }
else if (update_path ==
"navigation.magneticVariation") {
524 if (!item[
"value"].IsNull())
525 updateMagneticVariance(item[
"value"], sfixtime, temp_data);
533bool CommDecoder::updateNavigationPosition(
const rapidjson::Value& value,
534 const wxString& sfixtime,
536 if ((value.HasMember(
"latitude") && value[
"latitude"].IsDouble()) &&
537 (value.HasMember(
"longitude") && value[
"longitude"].IsDouble())) {
539 temp_data.gLat = value[
"latitude"].GetDouble();
540 temp_data.gLon = value[
"longitude"].GetDouble();
547void CommDecoder::updateNavigationSpeedOverGround(
const rapidjson::Value& value,
548 const wxString& sfixtime,
550 double sog_ms = value.GetDouble();
551 double sog_knot = sog_ms * 1.9438444924406;
553 temp_data.gSog = sog_knot;
556void CommDecoder::updateNavigationCourseOverGround(
557 const rapidjson::Value& value,
const wxString& sfixtime,
559 double cog_rad = value.GetDouble();
560 double cog_deg = GEODESIC_RAD2DEG(cog_rad);
562 temp_data.gCog = cog_deg;
565void CommDecoder::updateGnssSatellites(
const rapidjson::Value& value,
566 const wxString& sfixtime,
569 if (value.GetInt() > 0) {
570 temp_data.n_satellites = value.GetInt();
572 }
else if ((value.HasMember(
"count") && value[
"count"].IsInt())) {
573 temp_data.n_satellites = value[
"count"].GetInt();
576 if (GNSS_quality_map.find(src_string) != GNSS_quality_map.end()) {
577 if (GNSS_quality_map[src_string] == 0) {
578 temp_data.n_satellites = 0;
583void CommDecoder::updateHeadingTrue(
const rapidjson::Value& value,
584 const wxString& sfixtime,
586 temp_data.gHdt = GEODESIC_RAD2DEG(value.GetDouble());
589void CommDecoder::updateHeadingMagnetic(
const rapidjson::Value& value,
590 const wxString& sfixtime,
592 temp_data.gHdm = GEODESIC_RAD2DEG(value.GetDouble());
595void CommDecoder::updateMagneticVariance(
const rapidjson::Value& value,
596 const wxString& sfixtime,
598 temp_data.gVar = GEODESIC_RAD2DEG(value.GetDouble());
Incoming messages decoding support.
wxString ProcessNMEA4Tags(const wxString &msg)
Strip NMEA V4 tag blocks from NMEA0183 message.
Variables maintained by comm stack, read-only access for others.
double gVar
Magnetic variation in degrees.
Position, course, speed, etc.