31 #include <GeographicLib/UTMUPS.hpp> 
   32 #include <boost/tokenizer.hpp> 
   88                 msg.pose.covariance[0] = -1.0;
 
   89                 msg.pose.covariance[7] = -1.0;
 
   90                 msg.pose.covariance[14] = -1.0;
 
  102                     msg.pose.pose.orientation =
 
  106                     msg.pose.pose.orientation =
 
  125                 msg.pose.covariance[21] = -1.0;
 
  126                 msg.pose.covariance[28] = -1.0;
 
  127                 msg.pose.covariance[35] = -1.0;
 
  174             roll = std::isnan(roll) ? 0.0 : roll;
 
  175             pitch = std::isnan(pitch) ? 0.0 : pitch;
 
  196             msg.pose.covariance[23] =
 
  204             msg.pose.covariance[33] =
 
  211         publish<PoseWithCovarianceStampedMsg>(
"pose", msg);
 
  215         const std::shared_ptr<Telegram>& telegram)
 
  228         std::string serialnumber;
 
  232             serialnumber = 
"unknown";
 
  235         uint16_t indicators_type_mask = 
static_cast<uint16_t
>(255);
 
  236         uint16_t indicators_value_mask = 
static_cast<uint16_t
>(3840);
 
  237         uint16_t qualityind_pos;
 
  238         for (uint16_t i = 
static_cast<uint16_t
>(0);
 
  242                 static_cast<uint16_t
>(0))
 
  246                      8) == 
static_cast<uint16_t
>(0))
 
  248                     gnss_status.level = DiagnosticStatusMsg::STALE;
 
  250                              indicators_value_mask) >>
 
  251                             8) == 
static_cast<uint16_t
>(1) ||
 
  253                              indicators_value_mask) >>
 
  254                             8) == 
static_cast<uint16_t
>(2))
 
  259                     gnss_status.level = DiagnosticStatusMsg::OK;
 
  272         for (uint16_t i = 
static_cast<uint16_t
>(0);
 
  275             if (i == qualityind_pos)
 
  280                 static_cast<uint16_t
>(1))
 
  282                 gnss_status.values[i].key = 
"GNSS Signals, Main Antenna";
 
  283                 gnss_status.values[i].value = std::to_string(
 
  286                        static_cast<uint16_t
>(2))
 
  288                 gnss_status.values[i].key = 
"GNSS Signals, Aux1 Antenna";
 
  289                 gnss_status.values[i].value = std::to_string(
 
  292                        static_cast<uint16_t
>(11))
 
  294                 gnss_status.values[i].key = 
"RF Power, Main Antenna";
 
  295                 gnss_status.values[i].value = std::to_string(
 
  298                        static_cast<uint16_t
>(12))
 
  300                 gnss_status.values[i].key = 
"RF Power, Aux1 Antenna";
 
  301                 gnss_status.values[i].value = std::to_string(
 
  304                        static_cast<uint16_t
>(21))
 
  306                 gnss_status.values[i].key = 
"CPU Headroom";
 
  307                 gnss_status.values[i].value = std::to_string(
 
  310                        static_cast<uint16_t
>(25))
 
  312                 gnss_status.values[i].key = 
"OCXO Stability";
 
  313                 gnss_status.values[i].value = std::to_string(
 
  316                        static_cast<uint16_t
>(30))
 
  318                 gnss_status.values[i].key = 
"Base Station Measurements";
 
  319                 gnss_status.values[i].value = std::to_string(
 
  324                        static_cast<uint16_t
>(31));
 
  325                 gnss_status.values[i].key = 
