36#include "rapidjson/document.h"
38#include "model/comm_decoder.h"
39#include "model/comm_util.h"
40#include "model/comm_vars.h"
41#include "model/geodesic.h"
42#include "model/own_ship.h"
44bool CommDecoder::ParsePosition(
const LATLONG&
Position,
double& lat,
47 double llt =
Position.Latitude.Latitude;
49 if (!std::isnan(llt)) {
50 int lat_deg_int = (int)(llt / 100);
51 double lat_deg = lat_deg_int;
52 double lat_min = llt - (lat_deg * 100);
54 lat = lat_deg + (lat_min / 60.);
55 if (
Position.Latitude.Northing == South) lat = -lat;
59 double lln =
Position.Longitude.Longitude;
60 if (!std::isnan(lln)) {
61 int lon_deg_int = (int)(lln / 100);
62 double lon_deg = lon_deg_int;
63 double lon_min = lln - (lon_deg * 100);
65 lon = lon_deg + (lon_min / 60.);
66 if (
Position.Longitude.Easting == West) lon = -lon;
73bool CommDecoder::DecodeRMC(std::string s,
NavData& temp_data) {
74 wxString sentence(s.c_str());
75 wxString sentence3 = ProcessNMEA4Tags(sentence);
76 m_NMEA0183 << sentence3;
78 if (!m_NMEA0183.PreParse())
return false;
79 if (!m_NMEA0183.Parse())
return false;
81 if (m_NMEA0183.Rmc.IsDataValid == NTrue) {
83 if (ParsePosition(m_NMEA0183.Rmc.Position, tlat, tlon)) {
84 temp_data.gLat = tlat;
85 temp_data.gLon = tlon;
91 if (!std::isnan(m_NMEA0183.Rmc.SpeedOverGroundKnots)) {
92 temp_data.gSog = m_NMEA0183.Rmc.SpeedOverGroundKnots;
94 if (!std::isnan(temp_data.gSog) && (temp_data.gSog > 0.05)) {
95 temp_data.gCog = m_NMEA0183.Rmc.TrackMadeGoodDegreesTrue;
103 if ((!std::isnan(m_NMEA0183.Rmc.MagneticVariation)) &&
104 0.0 != m_NMEA0183.Rmc.MagneticVariation) {
105 if (m_NMEA0183.Rmc.MagneticVariationDirection == East)
106 temp_data.gVar = m_NMEA0183.Rmc.MagneticVariation;
107 else if (m_NMEA0183.Rmc.MagneticVariationDirection == West)
108 temp_data.gVar = -m_NMEA0183.Rmc.MagneticVariation;
113 gRmcTime = m_NMEA0183.Rmc.UTCTime;
114 gRmcDate = m_NMEA0183.Rmc.Date;
121bool CommDecoder::DecodeHDM(std::string s,
NavData& temp_data) {
122 wxString sentence(s.c_str());
123 wxString sentence3 = ProcessNMEA4Tags(sentence);
124 m_NMEA0183 << sentence3;
126 if (!m_NMEA0183.PreParse())
return false;
127 if (!m_NMEA0183.Parse())
return false;
129 temp_data.gHdm = m_NMEA0183.Hdm.DegreesMagnetic;
134bool CommDecoder::DecodeTHS(std::string s,
NavData& temp_data) {
135 wxString sentence(s.c_str());
136 wxString sentence3 = ProcessNMEA4Tags(sentence);
137 m_NMEA0183 << sentence3;
139 if (!m_NMEA0183.PreParse())
return false;
140 if (!m_NMEA0183.Parse())
return false;
143 if (!(m_NMEA0183.Ths.ModeInd ==
"A"))
return false;
144 temp_data.gHdt = m_NMEA0183.Ths.TrueHeading;
149bool CommDecoder::DecodeHDT(std::string s,
NavData& temp_data) {
150 wxString sentence(s.c_str());
151 wxString sentence3 = ProcessNMEA4Tags(sentence);
152 m_NMEA0183 << sentence3;
154 if (!m_NMEA0183.PreParse())
return false;
155 if (!m_NMEA0183.Parse())
return false;
157 temp_data.gHdt = m_NMEA0183.Hdt.DegreesTrue;
162bool CommDecoder::DecodeHDG(std::string s,
NavData& temp_data) {
163 wxString sentence(s.c_str());
164 wxString sentence3 = ProcessNMEA4Tags(sentence);
165 m_NMEA0183 << sentence3;
167 if (!m_NMEA0183.PreParse())
return false;
168 if (!m_NMEA0183.Parse())
return false;
170 temp_data.gHdm = m_NMEA0183.Hdg.MagneticSensorHeadingDegrees;
175 if ((!std::isnan(m_NMEA0183.Hdg.MagneticVariationDegrees)) &&
176 0.0 != m_NMEA0183.Hdg.MagneticVariationDegrees) {
177 if (m_NMEA0183.Hdg.MagneticVariationDirection == East)
178 temp_data.gVar = m_NMEA0183.Hdg.MagneticVariationDegrees;
179 else if (m_NMEA0183.Hdg.MagneticVariationDirection == West)
180 temp_data.gVar = -m_NMEA0183.Hdg.MagneticVariationDegrees;
188bool CommDecoder::DecodeVTG(std::string s,
NavData& temp_data) {
189 wxString sentence(s.c_str());
190 wxString sentence3 = ProcessNMEA4Tags(sentence);
191 m_NMEA0183 << sentence3;
193 if (!m_NMEA0183.PreParse())
return false;
194 if (!m_NMEA0183.Parse())
return false;
198 if (!std::isnan(m_NMEA0183.Vtg.SpeedKnots))
199 temp_data.gSog = m_NMEA0183.Vtg.SpeedKnots;
201 if (!std::isnan(m_NMEA0183.Vtg.SpeedKnots) &&
202 !std::isnan(m_NMEA0183.Vtg.TrackDegreesTrue)) {
203 temp_data.gCog = m_NMEA0183.Vtg.TrackDegreesTrue;
208 if (!std::isnan(m_NMEA0183.Vtg.SpeedKnots) &&
209 !std::isnan(m_NMEA0183.Vtg.TrackDegreesMagnetic)) {
211 if (std::isnan(gVar) && (g_UserVar != 0.0)) gVar = g_UserVar;
213 double cogt = m_NMEA0183.Vtg.TrackDegreesMagnetic + gVar;
214 if (!std::isnan(cogt)) {
217 else if (cogt >= 360)
219 temp_data.gCog = cogt;
225bool CommDecoder::DecodeGLL(std::string s,
NavData& temp_data) {
226 wxString sentence(s.c_str());
227 wxString sentence3 = ProcessNMEA4Tags(sentence);
228 m_NMEA0183 << sentence3;
230 if (!m_NMEA0183.PreParse())
return false;
231 if (!m_NMEA0183.Parse())
return false;
233 if (m_NMEA0183.Gll.IsDataValid == NTrue) {
235 if (ParsePosition(m_NMEA0183.Gll.Position, tlat, tlon)) {
236 temp_data.gLat = tlat;
237 temp_data.gLon = tlon;
246bool CommDecoder::DecodeGSV(std::string s,
NavData& temp_data) {
247 wxString sentence(s.c_str());
248 wxString sentence3 = ProcessNMEA4Tags(sentence);
249 m_NMEA0183 << sentence3;
251 if (!m_NMEA0183.PreParse())
return false;
252 if (!m_NMEA0183.Parse())
return false;
254 if (m_NMEA0183.Gsv.MessageNumber == 1)
255 temp_data.n_satellites = m_NMEA0183.Gsv.SatsInView;
260bool CommDecoder::DecodeGGA(std::string s,
NavData& temp_data) {
261 wxString sentence(s.c_str());
262 wxString sentence3 = ProcessNMEA4Tags(sentence);
263 m_NMEA0183 << sentence3;
265 if (!m_NMEA0183.PreParse())
return false;
266 if (!m_NMEA0183.Parse())
return false;
268 if (m_NMEA0183.Gga.GPSQuality > 0) {
270 if (ParsePosition(m_NMEA0183.Gga.Position, tlat, tlon)) {
271 temp_data.gLat = tlat;
272 temp_data.gLon = tlon;
276 temp_data.n_satellites = m_NMEA0183.Gga.NumberOfSatellitesInUse;
288bool CommDecoder::DecodePGN129026(std::vector<unsigned char> v,
291 tN2kHeadingReference ref;
294 if (ParseN2kPGN129026(v, SID, ref, COG, SOG)) {
295 temp_data.gCog = COG;
296 temp_data.gSog = SOG;
304bool CommDecoder::DecodePGN129029(std::vector<unsigned char> v,
307 uint16_t DaysSince1970;
308 double SecondsSinceMidnight;
309 double Latitude, Longitude, Altitude;
310 tN2kGNSStype GNSStype;
311 tN2kGNSSmethod GNSSmethod;
312 unsigned char nSatellites;
313 double HDOP, PDOP, GeoidalSeparation;
314 unsigned char nReferenceStations;
315 tN2kGNSStype ReferenceStationType;
316 uint16_t ReferenceSationID;
317 double AgeOfCorrection;
319 if (ParseN2kPGN129029(v, SID, DaysSince1970, SecondsSinceMidnight, Latitude,
320 Longitude, Altitude, GNSStype, GNSSmethod, nSatellites,
321 HDOP, PDOP, GeoidalSeparation, nReferenceStations,
322 ReferenceStationType, ReferenceSationID,
324 temp_data.gLat = Latitude;
325 temp_data.gLon = Longitude;
332 if ((GNSSmethod == N2kGNSSm_GNSSfix) || (GNSSmethod == N2kGNSSm_DGNSS) ||
333 (GNSSmethod == N2kGNSSm_PreciseGNSS)) {
334 if (nSatellites > 0) temp_data.n_satellites = nSatellites;
343bool CommDecoder::DecodePGN127250(std::vector<unsigned char> v,
346 double Heading, Deviation, Variation;
347 tN2kHeadingReference ref;
349 if (ParseN2kPGN127250(v, SID, Heading, Deviation, Variation, ref)) {
350 temp_data.gHdt = N2kDoubleNA;
351 temp_data.gHdm = N2kDoubleNA;
352 if (ref == tN2kHeadingReference::N2khr_true)
353 temp_data.gHdt = Heading;
354 else if (ref == tN2kHeadingReference::N2khr_magnetic)
355 temp_data.gHdm = Heading;
357 temp_data.gVar = Variation;
365bool CommDecoder::DecodePGN129025(std::vector<unsigned char> v,
367 double Latitude, Longitude;
369 if (ParseN2kPGN129025(v, Latitude, Longitude)) {
370 temp_data.gLat = Latitude;
371 temp_data.gLon = Longitude;
378bool CommDecoder::DecodePGN129540(std::vector<unsigned char> v,
383 tN2kRangeResidualMode Mode;
385 if (ParseN2kPGN129540(v, SID, Mode, NumberOfSVs)) {
386 temp_data.n_satellites = NumberOfSVs;
394bool CommDecoder::DecodeSignalK(std::string s,
NavData& temp_data) {
395 rapidjson::Document root;
398 if (root.HasParseError())
return false;
400 if (root.HasMember(
"updates") && root[
"updates"].IsArray()) {
401 for (rapidjson::Value::ConstValueIterator itr = root[
"updates"].Begin();
402 itr != root[
"updates"].End(); ++itr) {
403 handleUpdate(*itr, temp_data);
410void CommDecoder::handleUpdate(
const rapidjson::Value& update,
412 wxString sfixtime =
"";
414 if (update.HasMember(
"timestamp")) {
415 sfixtime = update[
"timestamp"].GetString();
417 if (update.HasMember(
"source") && update[
"source"].HasMember(
"src")) {
418 src_string = update[
"source"][
"src"].GetString();
421 if (update.HasMember(
"values") && update[
"values"].IsArray()) {
422 for (rapidjson::Value::ConstValueIterator itr = update[
"values"].Begin();
423 itr != update[
"values"].End(); ++itr) {
424 updateItem(*itr, sfixtime, temp_data);
429void CommDecoder::updateItem(
const rapidjson::Value& item, wxString& sfixtime,
431 bool bposValid =
false;
432 if (item.HasMember(
"path") && item.HasMember(
"value")) {
433 const wxString& update_path = item[
"path"].GetString();
435 if (update_path == _T(
"navigation.gnss.methodQuality")) {
437 if (src_string.size()) {
438 if (item[
"value"] ==
"no GPS") {
439 GNSS_quality_map[src_string] = 0;
441 GNSS_quality_map[src_string] = 1;
446 if (update_path == _T(
"navigation.position") && !item[
"value"].IsNull()) {
447 bposValid = updateNavigationPosition(item[
"value"], sfixtime, temp_data);
451 if (GNSS_quality_map.find(src_string) != GNSS_quality_map.end()) {
452 if (GNSS_quality_map[src_string] == 0) {
453 temp_data.gLat = NAN;
457 }
else if (update_path == _T(
"navigation.speedOverGround") &&
458 !item[
"value"].IsNull()) {
459 updateNavigationSpeedOverGround(item[
"value"], sfixtime, temp_data);
463 if (GNSS_quality_map.find(src_string) != GNSS_quality_map.end()) {
464 if (GNSS_quality_map[src_string] == 0) {
469 }
else if (update_path == _T(
"navigation.courseOverGroundTrue") &&
470 !item[
"value"].IsNull()) {
471 updateNavigationCourseOverGround(item[
"value"], sfixtime, temp_data);
472 }
else if (update_path == _T(
"navigation.courseOverGroundMagnetic")) {
473 }
else if (update_path ==
474 _T(
"navigation.gnss.satellites"))
476 updateGnssSatellites(item[
"value"], sfixtime, temp_data);
477 }
else if (update_path ==
478 _T(
"navigation.gnss.satellitesInView"))
480 updateGnssSatellites(item[
"value"], sfixtime, temp_data);
481 }
else if (update_path == _T(
"navigation.headingTrue")) {
482 if (!item[
"value"].IsNull())
483 updateHeadingTrue(item[
"value"], sfixtime, temp_data);
484 }
else if (update_path == _T(
"navigation.headingMagnetic")) {
485 if (!item[
"value"].IsNull())
486 updateHeadingMagnetic(item[
"value"], sfixtime, temp_data);
487 }
else if (update_path == _T(
"navigation.magneticVariation")) {
488 if (!item[
"value"].IsNull())
489 updateMagneticVariance(item[
"value"], sfixtime, temp_data);
497bool CommDecoder::updateNavigationPosition(
const rapidjson::Value& value,
498 const wxString& sfixtime,
500 if ((value.HasMember(
"latitude") && value[
"latitude"].IsDouble()) &&
501 (value.HasMember(
"longitude") && value[
"longitude"].IsDouble())) {
503 temp_data.gLat = value[
"latitude"].GetDouble();
504 temp_data.gLon = value[
"longitude"].GetDouble();
511void CommDecoder::updateNavigationSpeedOverGround(
const rapidjson::Value& value,
512 const wxString& sfixtime,
514 double sog_ms = value.GetDouble();
515 double sog_knot = sog_ms * 1.9438444924406;
517 temp_data.gSog = sog_knot;
520void CommDecoder::updateNavigationCourseOverGround(
521 const rapidjson::Value& value,
const wxString& sfixtime,
523 double cog_rad = value.GetDouble();
524 double cog_deg = GEODESIC_RAD2DEG(cog_rad);
526 temp_data.gCog = cog_deg;
529void CommDecoder::updateGnssSatellites(
const rapidjson::Value& value,
530 const wxString& sfixtime,
533 if (value.GetInt() > 0) {
534 temp_data.n_satellites = value.GetInt();
536 }
else if ((value.HasMember(
"count") && value[
"count"].IsInt())) {
537 temp_data.n_satellites = value[
"count"].GetInt();
540 if (GNSS_quality_map.find(src_string) != GNSS_quality_map.end()) {
541 if (GNSS_quality_map[src_string] == 0) {
542 temp_data.n_satellites = 0;
547void CommDecoder::updateHeadingTrue(
const rapidjson::Value& value,
548 const wxString& sfixtime,
550 temp_data.gHdt = GEODESIC_RAD2DEG(value.GetDouble());
553void CommDecoder::updateHeadingMagnetic(
const rapidjson::Value& value,
554 const wxString& sfixtime,
556 temp_data.gHdm = GEODESIC_RAD2DEG(value.GetDouble());
559void CommDecoder::updateMagneticVariance(
const rapidjson::Value& value,
560 const wxString& sfixtime,
562 temp_data.gVar = GEODESIC_RAD2DEG(value.GetDouble());