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;
 
   89      if (!std::isnan(m_NMEA0183.Rmc.SpeedOverGroundKnots)) {
 
   90        temp_data.gSog = m_NMEA0183.Rmc.SpeedOverGroundKnots;
 
   92      if (!std::isnan(temp_data.gSog) && (temp_data.gSog > 0.05)) {
 
   93        temp_data.gCog = m_NMEA0183.Rmc.TrackMadeGoodDegreesTrue;
 
  101    if ((!std::isnan(m_NMEA0183.Rmc.MagneticVariation)) &&
 
  102        0.0 != m_NMEA0183.Rmc.MagneticVariation) {
 
  103      if (m_NMEA0183.Rmc.MagneticVariationDirection == East)
 
  104        temp_data.gVar = m_NMEA0183.Rmc.MagneticVariation;
 
  105      else if (m_NMEA0183.Rmc.MagneticVariationDirection == West)
 
  106        temp_data.gVar = -m_NMEA0183.Rmc.MagneticVariation;
 
  111    gRmcTime = m_NMEA0183.Rmc.UTCTime;
 
  112    gRmcDate = m_NMEA0183.Rmc.Date;
 
  119bool CommDecoder::DecodeHDM(std::string s, 
NavData& temp_data) {
 
  120  wxString sentence(s.c_str());
 
  122  m_NMEA0183 << sentence3;
 
  124  if (!m_NMEA0183.PreParse()) 
return false;
 
  125  if (!m_NMEA0183.Parse()) 
return false;
 
  127  temp_data.gHdm = m_NMEA0183.Hdm.DegreesMagnetic;
 
  132bool CommDecoder::DecodeTHS(std::string s, 
NavData& temp_data) {
 
  133  wxString sentence(s.c_str());
 
  135  m_NMEA0183 << sentence3;
 
  137  if (!m_NMEA0183.PreParse()) 
return false;
 
  138  if (!m_NMEA0183.Parse()) 
return false;
 
  141  if (!(m_NMEA0183.Ths.ModeInd == 
"A")) 
return false;
 
  142  temp_data.gHdt = m_NMEA0183.Ths.TrueHeading;
 
  147bool CommDecoder::DecodeHDT(std::string s, 
NavData& temp_data) {
 
  148  wxString sentence(s.c_str());
 
  150  m_NMEA0183 << sentence3;
 
  152  if (!m_NMEA0183.PreParse()) 
return false;
 
  153  if (!m_NMEA0183.Parse()) 
return false;
 
  155  temp_data.gHdt = m_NMEA0183.Hdt.DegreesTrue;
 
  160bool CommDecoder::DecodeHDG(std::string s, 
NavData& temp_data) {
 
  161  wxString sentence(s.c_str());
 
  163  m_NMEA0183 << sentence3;
 
  165  if (!m_NMEA0183.PreParse()) 
return false;
 
  166  if (!m_NMEA0183.Parse()) 
return false;
 
  168  temp_data.gHdm = m_NMEA0183.Hdg.MagneticSensorHeadingDegrees;
 
  173  if ((!std::isnan(m_NMEA0183.Hdg.MagneticVariationDegrees)) &&
 
  174      0.0 != m_NMEA0183.Hdg.MagneticVariationDegrees) {
 
  175    if (m_NMEA0183.Hdg.MagneticVariationDirection == East)
 
  176      temp_data.gVar = m_NMEA0183.Hdg.MagneticVariationDegrees;
 
  177    else if (m_NMEA0183.Hdg.MagneticVariationDirection == West)
 
  178      temp_data.gVar = -m_NMEA0183.Hdg.MagneticVariationDegrees;
 
  186bool CommDecoder::DecodeVTG(std::string s, 
NavData& temp_data) {
 
  187  wxString sentence(s.c_str());
 
  189  m_NMEA0183 << sentence3;
 
  191  if (!m_NMEA0183.PreParse()) 
return false;
 
  192  if (!m_NMEA0183.Parse()) 
return false;
 
  196  if (!std::isnan(m_NMEA0183.Vtg.SpeedKnots))
 
  197    temp_data.gSog = m_NMEA0183.Vtg.SpeedKnots;
 
  199  if (!std::isnan(m_NMEA0183.Vtg.SpeedKnots) &&
 
  200      !std::isnan(m_NMEA0183.Vtg.TrackDegreesTrue)) {
 
  201    temp_data.gCog = m_NMEA0183.Vtg.TrackDegreesTrue;
 
  206  if (!std::isnan(m_NMEA0183.Vtg.SpeedKnots) &&
 
  207      !std::isnan(m_NMEA0183.Vtg.TrackDegreesMagnetic)) {
 
  209    if (std::isnan(
gVar) && (g_UserVar != 0.0)) 
gVar = g_UserVar;
 
  211    double cogt = m_NMEA0183.Vtg.TrackDegreesMagnetic + 
gVar;
 
  212    if (!std::isnan(cogt)) {
 
  215      else if (cogt >= 360)
 
  217      temp_data.gCog = cogt;
 
  223bool CommDecoder::DecodeGLL(std::string s, 
NavData& temp_data) {
 
  224  wxString sentence(s.c_str());
 
  226  m_NMEA0183 << sentence3;
 
  228  if (!m_NMEA0183.PreParse()) 
return false;
 
  229  if (!m_NMEA0183.Parse()) 
return false;
 
  231  if (m_NMEA0183.Gll.IsDataValid == NTrue) {
 
  233    if (ParsePosition(m_NMEA0183.Gll.Position, tlat, tlon)) {
 
  234      temp_data.gLat = tlat;
 
  235      temp_data.gLon = tlon;
 
  244bool CommDecoder::DecodeGSV(std::string s, 
NavData& temp_data) {
 
  245  wxString sentence(s.c_str());
 
  247  m_NMEA0183 << sentence3;
 
  249  if (!m_NMEA0183.PreParse()) 
return false;
 
  250  if (!m_NMEA0183.Parse()) 
return false;
 
  252  if (m_NMEA0183.Gsv.MessageNumber == 1)
 
  253    temp_data.n_satellites = m_NMEA0183.Gsv.SatsInView;
 
  258bool CommDecoder::DecodeGGA(std::string s, 
NavData& temp_data) {
 
  259  wxString sentence(s.c_str());
 
  261  m_NMEA0183 << sentence3;
 
  263  if (!m_NMEA0183.PreParse()) 
return false;
 
  264  if (!m_NMEA0183.Parse()) 
return false;
 
  266  if (m_NMEA0183.Gga.GPSQuality > 0) {
 
  268    if (ParsePosition(m_NMEA0183.Gga.Position, tlat, tlon)) {
 
  269      temp_data.gLat = tlat;
 
  270      temp_data.gLon = tlon;
 
  274    temp_data.n_satellites = m_NMEA0183.Gga.NumberOfSatellitesInUse;
 
  286bool CommDecoder::DecodePGN129026(std::vector<unsigned char> v,
 
  289  tN2kHeadingReference ref;
 
  292  if (ParseN2kPGN129026(v, SID, ref, COG, SOG)) {
 
  293    temp_data.gCog = COG;
 
  294    temp_data.gSog = SOG;
 
  302bool CommDecoder::DecodePGN129029(std::vector<unsigned char> v,
 
  305  uint16_t DaysSince1970;
 
  306  double SecondsSinceMidnight;
 
  307  double Latitude, Longitude, Altitude;
 
  308  tN2kGNSStype GNSStype;
 
  309  tN2kGNSSmethod GNSSmethod;
 
  310  unsigned char nSatellites;
 
  311  double HDOP, PDOP, GeoidalSeparation;
 
  312  unsigned char nReferenceStations;
 
  313  tN2kGNSStype ReferenceStationType;
 
  314  uint16_t ReferenceSationID;
 
  315  double AgeOfCorrection;
 
  317  if (ParseN2kPGN129029(v, SID, DaysSince1970, SecondsSinceMidnight, Latitude,
 
  318                        Longitude, Altitude, GNSStype, GNSSmethod, nSatellites,
 
  319                        HDOP, PDOP, GeoidalSeparation, nReferenceStations,
 
  320                        ReferenceStationType, ReferenceSationID,
 
  322    temp_data.gLat = Latitude;
 
  323    temp_data.gLon = Longitude;
 
  330    if ((GNSSmethod == N2kGNSSm_GNSSfix) || (GNSSmethod == N2kGNSSm_DGNSS) ||
 
  331        (GNSSmethod == N2kGNSSm_PreciseGNSS)) {
 
  332      if (nSatellites > 0) temp_data.n_satellites = nSatellites;
 
  341bool CommDecoder::DecodePGN127250(std::vector<unsigned char> v,
 
  344  double Heading, Deviation, Variation;
 
  345  tN2kHeadingReference ref;
 
  347  if (ParseN2kPGN127250(v, SID, Heading, Deviation, Variation, ref)) {
 
  348    temp_data.gHdt = N2kDoubleNA;
 
  349    temp_data.gHdm = N2kDoubleNA;
 
  350    if (ref == tN2kHeadingReference::N2khr_true)
 
  351      temp_data.gHdt = Heading;
 
  352    else if (ref == tN2kHeadingReference::N2khr_magnetic)
 
  353      temp_data.gHdm = Heading;
 
  355    temp_data.gVar = Variation;
 
  363bool CommDecoder::DecodePGN129025(std::vector<unsigned char> v,
 
  365  double Latitude, Longitude;
 
  367  if (ParseN2kPGN129025(v, Latitude, Longitude)) {
 
  368    temp_data.gLat = Latitude;
 
  369    temp_data.gLon = Longitude;
 
  376bool CommDecoder::DecodePGN129540(std::vector<unsigned char> v,
 
  381  tN2kRangeResidualMode Mode;
 
  383  if (ParseN2kPGN129540(v, SID, Mode, NumberOfSVs)) {
 
  384    temp_data.n_satellites = NumberOfSVs;
 
  392bool CommDecoder::DecodeSignalK(std::string s, 
NavData& temp_data) {
 
  393  rapidjson::Document root;
 
  396  if (root.HasParseError()) 
return false;
 
  398  if (root.HasMember(
"updates") && root[
"updates"].IsArray()) {
 
  399    for (rapidjson::Value::ConstValueIterator itr = root[
"updates"].Begin();
 
  400         itr != root[
"updates"].End(); ++itr) {
 
  401      handleUpdate(*itr, temp_data);
 
  408void CommDecoder::handleUpdate(
const rapidjson::Value& update,
 
  410  wxString sfixtime = 
"";
 
  412  if (update.HasMember(
"timestamp")) {
 
  413    sfixtime = update[
"timestamp"].GetString();
 
  415  if (update.HasMember(
"source") && update[
"source"].HasMember(
"src")) {
 
  416    src_string = update[
"source"][
"src"].GetString();
 
  419  if (update.HasMember(
"values") && update[
"values"].IsArray()) {
 
  420    for (rapidjson::Value::ConstValueIterator itr = update[
"values"].Begin();
 
  421         itr != update[
"values"].End(); ++itr) {
 
  422      updateItem(*itr, sfixtime, temp_data);
 
  427void CommDecoder::updateItem(
const rapidjson::Value& item, wxString& sfixtime,
 
  429  bool bposValid = 
false;
 
  430  if (item.HasMember(
"path") && item.HasMember(
"value")) {
 
  431    const wxString& update_path = item[
"path"].GetString();
 
  433    if (update_path == 
"navigation.gnss.methodQuality") {
 
  435      if (src_string.size()) {
 
  436        if (item[
"value"] == 
"no GPS") {  
 
  437          GNSS_quality_map[src_string] = 0;
 
  439          GNSS_quality_map[src_string] = 1;
 
  444    if (update_path == 
"navigation.position" && !item[
"value"].IsNull()) {
 
  445      bposValid = updateNavigationPosition(item[
"value"], sfixtime, temp_data);
 
  449      if (GNSS_quality_map.find(src_string) != GNSS_quality_map.end()) {
 
  450        if (GNSS_quality_map[src_string] == 0) {
 
  451          temp_data.gLat = NAN;
 
  455    } 
else if (update_path == 
"navigation.speedOverGround" &&
 
  456                !item[
"value"].IsNull()) {
 
  457      updateNavigationSpeedOverGround(item[
"value"], sfixtime, temp_data);
 
  461      if (GNSS_quality_map.find(src_string) != GNSS_quality_map.end()) {
 
  462        if (GNSS_quality_map[src_string] == 0) {
 
  467    } 
else if (update_path == 
"navigation.courseOverGroundTrue" &&
 
  468                !item[
"value"].IsNull()) {
 
  469      updateNavigationCourseOverGround(item[
"value"], sfixtime, temp_data);
 
  470    } 
else if (update_path == 
"navigation.courseOverGroundMagnetic") {
 
  471    } 
else if (update_path ==
 
  472               "navigation.gnss.satellites")  
 
  474      updateGnssSatellites(item[
"value"], sfixtime, temp_data);
 
  475    } 
else if (update_path ==
 
  476               "navigation.gnss.satellitesInView")  
 
  478      updateGnssSatellites(item[
"value"], sfixtime, temp_data);
 
  479    } 
else if (update_path == 
"navigation.headingTrue") {
 
  480      if (!item[
"value"].IsNull())
 
  481        updateHeadingTrue(item[
"value"], sfixtime, temp_data);
 
  482    } 
else if (update_path == 
"navigation.headingMagnetic") {
 
  483      if (!item[
"value"].IsNull())
 
  484        updateHeadingMagnetic(item[
"value"], sfixtime, temp_data);
 
  485    } 
else if (update_path == 
"navigation.magneticVariation") {
 
  486      if (!item[
"value"].IsNull())
 
  487        updateMagneticVariance(item[
"value"], sfixtime, temp_data);
 
  495bool CommDecoder::updateNavigationPosition(
const rapidjson::Value& value,
 
  496                                           const wxString& sfixtime,
 
  498  if ((value.HasMember(
"latitude") && value[
"latitude"].IsDouble()) &&
 
  499      (value.HasMember(
"longitude") && value[
"longitude"].IsDouble())) {
 
  501    temp_data.gLat = value[
"latitude"].GetDouble();
 
  502    temp_data.gLon = value[
"longitude"].GetDouble();
 
  509void CommDecoder::updateNavigationSpeedOverGround(
const rapidjson::Value& value,
 
  510                                                  const wxString& sfixtime,
 
  512  double sog_ms = value.GetDouble();
 
  513  double sog_knot = sog_ms * 1.9438444924406;  
 
  515  temp_data.gSog = sog_knot;
 
  518void CommDecoder::updateNavigationCourseOverGround(
 
  519    const rapidjson::Value& value, 
const wxString& sfixtime,
 
  521  double cog_rad = value.GetDouble();
 
  522  double cog_deg = GEODESIC_RAD2DEG(cog_rad);
 
  524  temp_data.gCog = cog_deg;
 
  527void CommDecoder::updateGnssSatellites(
const rapidjson::Value& value,
 
  528                                       const wxString& sfixtime,
 
  531    if (value.GetInt() > 0) {
 
  532      temp_data.n_satellites = value.GetInt();
 
  534  } 
else if ((value.HasMember(
"count") && value[
"count"].IsInt())) {
 
  535    temp_data.n_satellites = value[
"count"].GetInt();
 
  538  if (GNSS_quality_map.find(src_string) != GNSS_quality_map.end()) {
 
  539    if (GNSS_quality_map[src_string] == 0) {
 
  540      temp_data.n_satellites = 0;
 
  545void CommDecoder::updateHeadingTrue(
const rapidjson::Value& value,
 
  546                                    const wxString& sfixtime,
 
  548  temp_data.gHdt = GEODESIC_RAD2DEG(value.GetDouble());
 
  551void CommDecoder::updateHeadingMagnetic(
const rapidjson::Value& value,
 
  552                                        const wxString& sfixtime,
 
  554  temp_data.gHdm = GEODESIC_RAD2DEG(value.GetDouble());
 
  557void CommDecoder::updateMagneticVariance(
const rapidjson::Value& value,
 
  558                                         const wxString& sfixtime,
 
  560  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.