"RTK Post-Processing";
 
  326                 gnss_status.values[i].value = std::to_string(
 
  330         gnss_status.hardware_id = serialnumber;
 
  331         gnss_status.name = 
"septentrio_driver: Quality indicators";
 
  332         gnss_status.message =
 
  333             "GNSS quality Indicators (from 0 for low quality to 10 for high quality, 15 if unknown)";
 
  334         msg.status.push_back(gnss_status);
 
  336         receiver_status.hardware_id = serialnumber;
 
  337         receiver_status.name = 
"septentrio_driver: receiver status";
 
  338         receiver_status.message = 
"Receiver status";
 
  339         receiver_status.values.resize(5);
 
  340         receiver_status.values[0].key = 
"ExtError";
 
  341         receiver_status.values[0].value =
 
  343         receiver_status.values[1].key = 
"RxError";
 
  344         receiver_status.values[1].value =
 
  346         receiver_status.values[2].key = 
"RxStatus";
 
  347         receiver_status.values[2].value =
 
  349         receiver_status.values[3].key = 
"Uptime in s";
 
  350         receiver_status.values[3].value =
 
  352         receiver_status.values[4].key = 
"CPU load in %";
 
  353         receiver_status.values[4].value =
 
  360             receiver_status.level = DiagnosticStatusMsg::OK;
 
  361         msg.status.push_back(receiver_status);
 
  378         publish<DiagnosticArrayMsg>(
"/diagnostics", msg);
 
  387         diagOsnma.name = 
"septentrio_driver: OSNMA";
 
  388         diagOsnma.message = 
"Current status of the OSNMA authentication";
 
  390         diagOsnma.values.resize(6);
 
  391         diagOsnma.values[0].key = 
"status";
 
  396             diagOsnma.values[0].value = 
"Disabled";
 
  402             diagOsnma.values[0].value =
 
  403                 "Initializing " + std::to_string(percent) + 
" %";
 
  408             diagOsnma.values[0].value = 
"Waiting on NTP";
 
  413             diagOsnma.values[0].value = 
"Init failed - inconsistent time";
 
  418             diagOsnma.values[0].value = 
"Init failed - KROOT signature invalid";
 
  423             diagOsnma.values[0].value = 
"Init failed - invalid param received";
 
  428             diagOsnma.values[0].value = 
"Authenticating";
 
  436         diagOsnma.values[1].key = 
"trusted_time_delta";
 
  438             diagOsnma.values[1].value =
 
  441             diagOsnma.values[1].value = 
"N/A";
 
  445         uint8_t gal_authentic = (gal_auth & gal_active).count();
 
  446         uint8_t gal_spoofed = (~gal_auth & gal_active).count();
 
  447         diagOsnma.values[2].key = 
"Galileo authentic";
 
  448         diagOsnma.values[2].value = std::to_string(gal_authentic);
 
  449         diagOsnma.values[3].key = 
"Galileo spoofed";
 
  450         diagOsnma.values[3].value = std::to_string(gal_spoofed);
 
  454         uint8_t gps_authentic = (gps_auth & gps_active).count();
 
  455         uint8_t gps_spoofed = (~gps_auth & gps_active).count();
 
  456         diagOsnma.values[4].key = 
"GPS authentic";
 
  457         diagOsnma.values[4].value = std::to_string(gps_authentic);
 
  458         diagOsnma.values[5].key = 
"GPS spoofed";
 
  459         diagOsnma.values[5].value = std::to_string(gps_spoofed);
 
  461         if ((gal_spoofed + gps_spoofed) == 0)
 
  462             diagOsnma.level = DiagnosticStatusMsg::OK;
 
  463         else if ((gal_authentic + gps_authentic) > 0)
 
  468         msg.status.push_back(diagOsnma);
 
  471         publish<DiagnosticArrayMsg>(
"/diagnostics", msg);
 
  480         diagRf.name = 
"septentrio_driver: AIM+ status";
 
  482             "Current status of the AIM+ interference and spoofing mitigation";
 
  484         diagRf.values.resize(2);
 
  485         diagRf.values[0].key = 
"interference";
 
  486         bool mitigated = 
false;
 
  487         bool detected = 
false;
 
  490             std::bitset<8> info = rfband.info;
 
  501             diagRf.values[0].value = 
"present";
 
  502             aimMsg.interference = AimPlusStatusMsg::INTERFERENCE_PRESENT;
 
  503         } 
else if (mitigated)
 
  505             diagRf.values[0].value = 
"mitigated";
 
  506             aimMsg.interference = AimPlusStatusMsg::INTERFERENCE_MITIGATED;
 
  509             diagRf.values[0].value = 
"spectrum clean";
 
  510             aimMsg.interference = AimPlusStatusMsg::SPECTRUM_CLEAN;
 
  513         diagRf.values[1].key = 
"spoofing";
 
  514         bool spoofed = 
false;
 
  516         if (flags.test(0) && flags.test(1))
 
  518             diagRf.values[1].value = 
"detected by OSNMA and authenticity test";
 
  520                 AimPlusStatusMsg::SPOOFING_DETECTED_BY_OSNMA_AND_AUTHENTCITY_TEST;
 
  522         } 
else if (flags.test(0))
 
  524             diagRf.values[1].value = 
"detected by authenticity test";
 
  526                 AimPlusStatusMsg::SPOOFING_DETECTED_BY_AUTHENTCITY_TEST;
 
  528         } 
else if (flags.test(1))
 
  530             diagRf.values[1].value = 
"detected by OSNMA";
 
  531             aimMsg.spoofing = AimPlusStatusMsg::SPOOFING_DETECTED_BY_OSNMA;
 
  535             diagRf.values[1].value = 
"none detected";
 
  536             aimMsg.spoofing = AimPlusStatusMsg::NONE_DETECTED;
 
  540             aimMsg.osnma_authenticating =
 
  544             aimMsg.galileo_authentic = (gal_auth & gal_active).count();
 
  545             aimMsg.galileo_spoofed = (~gal_auth & gal_active).count();
 
  548             aimMsg.gps_authentic = (gps_auth & gps_active).count();
 
  549             aimMsg.gps_spoofed = (~gps_auth & gps_active).count();
 
  552             aimMsg.osnma_authenticating = 
false;
 
  553             aimMsg.galileo_authentic = 0;
 
  554             aimMsg.galileo_spoofed = 0;
 
  555             aimMsg.gps_authentic = 0;
 
  556             aimMsg.gps_spoofed = 0;
 
  561         publish<AimPlusStatusMsg>(
"aimplusstatus", aimMsg);
 
  563         if (spoofed || detected)
 
  568             diagRf.level = DiagnosticStatusMsg::OK;
 
  570         msg.status.push_back(diagRf);
 
  573         publish<DiagnosticArrayMsg>(
"/diagnostics", msg);
 
  596         bool valid_orientation = 
false;
 
  610                     valid_orientation = 
true;
 
  615                     valid_orientation = 
true;
 
  625                     msg.orientation_covariance[0] =
 
  628                     msg.orientation_covariance[4] =
 
  631                     msg.orientation_covariance[8] =
 
  638                         msg.orientation_covariance[1] =
 
  641                         msg.orientation_covariance[2] =
 
  644                         msg.orientation_covariance[3] =
 
  648                         msg.orientation_covariance[5] =
 
  651                         msg.orientation_covariance[6] =
 
  654                         msg.orientation_covariance[7] =
 
  660                     msg.orientation_covariance[0] = -1.0;
 
  661                     msg.orientation_covariance[4] = -1.0;
 
  662                     msg.orientation_covariance[8] = -1.0;
 
  667         if (!valid_orientation)
 
  672         publish<ImuMsg>(
"imu", msg);
 
  682         msg.twist.covariance[21] = -1.0;
 
  683         msg.twist.covariance[28] = -1.0;
 
  684         msg.twist.covariance[35] = -1.0;
 
  709                 msg.twist.twist.linear.x = vel(0);
 
  710                 msg.twist.twist.linear.y = vel(1);
 
  711                 msg.twist.twist.linear.z = vel(2);
 
  721                 Eigen::Matrix3d covVel_local = Eigen::Matrix3d::Zero();
 
  731                         covVel_local(0, 0) = -1.0;
 
  738                         covVel_local(1, 1) = -1.0;
 
  742                         covVel_local(2, 2) = -1.0;
 
  745                         covVel_local(0, 1) = covVel_local(1, 0) =
 
  750                             covVel_local(0, 2) = covVel_local(2, 0) =
 
  753                             covVel_local(2, 1) = covVel_local(1, 2) =
 
  758                             covVel_local(0, 2) = covVel_local(2, 0) =
 
  761                             covVel_local(2, 1) = covVel_local(1, 2) =
 
  766                     covVel_local(0, 0) = -1.0;
 
  767                     covVel_local(1, 1) = -1.0;
 
  768                     covVel_local(2, 2) = -1.0;
 
  771                 msg.twist.covariance[0] = covVel_local(0, 0);
 
  772                 msg.twist.covariance[1] = covVel_local(0, 1);
 
  773                 msg.twist.covariance[2] = covVel_local(0, 2);
 
  774                 msg.twist.covariance[6] = covVel_local(1, 0);
 
  775                 msg.twist.covariance[7] = covVel_local(1, 1);
 
  776                 msg.twist.covariance[8] = covVel_local(1, 2);
 
  777                 msg.twist.covariance[12] = covVel_local(2, 0);
 
  778                 msg.twist.covariance[13] = covVel_local(2, 1);
 
  779                 msg.twist.covariance[14] = covVel_local(2, 2);
 
  782                 msg.twist.covariance[0] = -1.0;
 
  783                 msg.twist.covariance[7] = -1.0;
 
  784                 msg.twist.covariance[14] = -1.0;
 
  787             publish<TwistWithCovarianceStampedMsg>(
"twist_ins", msg);
 
  813                 msg.twist.twist.linear.x = vel(0);
 
  814                 msg.twist.twist.linear.y = vel(1);
 
  815                 msg.twist.twist.linear.z = vel(2);
 
  823                 Eigen::Matrix3d covVel_local = Eigen::Matrix3d::Zero();
 
  831                     covVel_local(0, 0) = -1.0;
 
  838                     covVel_local(1, 1) = -1.0;
 
  842                     covVel_local(2, 2) = -1.0;
 
  844                 covVel_local(0, 1) = covVel_local(1, 0) =
 
  849                         covVel_local(0, 2) = covVel_local(2, 0) =
 
  852                         covVel_local(2, 1) = covVel_local(1, 2) =
 
  857                         covVel_local(0, 2) = covVel_local(2, 0) =
 
  860                         covVel_local(2, 1) = covVel_local(1, 2) =
 
  864                 msg.twist.covariance[0] = covVel_local(0, 0);
 
  865                 msg.twist.covariance[1] = covVel_local(0, 1);
 
  866                 msg.twist.covariance[2] = covVel_local(0, 2);
 
  867                 msg.twist.covariance[6] = covVel_local(1, 0);
 
  868                 msg.twist.covariance[7] = covVel_local(1, 1);
 
  869                 msg.twist.covariance[8] = covVel_local(1, 2);
 
  870                 msg.twist.covariance[12] = covVel_local(2, 0);
 
  871                 msg.twist.covariance[13] = covVel_local(2, 1);
 
  872                 msg.twist.covariance[14] = covVel_local(2, 2);
 
  875                 msg.twist.covariance[0] = -1.0;
 
  876                 msg.twist.covariance[7] = -1.0;
 
  877                 msg.twist.covariance[14] = -1.0;
 
  880             publish<TwistWithCovarianceStampedMsg>(
"twist_gnss", msg);
 
  898         std::string zonestring;
 
  899         bool northernHemisphere;
 
  902         double meridian_convergence = 0.0;
 
  910                 GeographicLib::UTMUPS::Forward(
 
  913                     easting, northing, meridian_convergence, k, zone);
 
  914             } 
catch (
const std::exception& e)
 
  917                            "UTMUPS conversion exception: " + std::string(e.what()));
 
  928                                                zone, northernHemisphere, easting,
 
  929                                                northing, meridian_convergence, k);
 
  931                     GeographicLib::UTMUPS::EncodeZone(zone, northernHemisphere);
 
  932             } 
catch (
const std::exception& e)
 
  935                            "UTMUPS conversion exception: " + std::string(e.what()));
 
  945             msg.pose.pose.position.x = easting;
 
  946             msg.pose.pose.position.y = northing;
 
  950             msg.pose.pose.position.x = northing;
 
  951             msg.pose.pose.position.y = easting;
 
  955         msg.header.frame_id = 
"utm_" + zonestring;
 
  962         Eigen::Matrix3d P_pos = -Eigen::Matrix3d::Identity();
 
  983             yaw += 
deg2rad(meridian_convergence);
 
  985             yaw -= 
deg2rad(meridian_convergence);
 
  990             msg.pose.pose.orientation =
 
 1007             msg.pose.covariance[21] = -1.0;
 
 1008             msg.pose.covariance[28] = -1.0;
 
 1009             msg.pose.covariance[35] = -1.0;
 
 1037             double cg = std::cos(meridian_convergence);
 
 1038             double sg = std::sin(meridian_convergence);
 
 1039             Eigen::Matrix3d R = Eigen::Matrix3d::Identity();
 
 1044             P_pos = (R * P_pos * R.transpose()).eval();
 
 1047         msg.pose.covariance[0] = P_pos(0, 0);
 
 1048         msg.pose.covariance[1] = P_pos(0, 1);
 
 1049         msg.pose.covariance[2] = P_pos(0, 2);
 
 1050         msg.pose.covariance[6] = P_pos(1, 0);
 
 1051         msg.pose.covariance[7] = P_pos(1, 1);
 
 1052         msg.pose.covariance[8] = P_pos(1, 2);
 
 1053         msg.pose.covariance[12] = P_pos(2, 0);
 
 1054         msg.pose.covariance[13] = P_pos(2, 1);
 
 1055         msg.pose.covariance[14] = P_pos(2, 2);
 
 1078             publish<LocalizationMsg>(
"localization", msg);
 
 1099         msg.header.frame_id = 
"ecef";
 
 1119             msg.pose.covariance[0] = -1.0;
 
 1120             msg.pose.covariance[7] = -1.0;
 
 1121             msg.pose.covariance[14] = -1.0;
 
 1148             Eigen::Quaterniond q_local_ecef;
 
 1155             Eigen::Quaterniond q_b_local =
 
 1158             Eigen::Quaterniond q_b_ecef = q_local_ecef * q_b_local;
 
 1160             msg.pose.pose.orientation =
 
 1166         Eigen::Matrix3d covAtt_local = Eigen::Matrix3d::Zero();
 
 1167         bool covAttValid = 
true;
 
 1182             covAtt_local(0, 0) = -1.0;
 
 1183             covAtt_local(1, 1) = -1.0;
 
 1184             covAtt_local(2, 2) = -1.0;
 
 1185             covAttValid = 
false;
 
 1207             Eigen::Matrix3d R_local_ecef;
 
 1215             Eigen::Matrix3d covAtt_ecef =
 
 1216                 R_local_ecef * covAtt_local * R_local_ecef.transpose();
 
 1218             msg.pose.covariance[21] = covAtt_ecef(0, 0);
 
 1219             msg.pose.covariance[22] = covAtt_ecef(0, 1);
 
 1220             msg.pose.covariance[23] = covAtt_ecef(0, 2);
 
 1221             msg.pose.covariance[27] = covAtt_ecef(1, 0);
 
 1222             msg.pose.covariance[28] = covAtt_ecef(1, 1);
 
 1223             msg.pose.covariance[29] = covAtt_ecef(1, 2);
 
 1224             msg.pose.covariance[33] = covAtt_ecef(2, 0);
 
 1225             msg.pose.covariance[34] = covAtt_ecef(2, 1);
 
 1226             msg.pose.covariance[35] = covAtt_ecef(2, 2);
 
 1229             msg.pose.covariance[21] = -1.0;
 
 1230             msg.pose.covariance[28] = -1.0;
 
 1231             msg.pose.covariance[35] = -1.0;
 
 1237             publish<LocalizationMsg>(
"localization_ecef", msg);
 
 1248         Eigen::Matrix3d R_local_body =
 
 1256             Eigen::Vector3d vel_local;
 
 1260                 vel_local << ve, vn, vu;
 
 1264                 vel_local << vn, ve, -vu;
 
 1267             Eigen::Vector3d vel_body = R_local_body * vel_local;
 
 1268             msg.twist.twist.linear.x = vel_body(0);
 
 1269             msg.twist.twist.linear.y = vel_body(1);
 
 1270             msg.twist.twist.linear.z = vel_body(2);
 
 1275         Eigen::Matrix3d covVel_local = Eigen::Matrix3d::Zero();
 
 1285                 covVel_local(0, 0) = -1.0;
 
 1292                 covVel_local(1, 1) = -1.0;
 
 1296                 covVel_local(2, 2) = -1.0;
 
 1299             covVel_local(0, 0) = -1.0;
 
 1300             covVel_local(1, 1) = -1.0;
 
 1301             covVel_local(2, 2) = -1.0;
 
 1313                 covVel_local(0, 2) = covVel_local(2, 0) =
 
 1315                 covVel_local(2, 1) = covVel_local(1, 2) =
 
 1328             Eigen::Matrix3d covVel_body =
 
 1329                 R_local_body * covVel_local * R_local_body.transpose();
 
 1331             msg.twist.covariance[0] = covVel_body(0, 0);
 
 1332             msg.twist.covariance[1] = covVel_body(0, 1);
 
 1333             msg.twist.covariance[2] = covVel_body(0, 2);
 
 1334             msg.twist.covariance[6] = covVel_body(1, 0);
 
 1335             msg.twist.covariance[7] = covVel_body(1, 1);
 
 1336             msg.twist.covariance[8] = covVel_body(1, 2);
 
 1337             msg.twist.covariance[12] = covVel_body(2, 0);
 
 1338             msg.twist.covariance[13] = covVel_body(2, 1);
 
 1339             msg.twist.covariance[14] = covVel_body(2, 2);
 
 1342             msg.twist.covariance[0] = -1.0;
 
 1343             msg.twist.covariance[7] = -1.0;
 
 1344             msg.twist.covariance[14] = -1.0;
 
 1347         msg.twist.covariance[21] = -1.0;
 
 1348         msg.twist.covariance[28] = -1.0;
 
 1349         msg.twist.covariance[35] = -1.0;
 
 1358             msg.status.status = NavSatStatusMsg::STATUS_NO_FIX;
 
 1363             msg.status.status = NavSatStatusMsg::STATUS_FIX;
 
 1368             msg.status.status = NavSatStatusMsg::STATUS_FIX;
 
 1373             msg.status.status = NavSatStatusMsg::STATUS_FIX;
 
 1378             msg.status.status = NavSatStatusMsg::STATUS_FIX;
 
 1383             msg.status.status = NavSatStatusMsg::STATUS_FIX;
 
 1388             msg.status.status = NavSatStatusMsg::STATUS_FIX;
 
 1393             msg.status.status = NavSatStatusMsg::STATUS_FIX;
 
 1398             msg.status.status = NavSatStatusMsg::STATUS_FIX;
 
 1403             msg.status.status = NavSatStatusMsg::STATUS_SBAS_FIX;
 
 1408             msg.status.status = NavSatStatusMsg::STATUS_NO_FIX;
 
 1411                 "PVTGeodetic's Mode field contains an invalid type of PVT solution.");
 
 1443             bool gps_in_pvt = 
false;
 
 1444             bool glo_in_pvt = 
false;
 
 1445             bool com_in_pvt = 
false;
 
 1446             bool gal_in_pvt = 
false;
 
 1447             uint32_t mask_2 = 1;
 
 1448             for (
int bit = 0; bit != 31; ++bit)
 
 1451                 if (bit <= 5 && in_use)
 
 1455                 if (8 <= bit && bit <= 12 && in_use)
 
 1457                 if (((13 <= bit && bit <= 14) || (28 <= bit && bit <= 30)) && in_use)
 
 1459                 if ((bit == 17 || (19 <= bit && bit <= 22)) && in_use)
 
 1465                 gps_in_pvt * 1 + glo_in_pvt * 2 + com_in_pvt * 4 + gal_in_pvt * 8;
 
 1466             msg.status.service = service;
 
 1479             msg.position_covariance_type = NavSatFixMsg::COVARIANCE_TYPE_KNOWN;
 
 1493             bool gps_in_pvt = 
false;
 
 1494             bool glo_in_pvt = 
false;
 
 1495             bool com_in_pvt = 
false;
 
 1496             bool gal_in_pvt = 
false;
 
 1497             uint32_t mask_2 = 1;
 
 1498             for (
int bit = 0; bit != 31; ++bit)
 
 1501                 if (bit <= 5 && in_use)
 
 1505                 if (8 <= bit && bit <= 12 && in_use)
 
 1507                 if (((13 <= bit && bit <= 14) || (28 <= bit && bit <= 30)) && in_use)
 
 1509                 if ((bit == 17 || (19 <= bit && bit <= 22)) && in_use)
 
 1515                 gps_in_pvt * 1 + glo_in_pvt * 2 + com_in_pvt * 4 + gal_in_pvt * 8;
 
 1516             msg.status.service = service;
 
 1523                 msg.position_covariance[0] =
 
 1525                 msg.position_covariance[4] =
 
 1538             msg.position_covariance_type =
 
 1539                 NavSatFixMsg::COVARIANCE_TYPE_DIAGONAL_KNOWN;
 
 1541         publish<NavSatFixMsg>(
"navsatfix", msg);
 
 1550             msg.status.status = GpsStatusMsg::STATUS_NO_FIX;
 
 1555             msg.status.status = GpsStatusMsg::STATUS_FIX;
 
 1560             msg.status.status = GpsStatusMsg::STATUS_FIX;
 
 1565             msg.status.status = GpsStatusMsg::STATUS_DGPS_FIX;
 
 1570             msg.status.status = GpsStatusMsg::STATUS_DGPS_FIX;
 
 1575             msg.status.status = GpsStatusMsg::STATUS_DGPS_FIX;
 
 1580             msg.status.status = GpsStatusMsg::STATUS_DGPS_FIX;
 
 1585             msg.status.status = GpsStatusMsg::STATUS_DGPS_FIX;
 
 1590             msg.status.status = GpsStatusMsg::STATUS_DGPS_FIX;
 
 1597             if (reference_id == 131 || reference_id == 133 || reference_id == 135 ||
 
 1598                 reference_id == 135)
 
 1600                 msg.status.status = GpsStatusMsg::STATUS_WAAS_FIX;
 
 1603                 msg.status.status = GpsStatusMsg::STATUS_SBAS_FIX;
 
 1609             msg.status.status = GpsStatusMsg::STATUS_NO_FIX;
 
 1612                 "PVTGeodetic's Mode field contains an invalid type of PVT solution.");
 
 1673         std::vector<int32_t> cno_tracked;
 
 1674         std::vector<int32_t> svid_in_sync;
 
 1682                 svid_in_sync.push_back(
 
 1683                     static_cast<int32_t
>(measepoch_channel_type1.sv_id));
 
 1686                 if (((measepoch_channel_type1.type & type_mask) ==
 
 1687                      static_cast<uint8_t
>(1)) ||
 
 1688                     ((measepoch_channel_type1.type & type_mask) ==
 
 1689                      static_cast<uint8_t
>(2)))
 
 1691                     cno_tracked.push_back(
 
 1692                         static_cast<int32_t
>(measepoch_channel_type1.cn0) / 4);
 
 1695                     cno_tracked.push_back(
 
 1696                         static_cast<int32_t
>(measepoch_channel_type1.cn0) / 4 +
 
 1697                         static_cast<int32_t
>(10));
 
 1703         std::vector<int32_t> svid_in_sync_2;
 
 1704         std::vector<int32_t> elevation_tracked;
 
 1705         std::vector<int32_t> azimuth_tracked;
 
 1706         std::vector<int32_t> svid_pvt;
 
 1708         std::vector<int32_t> ordering;
 
 1715                 bool to_be_added = 
false;
 
 1716                 for (int32_t j = 0; j < static_cast<int32_t>(svid_in_sync.size());
 
 1719                     if (svid_in_sync[j] ==
 
 1720                         static_cast<int32_t
>(channel_sat_info.sv_id))
 
 1722                         ordering.push_back(j);
 
 1729                     svid_in_sync_2.push_back(
 
 1730                         static_cast<int32_t
>(channel_sat_info.sv_id));
 
 1731                     elevation_tracked.push_back(
 
 1732                         static_cast<int32_t
>(channel_sat_info.elev));
 
 1733                     constexpr uint16_t azimuth_mask = 511;
 
 1734                     azimuth_tracked.push_back(
static_cast<int32_t
>(
 
 1735                         (channel_sat_info.az_rise_set & azimuth_mask)));
 
 1737                 svid_pvt.reserve(channel_sat_info.stateInfo.size());
 
 1738                 for (
const auto& channel_state_info : channel_sat_info.stateInfo)
 
 1741                     bool pvt_status = 
false;
 
 1742                     uint16_t pvt_status_mask = std::pow(2, 15) + std::pow(2, 14);
 
 1743                     for (
int k = 15; k != -1; k -= 2)
 
 1745                         uint16_t pvt_status_value =
 
 1746                             (channel_state_info.pvt_status & pvt_status_mask) >>
 
 1748                         if (pvt_status_value == 2)
 
 1754                             pvt_status_mask = pvt_status_mask - std::pow(2, k) -
 
 1755                                               std::pow(2, k - 1) +
 
 1756                                               std::pow(2, k - 2) +
 
 1763                             static_cast<int32_t
>(channel_sat_info.sv_id));
 
 1768         msg.status.satellite_used_prn =
 
 1771         msg.status.satellites_visible = 
static_cast<uint16_t
>(svid_in_sync.size());
 
 1772         msg.status.satellite_visible_prn = svid_in_sync_2;
 
 1773         msg.status.satellite_visible_z = elevation_tracked;
 
 1774         msg.status.satellite_visible_azimuth = azimuth_tracked;
 
 1777         std::vector<int32_t> cno_tracked_reordered;
 
 1780             for (int32_t k = 0; k < static_cast<int32_t>(ordering.size()); ++k)
 
 1782                 cno_tracked_reordered.push_back(cno_tracked[ordering[k]]);
 
 1785         msg.status.satellite_visible_snr = cno_tracked_reordered;
 
 1796             msg.status.motion_source = GpsStatusMsg::SOURCE_POINTS;
 
 1799             msg.status.orientation_source = GpsStatusMsg::SOURCE_POINTS;
 
 1800             msg.status.position_source = GpsStatusMsg::SOURCE_GPS;
 
 1897             msg.position_covariance_type = NavSatFixMsg::COVARIANCE_TYPE_KNOWN;
 
 1906             msg.status.motion_source = GpsStatusMsg::SOURCE_POINTS;
 
 1909             msg.status.orientation_source = GpsStatusMsg::SOURCE_POINTS;
 
 1910             msg.status.position_source = GpsStatusMsg::SOURCE_GPS;
 
 2005                 msg.position_covariance[0] =
 
 2007                 msg.position_covariance[4] =
 
 2020             msg.position_covariance_type =
 
 2021                 NavSatFixMsg::COVARIANCE_TYPE_DIAGONAL_KNOWN;
 
 2023         publish<GpsFixMsg>(
"gpsfix", msg);
 
 2032         msg.source = 
"GPST";
 
 2034         publish<TimeReferenceMsg>(
"gpst", msg);
 
 2037     template <
typename T>
 
 2039                                         const std::shared_ptr<Telegram>& telegram,
 
 2045         msg.header.frame_id = 
frameId;
 
 2049             if constexpr (std::is_same<INSNavCartMsg, T>::value ||
 
 2050                           std::is_same<INSNavGeodMsg, T>::value)
 
 2052                 time_obj -= msg.latency * 100000ul; 
 
 2053             } 
else if constexpr (std::is_same<PVTCartesianMsg, T>::value ||
 
 2054                                  std::is_same<PVTGeodeticMsg, T>::value)
 
 2058             } 
else if constexpr (std::is_same<PosCovCartesianMsg, T>::value ||
 
 2059                                  std::is_same<PosCovGeodeticMsg, T>::value ||
 
 2060                                  std::is_same<VelCovCartesianMsg, T>::value ||
 
 2061                                  std::is_same<VelCovGeodeticMsg, T>::value ||
 
 2062                                  std::is_same<AttEulerMsg, T>::value ||
 
 2063                                  std::is_same<AttCovEulerMsg, T>::value ||
 
 2064                                  std::is_same<BaseVectorCartMsg, T>::value ||
 
 2065                                  std::is_same<BaseVectorGeodMsg, T>::value)
 
 2096         constexpr uint64_t secToNSec = 1000000000;
 
 2097         constexpr uint64_t mSec2NSec = 1000000;
 
 2098         constexpr uint64_t nsOfGpsStart =
 
 2102         constexpr uint64_t nsecPerWeek = 7 * 24 * 60 * 60 * secToNSec;
 
 2104         time_obj = nsOfGpsStart + tow * mSec2NSec + wnc * nsecPerWeek;
 
 2116     template <
typename M>
 
 2132                 "Not publishing message with GNSS time because no leap seconds are available yet.");
 
 2137                     "No leap seconds were set and none were received from log yet.");
 
 2161                 "Not publishing tf with GNSS time because no leap seconds are available yet.");
 
 2166                     "No leap seconds were set and none were received from log yet. ");
 
 2191                                         telegram->message.end(), msg))
 
 2197                 publish<PVTCartesianMsg>(
"pvtcartesian", msg);
 
 2230                                           telegram->message.end(), msg))
 
 2236                 publish<BaseVectorCartMsg>(
"basevectorcart", msg);
 
 2247                                           telegram->message.end(), msg))
 
 2253                 publish<BaseVectorGeodMsg>(
"basevectorgeod", msg);
 
 2264                                            telegram->message.end(), msg))
 
 2270                 publish<PosCovCartesianMsg>(
"poscovcartesian", msg);
 
 2426                                     telegram->message.end(), msg,
 
 2433                 publish<IMUSetupMsg>(
"imusetup", msg);
 
 2444                                           telegram->message.end(), msg,
 
 2451                 publish<VelSensorSetupMsg>(
"velsensorsetup", msg);
 
 2463                                       telegram->message.end(), msg,
 
 2467                                "parse error in ExtEventINSNavCart");
 
 2479                 publish<INSNavCartMsg>(
"exteventinsnavcart", msg);
 
 2490                                       telegram->message.end(), msg,
 
 2494                                "parse error in ExtEventINSNavGeod");
 
 2506                 publish<INSNavGeodMsg>(
"exteventinsnavgeod", msg);
 
 2554             if (!
DOPParser(
node_, telegram->message.begin(), telegram->message.end(),
 
 2570                                            telegram->message.end(), msg))
 
 2576                 publish<VelCovCartesianMsg>(
"velcovcartesian", msg);
 
 2630             static const int32_t ins_major = 1;
 
 2631             static const int32_t ins_minor = 4;
 
 2632             static const int32_t ins_patch = 0;
 
 2633             static const int32_t gnss_major = 4;
 
 2634             static const int32_t gnss_minor = 12;
 
 2635             static const int32_t gnss_patch = 1;
 
 2637             boost::tokenizer<>::iterator it = tok.begin();
 
 2638             std::vector<int32_t> major_minor_patch;
 
 2639             major_minor_patch.reserve(3);
 
 2640             for (boost::tokenizer<>::iterator it = tok.begin(); it != tok.end();
 
 2643                 int32_t v = std::atoi(it->c_str());
 
 2644                 major_minor_patch.push_back(v);
 
 2646             if (major_minor_patch.size() < 3)
 
 2653                     if ((major_minor_patch[0] < ins_major) ||
 
 2654                         ((major_minor_patch[0] == ins_major) &&
 
 2655                          (major_minor_patch[1] < ins_minor)) ||
 
 2656                         ((major_minor_patch[0] == ins_major) &&
 
 2657                          (major_minor_patch[1] == ins_minor) &&
 
 2658                          (major_minor_patch[2] < ins_patch)))
 
 2662                             "INS receiver has firmware version: " +
 
 2664                                 ", which does not support all features. Please update to at least " +
 
 2665                                 std::to_string(ins_major) + 
"." +
 
 2666                                 std::to_string(ins_minor) + 
"." +
 
 2667                                 std::to_string(ins_patch) + 
" or consult README.");
 
 2672                     if ((major_minor_patch[0] < gnss_major) ||
 
 2673                         ((major_minor_patch[0] == gnss_major) &&
 
 2674                          (major_minor_patch[1] < gnss_minor)) ||
 
 2675                         ((major_minor_patch[0] == gnss_major) &&
 
 2676                          (major_minor_patch[1] == gnss_minor) &&
 
 2677                          (major_minor_patch[2] < gnss_patch)))
 
 2681                             "GNSS receiver has firmware version: " +
 
 2683                                 ", which may not support all features. Please update to at least " +
 
 2684                                 std::to_string(gnss_major) + 
"." +
 
 2685                                 std::to_string(gnss_minor) + 
"." +
 
 2686                                 std::to_string(gnss_patch) + 
" or consult README.");
 
 2698                                     telegram->message.end(), msg))
 
 2709                                              std::to_string(sbfId) + 
" received.");
 
 2720         if ((unix_old != 0) && (
unix_time_ > unix_old))
 
 2724             std::stringstream ss;
 
 2725             ss << 
"Waiting for " << sleep_nsec / 1000000 << 
" milliseconds...";
 
 2728             std::this_thread::sleep_for(std::chrono::nanoseconds(sleep_nsec));
 
 2734         std::string message(telegram->message.begin(), telegram->message.end());
 
 2739         boost::char_separator<char> sep_2(
",*", 
"", boost::keep_empty_tokens);
 
 2740         boost::tokenizer<boost::char_separator<char>> tokens(message, sep_2);
 
 2741         std::vector<std::string> body;
 
 2743         for (boost::tokenizer<boost::char_separator<char>>::iterator tok_iter =
 
 2745              tok_iter != tokens.end(); ++tok_iter)
 
 2747             body.push_back(*tok_iter);
 
 2750         std::string id(body[0].begin() + 1, body[0].end());
 
 2771                                "GpggaMsg: " + std::string(e.what()));
 
 2774                 publish<GpggaMsg>(
"gpgga", msg);
 
 2791                                "GprmcMsg: " + std::string(e.what()));
 
 2794                 publish<GprmcMsg>(
"gprmc", msg);
 
 2811                                "GpgsaMsg: " + std::string(e.what()));
 
 2832                 publish<GpgsaMsg>(
"gpgsa", msg);
 
 2849                                "GpgsvMsg: " + std::string(e.what()));
 
 2871                 publish<GpgsvMsg>(
"gpgsv", msg);