diff --git a/fpsdk_apps/fpltool/fpltool_extract.cpp b/fpsdk_apps/fpltool/fpltool_extract.cpp index a69903d..b1ab3b5 100644 --- a/fpsdk_apps/fpltool/fpltool_extract.cpp +++ b/fpsdk_apps/fpltool/fpltool_extract.cpp @@ -41,10 +41,7 @@ #include #include #include -#include #include -#include -#include #include #include #include @@ -61,9 +58,6 @@ using namespace fpsdk::common::app; using namespace fpsdk::common::cam; using namespace fpsdk::common::fpl; using namespace fpsdk::common::parser; -using namespace fpsdk::common::parser::fpa; -using namespace fpsdk::common::parser::fpb; -using namespace fpsdk::common::parser::nmea; using namespace fpsdk::common::path; using namespace fpsdk::common::ros1; using namespace fpsdk::common::string; @@ -628,17 +622,8 @@ bool FplToolExtract::WriteJson(const std::string& name, const nlohmann::json& js bool FplToolExtract::WriteStreamMsg(const std::string& name, const StreamMsg& streammsg, const ParserMsg& parsermsg) { parsermsg.MakeInfo(); - nlohmann::json jdata = streammsg; // magic to_json() (_type, _stamp, _stream, _data/_data_b64) - jdata.update(parsermsg); // magic to_json() (_proto, _name, _seq, _info, _data/_data_b64) - - // We can decode some messages of some protocols - if (parsermsg.proto_ == Protocol::FP_A) { - jdata.update(FpaDecodeMessage(parsermsg.data_)); // magic to_json() - } else if (parsermsg.proto_ == Protocol::NMEA) { - jdata.update(NmeaDecodeMessage(parsermsg.data_)); // magic to_json() - } else if (parsermsg.proto_ == Protocol::FP_B) { - jdata.update(to_json_FP_B(parsermsg)); // magic to_json() - } + auto jdata = ParserMsgToJson(parsermsg); // magic to_json() (_proto, _name, _seq, _info, _data/_data_b64) + jdata.update(streammsg); // magic to_json() (_type, _stamp, _stream, _data/_data_b64) return WriteJson(name, jdata); } diff --git a/fpsdk_apps/parsertool/parsertool.cpp b/fpsdk_apps/parsertool/parsertool.cpp index d29c17d..00ded8d 100644 --- a/fpsdk_apps/parsertool/parsertool.cpp +++ b/fpsdk_apps/parsertool/parsertool.cpp @@ -27,6 +27,7 @@ #include #include #include +#include /* PACKAGE */ #include "../common/common.hpp" @@ -50,15 +51,17 @@ class ParserToolOptions : public ProgramOptions public: ParserToolOptions() // clang-format off : ProgramOptions("parsertool", { - { 'x', false, "hexdump" }, { 's', false, "save" }, { 'f', true, "filter" }, { 'c', false, "stdout" } + { 'x', false, "hexdump" }, { 's', false, "save" }, { 'f', true, "filter" }, { 'c', false, "stdout" }, + { 'j', false, "jsonl" } }) {}; // clang-format on // clang-format off - bool hexdump_ = false; //!< Do hexdump of messages - bool split_ = false; //!< Split individual messages and save to files - std::vector inputs_; //!< Input file(s) - std::vector filters_; //!< Filters - bool stdout_ = false; //!< Write message to stdout instead of info about it + bool hexdump_ = false; //!< See help screen below + bool save_ = false; //!< See help screen below + std::vector inputs_; //!< See help screen below + std::vector filters_; //!< See help screen below + bool stdout_ = false; //!< See help screen below + bool jsonl_ = false; //!< See help screen below // clang-format on void PrintHelp() override final @@ -79,11 +82,12 @@ class ParserToolOptions : public ProgramOptions std::fputs( "\n" " -x, --hexdump -- Print hexdump of each message, not with -c\n" - " -s, --save -- Save each (!) message into a separate (!) file in the current directory, not with -c\n" + " -s, --save -- Save each (!) message into a separate (!) file in the current directory, not with -cj\n" " -f , --filter \n" " -- Filter input, where is a comma-separated list of full or partial message.\n" " names. Multiple -f can be given.\n" - " -c, --stdout -- Write messages to stdout instead of printing info, useful with -f\n" + " -c, --stdout -- Write messages to stdout instead of printing info, useful with -f, not with -j\n" + " -j, --jsonl -- Write messages as JSONL to stdout instead of printing info, not with -c\n" " -- File or device to read data from (instead of stdin)\n" "\n" "Examples:\n" @@ -107,16 +111,24 @@ class ParserToolOptions : public ProgramOptions "\n" " Filter all FP_A-ODOMETRY:\n" "\n" - " parsertool -f FP_A-ODOMETRY fpsdk_common/test/data/mixed.bin\n" + " parsertool -f FP_A-ODOMETRY fpsdk_common/test/data/test_data_mixed.bin\n" "\n" " Filter all NMEA and FP_A messages. Either command does the same.\n" "\n" - " parsertool -f FP_A -f NMEA fpsdk_common/test/data/mixed.bin\n" - " parsertool -f FP_A,NMEA fpsdk_common/test/data/mixed.bin\n" + " parsertool -f FP_A -f NMEA fpsdk_common/test/data/test_data_mixed.bin\n" + " parsertool -f FP_A,NMEA fpsdk_common/test/data/test_data_mixed.bin\n" "\n" " Filter all NMEA and FP_A messages and store to output.txt file:\n" "\n" - " parsertool -f FP_A,NMEA -c fpsdk_common/test/data/mixed.bin > output.txt\n" + " parsertool -f FP_A,NMEA -c fpsdk_common/test/data/test_data_mixed.bin > output.txt\n" + "\n" + " Output messages as JSON (incl. decoding of fields where implemented):\n" + "\n" + " parsertool -j fpsdk_common/test/data/test_data_mixed.bin\n" + "\n" + " Output messages as JSON and pretty-print:\n" + "\n" + " parsertool -j fpsdk_common/test/data/test_data_mixed.bin | jq\n" "\n" "\n", stdout); // clang-format on @@ -130,7 +142,7 @@ class ParserToolOptions : public ProgramOptions hexdump_ = true; break; case 's': - split_ = true; + save_ = true; break; case 'f': for (auto& f : StrSplit(argument, ",")) { @@ -140,6 +152,9 @@ class ParserToolOptions : public ProgramOptions case 'c': stdout_ = true; break; + case 'j': + jsonl_ = true; + break; default: ok = false; break; @@ -158,11 +173,27 @@ class ParserToolOptions : public ProgramOptions DEBUG("inputs_[%" PRIuMAX "] = '%s'", ix, inputs_[ix].c_str()); } DEBUG("hexdump = %s", ToStr(hexdump_)); - DEBUG("split = %s", ToStr(split_)); + DEBUG("save = %s", ToStr(save_)); for (std::size_t ix = 0; ix < filters_.size(); ix++) { DEBUG("filters[%" PRIuMAX "] = %s", ix, filters_[ix].c_str()); } DEBUG("stdout = %s", ToStr(stdout_)); + DEBUG("jsonl = %s", ToStr(jsonl_)); + + if (stdout_ && jsonl_) { + WARNING("Cannot do --stdout and --jsonl at the same time"); + ok = false; + } + + if (hexdump_ && jsonl_) { + WARNING("Cannot do --hexdump and --jsonl at the same time"); + ok = false; + } + + if (save_ && (stdout_ || jsonl_)) { + WARNING("Cannot do --save and --stdout or --jsonlat the same time"); + ok = false; + } return ok; } @@ -289,7 +320,8 @@ class ParserTool void PrintMessageHeader() { // Keep in sync with PrintMessageData() - std::printf("------- Seq# Offset Size Protocol Message Info\n"); + std::fprintf(opts_.jsonl_ ? stderr : stdout, + "------- Seq# Offset Size Protocol Message Info\n"); } // ----------------------------------------------------------------------------------------------------------------- @@ -302,16 +334,19 @@ class ParserTool if (opts_.stdout_) { std::fwrite(msg.Data(), msg.Size(), 1, stdout); + } else if (opts_.jsonl_) { + msg.MakeInfo(); + std::printf("%s\n", ParserMsgToJson(msg).dump().c_str()); } else { msg.MakeInfo(); - std::printf("message %06" PRIuMAX " %8" PRIuMAX " %5" PRIuMAX " %-8s %-30s %s\n", msg.seq_, offs, + std::printf("message %08" PRIuMAX " %8" PRIuMAX " %5" PRIuMAX " %-8s %-30s %s\n", msg.seq_, offs, msg.Size(), ProtocolStr(msg.proto_), msg.name_.c_str(), msg.info_.empty() ? "-" : msg.info_.c_str()); if (hexdump) { for (auto& line : HexDump(msg.data_)) { std::printf("%s\n", line.c_str()); } } - if (opts_.split_) { + if (opts_.save_) { SaveMessage(msg); } } @@ -327,21 +362,22 @@ class ParserTool const auto& s = stats_; const double p_n = (s.n_msgs_ > 0 ? 100.0 / (double)s.n_msgs_ : 0.0); const double p_s = (s.s_msgs_ > 0 ? 100.0 / (double)s.s_msgs_ : 0.0); - std::printf("Stats: Messages Bytes\n"); + FILE* f = (opts_.jsonl_ ? stderr : stdout); + std::fprintf(f, "Stats: Messages Bytes\n"); const char* fmt = "%-8s %10" PRIu64 " (%5.1f%%) %10" PRIu64 " (%5.1f%%)\n"; // clang-format off - std::printf(fmt, "Total", s.n_msgs_, (double)s.n_msgs_ * p_n, s.s_msgs_, (double)s.s_msgs_ * p_s); - std::printf(fmt, ProtocolStr(Protocol::FP_A), s.n_fpa_, (double)s.n_fpa_ * p_n, s.s_fpa_, (double)s.s_fpa_ * p_s); - std::printf(fmt, ProtocolStr(Protocol::FP_B), s.n_fpb_, (double)s.n_fpb_ * p_n, s.s_fpb_, (double)s.s_fpb_ * p_s); - std::printf(fmt, ProtocolStr(Protocol::NMEA), s.n_nmea_, (double)s.n_nmea_ * p_n, s.s_nmea_, (double)s.s_nmea_ * p_s); - std::printf(fmt, ProtocolStr(Protocol::UBX), s.n_ubx_, (double)s.n_ubx_ * p_n, s.s_ubx_, (double)s.s_ubx_ * p_s); - std::printf(fmt, ProtocolStr(Protocol::RTCM3), s.n_rtcm3_, (double)s.n_rtcm3_ * p_n, s.s_rtcm3_, (double)s.s_rtcm3_ * p_s); - std::printf(fmt, ProtocolStr(Protocol::NOV_B), s.n_novb_, (double)s.n_novb_ * p_n, s.s_novb_, (double)s.s_novb_ * p_s); - std::printf(fmt, ProtocolStr(Protocol::UNI_B), s.n_unib_, (double)s.n_unib_ * p_n, s.s_unib_, (double)s.s_unib_ * p_s); - std::printf(fmt, ProtocolStr(Protocol::SBF), s.n_sbf_, (double)s.n_sbf_ * p_n, s.s_sbf_, (double)s.s_sbf_ * p_s); - std::printf(fmt, ProtocolStr(Protocol::QGC), s.n_qgc_, (double)s.n_qgc_ * p_n, s.s_qgc_, (double)s.s_qgc_ * p_s); - std::printf(fmt, ProtocolStr(Protocol::SPARTN), s.n_spartn_, (double)s.n_spartn_ * p_n, s.s_spartn_, (double)s.s_spartn_ * p_s); - std::printf(fmt, ProtocolStr(Protocol::OTHER), s.n_other_, (double)s.n_other_ * p_n, s.s_other_, (double)s.s_other_ * p_s); + std::fprintf(f, fmt, "Total", s.n_msgs_, (double)s.n_msgs_ * p_n, s.s_msgs_, (double)s.s_msgs_ * p_s); + std::fprintf(f, fmt, ProtocolStr(Protocol::FP_A), s.n_fpa_, (double)s.n_fpa_ * p_n, s.s_fpa_, (double)s.s_fpa_ * p_s); + std::fprintf(f, fmt, ProtocolStr(Protocol::FP_B), s.n_fpb_, (double)s.n_fpb_ * p_n, s.s_fpb_, (double)s.s_fpb_ * p_s); + std::fprintf(f, fmt, ProtocolStr(Protocol::NMEA), s.n_nmea_, (double)s.n_nmea_ * p_n, s.s_nmea_, (double)s.s_nmea_ * p_s); + std::fprintf(f, fmt, ProtocolStr(Protocol::UBX), s.n_ubx_, (double)s.n_ubx_ * p_n, s.s_ubx_, (double)s.s_ubx_ * p_s); + std::fprintf(f, fmt, ProtocolStr(Protocol::RTCM3), s.n_rtcm3_, (double)s.n_rtcm3_ * p_n, s.s_rtcm3_, (double)s.s_rtcm3_ * p_s); + std::fprintf(f, fmt, ProtocolStr(Protocol::NOV_B), s.n_novb_, (double)s.n_novb_ * p_n, s.s_novb_, (double)s.s_novb_ * p_s); + std::fprintf(f, fmt, ProtocolStr(Protocol::UNI_B), s.n_unib_, (double)s.n_unib_ * p_n, s.s_unib_, (double)s.s_unib_ * p_s); + std::fprintf(f, fmt, ProtocolStr(Protocol::SBF), s.n_sbf_, (double)s.n_sbf_ * p_n, s.s_sbf_, (double)s.s_sbf_ * p_s); + std::fprintf(f, fmt, ProtocolStr(Protocol::QGC), s.n_qgc_, (double)s.n_qgc_ * p_n, s.s_qgc_, (double)s.s_qgc_ * p_s); + std::fprintf(f, fmt, ProtocolStr(Protocol::SPARTN), s.n_spartn_, (double)s.n_spartn_ * p_n, s.s_spartn_, (double)s.s_spartn_ * p_s); + std::fprintf(f, fmt, ProtocolStr(Protocol::OTHER), s.n_other_, (double)s.n_other_ * p_n, s.s_other_, (double)s.s_other_ * p_s); // clang-format on } diff --git a/fpsdk_common/include/fpsdk_common/parser/ubx.hpp b/fpsdk_common/include/fpsdk_common/parser/ubx.hpp index 922af7d..9bac580 100644 --- a/fpsdk_common/include/fpsdk_common/parser/ubx.hpp +++ b/fpsdk_common/include/fpsdk_common/parser/ubx.hpp @@ -40,6 +40,7 @@ /* EXTERNAL */ /* PACKAGE */ +#include "../types.hpp" namespace fpsdk { namespace common { @@ -475,6 +476,8 @@ static constexpr uint8_t UBX_SEC_SIGLOG_MSGID = 0x10; static constexpr const char* UBX_SEC_SIGLOG_STRID = "UBX-SEC-SIGLOG"; //!< UBX-SEC-SIGLOG message name static constexpr uint8_t UBX_SEC_UNIQID_MSGID = 0x03; //!< UBX-SEC-UNIQID message ID static constexpr const char* UBX_SEC_UNIQID_STRID = "UBX-SEC-UNIQID"; //!< UBX-SEC-UNIQID message name +static constexpr uint8_t UBX_TIM_SVIN_MSGID = 0x04; //!< UBX-TIM-SVIN message ID +static constexpr const char* UBX_TIM_SVIN_STRID = "UBX-TIM-SVIN"; //!< UBX-TIM-SVIN message name static constexpr uint8_t UBX_TIM_TM2_MSGID = 0x03; //!< UBX-TIM-TM2 message ID static constexpr const char* UBX_TIM_TM2_STRID = "UBX-TIM-TM2"; //!< UBX-TIM-TM2 message name static constexpr uint8_t UBX_TIM_TP_MSGID = 0x01; //!< UBX-TIM-TP message ID @@ -610,7 +613,7 @@ struct UbxMsgInfo // @fp_codegen_begin{FPSDK_COMMON_PARSER_UBX_MSGINFO_HPP} using UbxClassesInfo = std::array; //!< UBX classes lookup table -using UbxMessagesInfo = std::array; //!< UBX messages lookup table +using UbxMessagesInfo = std::array; //!< UBX messages lookup table // @fp_codegen_end{FPSDK_COMMON_PARSER_UBX_MSGINFO_HPP} /** @@ -654,6 +657,7 @@ static constexpr uint8_t UBX_GNSSID_BDS = 3; //!< BeiDou static constexpr uint8_t UBX_GNSSID_QZSS = 5; //!< QZSS static constexpr uint8_t UBX_GNSSID_GLO = 6; //!< GLONASS static constexpr uint8_t UBX_GNSSID_NAVIC = 7; //!< NavIC +inline const char * UBX_GNSSID_STR(const uint8_t gnssId) { return gnssId == UBX_GNSSID_NONE ? "NONE" : types::IxToStr(gnssId, "GPS", "SBAS", "GAL", "BDS", "?", "QZSS", "GLO", "NAVIC"); } //!< @todo documentation // clang-format on ///@} @@ -690,7 +694,9 @@ static constexpr uint8_t UBX_SIGID_GPS_L2CL = 3; //!< GPS L2 CL static constexpr uint8_t UBX_SIGID_GPS_L2CM = 4; //!< GPS L2 CM static constexpr uint8_t UBX_SIGID_GPS_L5I = 6; //!< GPS L5 I static constexpr uint8_t UBX_SIGID_GPS_L5Q = 7; //!< GPS L5 Q +inline const char * UBX_SIGID_GPS_STR(const uint8_t sigId) { return types::IxToStr(sigId, "L1CA", "?", "?", "L2CL", "L2CM", "?", "L5I", "L5Q"); } //!< @todo documentation static constexpr uint8_t UBX_SIGID_SBAS_L1CA = 0; //!< SBAS L1 C/A +inline const char * UBX_SIGID_SBAS_STR(const uint8_t sigId) { return types::IxToStr(sigId, "L1CA"); } //!< @todo documentation static constexpr uint8_t UBX_SIGID_GAL_E1C = 0; //!< Galileo E1 C static constexpr uint8_t UBX_SIGID_GAL_E1B = 1; //!< Galileo E1 B static constexpr uint8_t UBX_SIGID_GAL_E5AI = 3; //!< Galileo E5 aI @@ -700,6 +706,7 @@ static constexpr uint8_t UBX_SIGID_GAL_E5BQ = 6; //!< Galileo E5 bQ static constexpr uint8_t UBX_SIGID_GAL_E6B = 8; //!< Galileo E6 B static constexpr uint8_t UBX_SIGID_GAL_E6C = 9; //!< Galileo E6 C static constexpr uint8_t UBX_SIGID_GAL_E6A = 10; //!< Galileo E6 A +inline const char * UBX_SIGID_GAL_STR(const uint8_t sigId) { return types::IxToStr(sigId, "E1C", "E1B", "?", "E5AI", "E5AQ", "E5BI", "E5BQ", "?", "E6B", "E6C", "E6A"); } //!< @todo documentation static constexpr uint8_t UBX_SIGID_BDS_B1ID1 = 0; //!< BeiDou B1I D1 static constexpr uint8_t UBX_SIGID_BDS_B1ID2 = 1; //!< BeiDou B1I D2 static constexpr uint8_t UBX_SIGID_BDS_B2ID1 = 2; //!< BeiDou B2I D1 @@ -710,15 +717,29 @@ static constexpr uint8_t UBX_SIGID_BDS_B1CP = 5; //!< BeiDou B1 Cp (p static constexpr uint8_t UBX_SIGID_BDS_B1CD = 6; //!< BeiDou B1 Cd (data) static constexpr uint8_t UBX_SIGID_BDS_B2AP = 7; //!< BeiDou B2 ap (pilot) static constexpr uint8_t UBX_SIGID_BDS_B2AD = 8; //!< BeiDou B2 ad (data) +inline const char * UBX_SIGID_BDS_STR(const uint8_t sigId) { return types::IxToStr(sigId, "B1ID1", "B1ID2", "B2ID1", "B2ID2", "B3ID1", "B1CP", "B1CD", "B2AP", "B2AD", "?", "B3ID2"); } //!< @todo documentation static constexpr uint8_t UBX_SIGID_QZSS_L1CA = 0; //!< QZSS L1 C/A static constexpr uint8_t UBX_SIGID_QZSS_L1S = 1; //!< QZSS L1 S static constexpr uint8_t UBX_SIGID_QZSS_L2CM = 4; //!< QZSS L2 CM static constexpr uint8_t UBX_SIGID_QZSS_L2CL = 5; //!< QZSS L2 CL static constexpr uint8_t UBX_SIGID_QZSS_L5I = 8; //!< QZSS L5 I static constexpr uint8_t UBX_SIGID_QZSS_L5Q = 9; //!< QZSS L5 Q +inline const char * UBX_SIGID_QZSS_STR(const uint8_t sigId) { return types::IxToStr(sigId, "L1CA", "L1S", "?", "?", "L2CM", "L2CL", "?", "?", "L5I", "L5Q"); } //!< @todo documentation static constexpr uint8_t UBX_SIGID_GLO_L1OF = 0; //!< GLONASS L1 OF static constexpr uint8_t UBX_SIGID_GLO_L2OF = 2; //!< GLONASS L2 OF +inline const char * UBX_SIGID_GLO_STR(const uint8_t sigId) { return types::IxToStr(sigId, "L1OF", "?", "L2OF"); } //!< @todo documentation static constexpr uint8_t UBX_SIGID_NAVIC_L5A = 0; //!< NavIC L5 A +inline const char * UBX_SIGID_NAVIC_STR(const uint8_t sigId) { return types::IxToStr(sigId, "L5A"); } //!< @todo documentation +inline const char * UBX_SIGID_STR(const uint8_t gnssId, const uint8_t sigId) { \ + if (sigId == UBX_SIGID_NONE) { return "NONE"; } \ + switch (gnssId) { \ + case UBX_GNSSID_GPS: return UBX_SIGID_GPS_STR(sigId); \ + case UBX_GNSSID_SBAS: return UBX_SIGID_SBAS_STR(sigId); \ + case UBX_GNSSID_GAL: return UBX_SIGID_GAL_STR(sigId); \ + case UBX_GNSSID_BDS: return UBX_SIGID_BDS_STR(sigId); \ + case UBX_GNSSID_QZSS: return UBX_SIGID_QZSS_STR(sigId); \ + case UBX_GNSSID_GLO: return UBX_SIGID_GLO_STR(sigId); \ + case UBX_GNSSID_NAVIC: return UBX_SIGID_NAVIC_STR(sigId); } return "?"; } //!< @todo documentation // clang-format on ///@} @@ -808,6 +829,7 @@ static constexpr uint8_t UBX_CFG_VALSET_V1_TRANSACTION_NONE static constexpr uint8_t UBX_CFG_VALSET_V1_TRANSACTION_BEGIN = 1; //!< UBX-CFG-VALSET.transaction value: transaction begin static constexpr uint8_t UBX_CFG_VALSET_V1_TRANSACTION_CONTINUE = 2; //!< UBX-CFG-VALSET.transaction value: transaction continue static constexpr uint8_t UBX_CFG_VALSET_V1_TRANSACTION_END = 3; //!< UBX-CFG-VALSET.transaction value: transaction: end +inline const char * UBX_CFG_VALSET_V1_TRANSACTION_STR(const uint8_t transaction) { return types::IxToStr(transaction, "NONE", "BEGIN", "CONTINUE", "END"); } //!< @todo documentation static constexpr uint8_t UBX_CFG_VALSET_V1_RESERVED = 0x00; //!< UBX-CFG-VALSET.reserved value static constexpr std::size_t UBX_CFG_VALSET_V1_MAX_KV = 64; //!< UBX-CFG-VALSET.cfgData: maximum number of key-value pairs static constexpr std::size_t UBX_CFG_VALSET_V1_CFGDATA_MAX_SIZE = UBX_CFG_VALSET_V1_MAX_KV * (4 + 8); //!< UBX-CFG-VALSET.cfgData maximum size @@ -850,6 +872,7 @@ static constexpr uint8_t UBX_CFG_VALGET_V0_LAYER_RAM static constexpr uint8_t UBX_CFG_VALGET_V0_LAYER_BBR = 1; //!< UBX-CFG-VALGET.layers value: layer BBR static constexpr uint8_t UBX_CFG_VALGET_V0_LAYER_FLASH = 2; //!< UBX-CFG-VALGET.layers value: layer Flash static constexpr uint8_t UBX_CFG_VALGET_V0_LAYER_DEFAULT = 7; //!< UBX-CFG-VALGET.layers value: layer Default +inline const char * UBX_CFG_VALGET_V0_LAYER_STR(const uint8_t layer) { return types::IxToStr(layer, "RAM", "BBR", "FLASH", "?", "?", "?", "?", "DEFAULT"); } //!< @todo documentation static constexpr std::size_t UBX_CFG_VALGET_V0_MAX_K = 64; //!< UBX-CFG-VALGET.cfgData maximum number of keys static constexpr std::size_t UBX_CFG_VALGET_V0_KEYS_MAX_SIZE = UBX_CFG_VALGET_V0_MAX_K * sizeof(uint32_t); //!< UBX-CFG-VALGET.keys maximum size static constexpr uint32_t UBX_CFG_VALGET_V0_GROUP_WILDCARD(const uint32_t groupId) { return groupId | 0x0000ffff; } //!< UBX-CFG-VALGET.keys group wildcard @@ -862,6 +885,7 @@ static constexpr uint8_t UBX_CFG_VALGET_V1_LAYER_RAM static constexpr uint8_t UBX_CFG_VALGET_V1_LAYER_BBR = 1; //!< UBX-CFG-VALGET.layers value: layer BBR static constexpr uint8_t UBX_CFG_VALGET_V1_LAYER_FLASH = 2; //!< UBX-CFG-VALGET.layers value: layer Flash static constexpr uint8_t UBX_CFG_VALGET_V1_LAYER_DEFAULT = 7; //!< UBX-CFG-VALGET.layers value: layer Default +inline const char * UBX_CFG_VALGET_V1_LAYER_STR(const uint8_t layer) { return types::IxToStr(layer, "RAM", "BBR", "FLASH", "?", "?", "?", "?", "DEFAULT"); } //!< @todo documentation static constexpr std::size_t UBX_CFG_VALGET_V1_MAX_KV = 64; //!< UBX-CFG-VALGET.cfgData maximum number of keys static constexpr std::size_t UBX_CFG_VALGET_V1_CFGDATA_MAX_SIZE = UBX_CFG_VALGET_V1_MAX_KV * (sizeof(uint32_t) + sizeof(uint64_t)); //!< UBX-CFG-VALGET.keys maximum size static constexpr uint32_t UBX_CFG_VALGET_V1_GROUP_WILDCARD(const uint32_t groupId) { return groupId | 0x0000ffff; } //!< UBX-CFG-VALGET.keys group wildcard @@ -897,6 +921,7 @@ static constexpr uint8_t UBX_CFG_VALDEL_V1_TRANSACTION_NONE static constexpr uint8_t UBX_CFG_VALDEL_V1_TRANSACTION_BEGIN = 1; //!< UBX-CFG-VALDEL.transaction value: transaction begin static constexpr uint8_t UBX_CFG_VALDEL_V1_TRANSACTION_CONTINUE = 2; //!< UBX-CFG-VALDEL.transaction value: transaction continue static constexpr uint8_t UBX_CFG_VALDEL_V1_TRANSACTION_END = 3; //!< UBX-CFG-VALDEL.transaction value: transaction: end +inline const char * UBX_CFG_VALDEL_V1_TRANSACTION_STR(const uint8_t transaction) { return types::IxToStr(transaction, "NONE", "BEGIN", "CONTINUE", "END"); } //!< @todo documentation static constexpr uint8_t UBX_CFG_VALDEL_V1_RESERVED = 0x00; //!< UBX-CFG-VALDEL.reserved value static constexpr std::size_t UBX_CFG_VALDEL_V1_MAX_K = 64; //!< UBX-CFG-VALDEL.cfgData maximum number of key IDs static constexpr std::size_t UBX_CFG_VALDEL_V1_KEYS_MAX_SIZE = UBX_CFG_VALDEL_V1_MAX_K * 4; //!< UBX-CFG-VALDEL.keys maximum size @@ -942,6 +967,7 @@ static constexpr uint8_t UBX_CFG_RST_V0_RESETMODE_GNSS static constexpr uint8_t UBX_CFG_RST_V0_RESETMODE_HW_CONTROLLED = 0x04; //!< Controlled hardware reset static constexpr uint8_t UBX_CFG_RST_V0_RESETMODE_GNSS_STOP = 0x08; //!< Stop GNSS static constexpr uint8_t UBX_CFG_RST_V0_RESETMODE_GNSS_START = 0x09; //!< Start GNSS +inline const char * UBX_CFG_RST_V0_RESETMODE_STR(const uint8_t resetMode) { return types::IxToStr(resetMode, "HW_FORCED", "SW", "GNSS", "?", "HW_CONTROLLED", "?", "?", "?", "GNSS_STOP", "GNSS_START"); } //!< @todo documentation static constexpr uint8_t UBX_CFG_RST_V0_RESERVED = 0x00; //!< Reserved // clang-format on @@ -1019,6 +1045,7 @@ static_assert(sizeof(UBX_ESF_MEAS_V0_GROUP2) == 4, ""); // clang-format off static constexpr std::size_t UBX_ESF_MEAS_V0_MIN_SIZE = sizeof(UBX_ESF_MEAS_V0_GROUP0) + UBX_FRAME_SIZE; //!< @todo documentation static constexpr uint8_t UBX_ESF_MEAS_V0_FLAGS_TIMEMARKSENT(const uint16_t flags) { return flags & 0x03; } //!< @todo documentation +inline const char * UBX_ESF_MEAS_V0_FLAGS_TIMEMARKSENT_STR(const uint16_t flags) { return types::IxToStr(UBX_ESF_MEAS_V0_FLAGS_TIMEMARKSENT(flags), "NONE", "EXT0", "EXT1"); } //!< @todo documentation static constexpr uint8_t UBX_ESF_MEAS_V0_FLAGS_TIMEMARKSENT_NONE = 0; //!< @todo documentation static constexpr uint8_t UBX_ESF_MEAS_V0_FLAGS_TIMEMARKSENT_EXT0 = 1; //!< @todo documentation static constexpr uint8_t UBX_ESF_MEAS_V0_FLAGS_TIMEMARKSENT_EXT1 = 2; //!< @todo documentation @@ -1073,20 +1100,24 @@ static constexpr std::size_t UBX_ESF_STATUS_V2_SIZE(const uint8_t* msg) sizeof(UBX_ESF_STATUS_V2_GROUP0) + UBX_FRAME_SIZE + (((const uint8_t *)(msg))[UBX_HEAD_SIZE + 15] * sizeof(UBX_ESF_STATUS_V2_GROUP1)); } //!< @todo documentation static constexpr double UBX_ESF_STATUS_V2_ITOW_SCALE = 1e-3; //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_INITSTATUS1_WTINITSTATUS(const uint8_t initStatus1) { return initStatus1 & 0x03; } //!< @todo documentation +inline const char * UBX_ESF_STATUS_V2_INITSTATUS1_WTINITSTATUS_STR(const uint8_t initStatus1) { return types::IxToStr(UBX_ESF_STATUS_V2_INITSTATUS1_WTINITSTATUS(initStatus1), "OFF", "INITALIZING", "INITIALIZED"); } //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_INITSTATUS1_WTINITSTATUS_OFF = 0; //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_INITSTATUS1_WTINITSTATUS_INITALIZING = 1; //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_INITSTATUS1_WTINITSTATUS_INITIALIZED = 2; //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_INITSTATUS1_MNTALGSTATUS(const uint8_t initStatus1) { return (initStatus1 >> 2) & 0x07; } //!< @todo documentation +inline const char * UBX_ESF_STATUS_V2_INITSTATUS1_MNTALGSTATUS_STR(const uint8_t initStatus1) { return types::IxToStr(UBX_ESF_STATUS_V2_INITSTATUS1_MNTALGSTATUS(initStatus1), "OFF", "INITALIZING", "INITIALIZED1", "INITIALIZED2"); } //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_INITSTATUS1_MNTALGSTATUS_OFF = 0; //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_INITSTATUS1_MNTALGSTATUS_INITALIZING = 1; //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_INITSTATUS1_MNTALGSTATUS_INITIALIZED1 = 2; //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_INITSTATUS1_MNTALGSTATUS_INITIALIZED2 = 3; //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_INITSTATUS1_INSINITSTATUS(const uint8_t initStatus1) { return (initStatus1 >> 5) & 0x07; } //!< @todo documentation +inline const char * UBX_ESF_STATUS_V2_INITSTATUS1_INSINITSTATUS_STR(const uint8_t initStatus1) { return types::IxToStr(UBX_ESF_STATUS_V2_INITSTATUS1_INSINITSTATUS(initStatus1), "OFF", "INITALIZING", "INITIALIZED1", "INITIALIZED2"); } //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_INITSTATUS1_INSINITSTATUS_OFF = 0; //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_INITSTATUS1_INSINITSTATUS_INITALIZING = 1; //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_INITSTATUS1_INSINITSTATUS_INITIALIZED1 = 2; //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_INITSTATUS1_INSINITSTATUS_INITIALIZED2 = 3; //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_INITSTATUS2_IMUINITSTATUS(const uint8_t initStatus2) { return initStatus2 & 0x03; } //!< @todo documentation +inline const char * UBX_ESF_STATUS_V2_INITSTATUS2_IMUINITSTATUS_STR(const uint8_t initStatus2) { return types::IxToStr(UBX_ESF_STATUS_V2_INITSTATUS2_IMUINITSTATUS(initStatus2), "OFF", "INITALIZING", "INITIALIZED1", "INITIALIZED2"); } //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_INITSTATUS2_IMUINITSTATUS_OFF = 0; //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_INITSTATUS2_IMUINITSTATUS_INITALIZING = 1; //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_INITSTATUS2_IMUINITSTATUS_INITIALIZED1 = 2; //!< @todo documentation @@ -1095,15 +1126,18 @@ static constexpr uint8_t UBX_ESF_STATUS_V2_FUSIONMODE_INIT static constexpr uint8_t UBX_ESF_STATUS_V2_FUSIONMODE_FUSION = 0x01; //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_FUSIONMODE_SUSPENDED = 0x02; //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_FUSIONMODE_DISABLED = 0x03; //!< @todo documentation +inline const char * UBX_ESF_STATUS_V2_FUSIONMODE_STR(const uint8_t fusionMode) { return types::IxToStr(fusionMode, "INIT", "FUSION", "SUSPENDED", "DISABLED"); } //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_SENSSTATUS1_TYPE(const uint8_t sensStatus1) { return sensStatus1 & 0x3f; } //!< same enum as UBX-ESF-MEAS.dataType it seems //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_SENSSTATUS1_USED = 0x40; //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_SENSSTATUS1_READY = 0x80; //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_SENSSTATUS2_CALIBSTATUS(const uint8_t sensStatus2) { return sensStatus2 & 0x03; } //!< @todo documentation +inline const char * UBX_ESF_STATUS_V2_SENSSTATUS2_CALIBSTATUS_STR(const uint8_t sensStatus2) { return types::IxToStr(UBX_ESF_STATUS_V2_SENSSTATUS2_CALIBSTATUS(sensStatus2), "NOTCALIB", "CALIBRATING", "CALIBRATED1", "CALIBRATED2"); } //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_SENSSTATUS2_CALIBSTATUS_NOTCALIB = 0; //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_SENSSTATUS2_CALIBSTATUS_CALIBRATING = 1; //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_SENSSTATUS2_CALIBSTATUS_CALIBRATED1 = 2; //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_SENSSTATUS2_CALIBSTATUS_CALIBRATED2 = 3; //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_SENSSTATUS2_TIMESTATUS(const uint8_t sensStatus2) { return (sensStatus2 >> 2) & 0x03; } //!< @todo documentation +inline const char * UBX_ESF_STATUS_V2_SENSSTATUS2_TIMESTATUS_STR(const uint8_t sensStatus2) { return types::IxToStr(UBX_ESF_STATUS_V2_SENSSTATUS2_TIMESTATUS(sensStatus2), "NODATA", "FIRSTBYTE", "EVENT", "TIMETAG"); } //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_SENSSTATUS2_TIMESTATUS_NODATA = 0; //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_SENSSTATUS2_TIMESTATUS_FIRSTBYTE = 1; //!< @todo documentation static constexpr uint8_t UBX_ESF_STATUS_V2_SENSSTATUS2_TIMESTATUS_EVENT = 2; //!< @todo documentation @@ -1141,6 +1175,7 @@ static constexpr uint8_t UBX_MGA_GAL_OSNMA_PUBKEY_V0_VERSION static constexpr std::size_t UBX_MGA_GAL_OSNMA_PUBKEY_V0_SIZE = sizeof(UBX_MGA_GAL_OSNMA_PUBKEY_V0_GROUP0) + UBX_FRAME_SIZE; //!< @todo documentation static constexpr uint8_t UBX_MGA_GAL_OSNMA_PUBKEY_V0_BITFIELD0_PUBKEYID(const uint8_t bitfield0) { return bitfield0 & 0x0f; } //!< @todo documentation static constexpr uint8_t UBX_MGA_GAL_OSNMA_PUBKEY_V0_BITFIELD0_PUBKEYTYPE(const uint8_t bitfield0) { return (bitfield0 >> 4) & 0x0f; } //!< @todo documentation +inline const char * UBX_MGA_GAL_OSNMA_PUBKEY_V0_BITFIELD0_PUBKEYTYPE_STR(const uint8_t bitfield0) { return types::IxToStr(UBX_MGA_GAL_OSNMA_PUBKEY_V0_BITFIELD0_PUBKEYTYPE(bitfield0), "?", "ECDSAP256", "?", "ECDSAP521"); } //!< @todo documentation static constexpr uint8_t UBX_MGA_GAL_OSNMA_PUBKEY_V0_BITFIELD0_PUBKEYTYPE_ECDSAP256 = 1; //!< @todo documentation static constexpr uint8_t UBX_MGA_GAL_OSNMA_PUBKEY_V0_BITFIELD0_PUBKEYTYPE_ECDSAP521 = 3; //!< @todo documentation // clang-format on @@ -1170,6 +1205,7 @@ static constexpr const char* UBX_MGA_GAL_OSNMA_MERKLE_STRID static constexpr uint8_t UBX_MGA_GAL_OSNMA_MERKLE_V0_VERSION = 0x00; //!< @todo documentation static constexpr std::size_t UBX_MGA_GAL_OSNMA_MERKLE_V0_SIZE = sizeof(UBX_MGA_GAL_OSNMA_MERKLE_V0_GROUP0) + UBX_FRAME_SIZE; //!< @todo documentation static constexpr uint8_t UBX_MGA_GAL_OSNMA_MERKLE_V0_BITFIELD0_APPLICABILITYTIME(const uint8_t bitfield0) { return bitfield0 & 0x01; } //!< @todo documentation +inline const char * UBX_MGA_GAL_OSNMA_MERKLE_V0_BITFIELD0_APPLICABILITYTIME_STR(const uint8_t bitfield0) { return types::IxToStr(UBX_MGA_GAL_OSNMA_MERKLE_V0_BITFIELD0_APPLICABILITYTIME(bitfield0), "CURRENT", "FUTURE"); } //!< @todo documentation static constexpr uint8_t UBX_MGA_GAL_OSNMA_MERKLE_V0_BITFIELD0_APPLICABILITYTIME_CURRENT = 0; //!< @todo documentation static constexpr uint8_t UBX_MGA_GAL_OSNMA_MERKLE_V0_BITFIELD0_APPLICABILITYTIME_FUTURE = 1; //!< @todo documentation // clang-format on @@ -1209,6 +1245,7 @@ static constexpr const char* UBX_MGA_INI_TIME_UTC_STRID static constexpr uint8_t UBX_MGA_INI_TIME_UTC_V0_VERSION = 0x00; //!< @todo documentation static constexpr std::size_t UBX_MGA_INI_TIME_UTC_V0_SIZE = sizeof(UBX_MGA_INI_TIME_UTC_V0_GROUP0) + UBX_FRAME_SIZE; //!< @todo documentation static constexpr uint8_t UBX_MGA_INI_TIME_UTC_V0_REF_SOURCE(const uint8_t ref) { return ref & 0x0f; } //!< @todo documentation +inline const char * UBX_MGA_INI_TIME_UTC_V0_REF_SOURCE_STR(const uint8_t ref) { return types::IxToStr(UBX_MGA_INI_TIME_UTC_V0_REF_SOURCE(ref), "NONE", "EXTINT0", "EXTINT1"); } //!< @todo documentation static constexpr uint8_t UBX_MGA_INI_TIME_UTC_V0_REF_SOURCE_NONE = 0; //!< @todo documentation static constexpr uint8_t UBX_MGA_INI_TIME_UTC_V0_REF_SOURCE_EXTINT0 = 1; //!< @todo documentation static constexpr uint8_t UBX_MGA_INI_TIME_UTC_V0_REF_SOURCE_EXTINT1 = 2; //!< @todo documentation @@ -1250,6 +1287,7 @@ static constexpr const char* UBX_MGA_INI_TIME_GNSS_STRID static constexpr uint8_t UBX_MGA_INI_TIME_GNSS_V0_VERSION = 0x00; //!< @todo documentation static constexpr std::size_t UBX_MGA_INI_TIME_GNSS_V0_SIZE = sizeof(UBX_MGA_INI_TIME_GNSS_V0_GROUP0) + UBX_FRAME_SIZE; //!< @todo documentation static constexpr uint8_t UBX_MGA_INI_TIME_GNSS_V0_REF_SOURCE(const uint8_t ref) { return ref & 0x0f; } //!< @todo documentation +inline const char * UBX_MGA_INI_TIME_GNSS_V0_REF_SOURCE_STR(const uint8_t ref) { return types::IxToStr(UBX_MGA_INI_TIME_GNSS_V0_REF_SOURCE(ref), "NONE", "EXTINT0", "EXTINT1"); } //!< @todo documentation static constexpr uint8_t UBX_MGA_INI_TIME_GNSS_V0_REF_SOURCE_NONE = 0; //!< @todo documentation static constexpr uint8_t UBX_MGA_INI_TIME_GNSS_V0_REF_SOURCE_EXTINT0 = 1; //!< @todo documentation static constexpr uint8_t UBX_MGA_INI_TIME_GNSS_V0_REF_SOURCE_EXTINT1 = 2; //!< @todo documentation @@ -1310,6 +1348,7 @@ static constexpr std::size_t UBX_MON_COMMS_V0_SIZE(const uint8_t* msg) static constexpr bool UBX_MON_COMMS_V0_TXERRORS_MEM(const uint8_t txErrors) { return (txErrors & 0x01) == 0x01; } //!< @todo documentation static constexpr bool UBX_MON_COMMS_V0_TXERRORS_ALLOC(const uint8_t txErrors) { return (txErrors & 0x02) == 0x02; } //!< @todo documentation static constexpr uint8_t UBX_MON_COMMS_V0_TXERRORS_OUTPUTPORT(const uint8_t txErrors) { return (txErrors >> 3) & 0x7; } //!< @todo documentation +inline const char * UBX_MON_COMMS_V0_TXERRORS_OUTPUTPORT_STR(const uint8_t txErrors) { return types::IxToStr(UBX_MON_COMMS_V0_TXERRORS_OUTPUTPORT(txErrors), "NA", "I2C", "UART1", "UART2", "USB", "SPI"); } //!< @todo documentation static constexpr uint8_t UBX_MON_COMMS_V0_TXERRORS_OUTPUTPORT_NA = 0; //!< @todo documentation static constexpr uint8_t UBX_MON_COMMS_V0_TXERRORS_OUTPUTPORT_I2C = 1; //!< @todo documentation static constexpr uint8_t UBX_MON_COMMS_V0_TXERRORS_OUTPUTPORT_UART1 = 2; //!< @todo documentation @@ -1323,6 +1362,7 @@ static constexpr uint8_t UBX_MON_COMMS_V0_PROTIDS_RTCM2 static constexpr uint8_t UBX_MON_COMMS_V0_PROTIDS_RTCM3 = 0x05; //!< @todo documentation static constexpr uint8_t UBX_MON_COMMS_V0_PROTIDS_SPARTN = 0x06; //!< @todo documentation static constexpr uint8_t UBX_MON_COMMS_V0_PROTIDS_OTHER = 0xff; //!< @todo documentation +inline const char * UBX_MON_COMMS_V0_PROTIDS_STR(const uint8_t protId) { return protId == UBX_MON_COMMS_V0_PROTIDS_OTHER ? "OTHER" : types::IxToStr(protId, "UBX", "NMEA", "RTCM2", "RAW", "?", "RTCM3", "SPARTN"); } //!< @todo documentation // clang-format on ///@} @@ -1361,6 +1401,7 @@ static constexpr std::size_t UBX_MON_HW_V0_SIZE static constexpr uint8_t UBX_MON_HW_V0_FLAGS_RTCCALIB = 0x01; //!< @todo documentation static constexpr uint8_t UBX_MON_HW_V0_FLAGS_SAFEBOOT = 0x02; //!< @todo documentation static constexpr uint8_t UBX_MON_HW_V0_FLAGS_JAMMINGSTATE(const uint8_t flags) { return (flags >> 2) & 0x03; } //!< @todo documentation +inline const char * UBX_MON_HW_V0_FLAGS_JAMMINGSTATE_STR(const uint8_t flags) { return types::IxToStr(UBX_MON_HW_V0_FLAGS_JAMMINGSTATE(flags), "UNKNOWN", "OK", "WARNING", "CRITICAL"); } //!< @todo documentation static constexpr uint8_t UBX_MON_HW_V0_FLAGS_JAMMINGSTATE_UNKNOWN = 0x00; //!< @todo documentation static constexpr uint8_t UBX_MON_HW_V0_FLAGS_JAMMINGSTATE_OK = 0x01; //!< @todo documentation static constexpr uint8_t UBX_MON_HW_V0_FLAGS_JAMMINGSTATE_WARNING = 0x02; //!< @todo documentation @@ -1371,9 +1412,11 @@ static constexpr uint8_t UBX_MON_HW_V0_ASTATUS_UNKNOWN static constexpr uint8_t UBX_MON_HW_V0_ASTATUS_OK = 0x02; //!< @todo documentation static constexpr uint8_t UBX_MON_HW_V0_ASTATUS_SHORT = 0x03; //!< @todo documentation static constexpr uint8_t UBX_MON_HW_V0_ASTATUS_OPEN = 0x04; //!< @todo documentation +inline const char * UBX_MON_HW_V0_ASTATUS_STR(const uint8_t aStatus) { return types::IxToStr(aStatus, "INIT", "UNKNOWN", "OK", "SHORT", "OPEN"); } //!< @todo documentation static constexpr uint8_t UBX_MON_HW_V0_APOWER_OFF = 0x00; //!< @todo documentation static constexpr uint8_t UBX_MON_HW_V0_APOWER_ON = 0x01; //!< @todo documentation static constexpr uint8_t UBX_MON_HW_V0_APOWER_UNKNOWN = 0x02; //!< @todo documentation +inline const char * UBX_MON_HW_V0_APOWER_STR(const uint8_t aPower) { return types::IxToStr(aPower, "OFF", "ON", "UNKNOWN"); } //!< @todo documentation static constexpr uint16_t UBX_MON_HW_V0_NOISEPERMS_MAX = 200; //!< This seems to be what u-center uses.. static constexpr uint16_t UBX_MON_HW_V0_AGCCNT_MAX = 8191; //!< @todo documentation static constexpr uint8_t UBX_MON_HW_V0_JAMIND_MAX = 255; //!< @todo documentation @@ -1409,6 +1452,11 @@ static constexpr uint8_t UBX_MON_HW2_V0_CFGSOURCE_ROM static constexpr uint8_t UBX_MON_HW2_V0_CFGSOURCE_OTP = 111; //!< @todo documentation static constexpr uint8_t UBX_MON_HW2_V0_CFGSOURCE_PIN = 112; //!< @todo documentation static constexpr uint8_t UBX_MON_HW2_V0_CFGSOURCE_FLASH = 102; //!< @todo documentation +inline const char * UBX_MON_HW2_V0_CFGSOURCE_STR(const uint8_t cfgSource) { switch (cfgSource) { \ + case UBX_MON_HW2_V0_CFGSOURCE_ROM: return "ROM"; \ + case UBX_MON_HW2_V0_CFGSOURCE_OTP: return "OTP"; \ + case UBX_MON_HW2_V0_CFGSOURCE_PIN: return "PIN"; \ + case UBX_MON_HW2_V0_CFGSOURCE_FLASH: return "FLASH"; } return "?"; } //!< @todo documentation // clang-format on ///@} @@ -1451,9 +1499,11 @@ static constexpr bool UBX_MON_HW3_V0_FLAGS_RTCCALIB(const uint8_t flags) static constexpr bool UBX_MON_HW3_V0_FLAGS_SAFEBOOT(const uint8_t flags) { return (flags & 0x02) == 0x02; } //!< @todo documentation static constexpr bool UBX_MON_HW3_V0_FLAGS_XTALABSENT(const uint8_t flags) { return (flags & 0x04) == 0x04; } //!< @todo documentation static constexpr uint8_t UBX_MON_HW3_V0_PINMASK_PERIPHPIO(const uint16_t pinMask) { return pinMask & 0x01; } //!< @todo documentation +inline const char * UBX_MON_HW3_V0_PINMASK_PERIPHPIO_STR(const uint16_t pinMask) { return types::IxToStr(UBX_MON_HW3_V0_PINMASK_PERIPHPIO(pinMask), "PERIPH", "PIO"); } //!< @todo documentation static constexpr uint8_t UBX_MON_HW3_V0_PINMASK_PERIPHPIO_PERIPH = 0; //!< @todo documentation static constexpr uint8_t UBX_MON_HW3_V0_PINMASK_PERIPHPIO_PIO = 1; //!< @todo documentation static constexpr uint8_t UBX_MON_HW3_V0_PINMASK_PINBANK(const uint16_t pinMask) { return (pinMask >> 1) & 0x01; } //!< @todo documentation +inline const char * UBX_MON_HW3_V0_PINMASK_PINBANK_STR(const uint16_t pinMask) { return types::IxToStr(UBX_MON_HW3_V0_PINMASK_PINBANK(pinMask), "A", "B", "C", "D", "E", "F", "G", "H"); } //!< @todo documentation static constexpr uint8_t UBX_MON_HW3_V0_PINMASK_PINBANK_A = 0; //!< @todo documentation static constexpr uint8_t UBX_MON_HW3_V0_PINMASK_PINBANK_B = 1; //!< @todo documentation static constexpr uint8_t UBX_MON_HW3_V0_PINMASK_PINBANK_C = 2; //!< @todo documentation @@ -1463,6 +1513,7 @@ static constexpr uint8_t UBX_MON_HW3_V0_PINMASK_PINBANK_F static constexpr uint8_t UBX_MON_HW3_V0_PINMASK_PINBANK_G = 6; //!< @todo documentation static constexpr uint8_t UBX_MON_HW3_V0_PINMASK_PINBANK_H = 7; //!< @todo documentation static constexpr uint8_t UBX_MON_HW3_V0_PINMASK_DIRECTION(const uint16_t pinMask) { return (pinMask >> 4) & 0x01; } //!< @todo documentation +inline const char * UBX_MON_HW3_V0_PINMASK_DIRECTION_STR(const uint16_t pinMask) { return types::IxToStr(UBX_MON_HW3_V0_PINMASK_DIRECTION(pinMask), "OUT", "IN"); } //!< @todo documentation static constexpr uint8_t UBX_MON_HW3_V0_PINMASK_DIRECTION_OUT = 0; //!< @todo documentation static constexpr uint8_t UBX_MON_HW3_V0_PINMASK_DIRECTION_IN = 1; //!< @todo documentation static constexpr bool UBX_MON_HW3_V0_PINMASK_VALUE(const uint16_t pinMask) { return (pinMask & 0x0020) == 0x0020; } //!< @todo documentation @@ -1518,6 +1569,7 @@ static constexpr std::size_t UBX_MON_RF_V0_MIN_SIZE static constexpr std::size_t UBX_MON_RF_V0_SIZE(const uint8_t* msg) { return sizeof(UBX_MON_RF_V0_GROUP0) + UBX_FRAME_SIZE + (((const uint8_t *)(msg))[UBX_HEAD_SIZE + 1] * sizeof(UBX_MON_RF_V0_GROUP1)); } //!< @todo documentation static constexpr uint8_t UBX_MON_RF_V0_FLAGS_JAMMINGSTATE(const uint8_t flags) { return flags & 0x03; } //!< @todo documentation +inline const char * UBX_MON_RF_V0_FLAGS_JAMMINGSTATE_STR(const uint8_t flags) { return types::IxToStr(UBX_MON_RF_V0_FLAGS_JAMMINGSTATE(flags), "UNKN", "OK", "WARN", "CRIT"); } //!< @todo documentation static constexpr uint8_t UBX_MON_RF_V0_FLAGS_JAMMINGSTATE_UNKN = 0; //!< @todo documentation static constexpr uint8_t UBX_MON_RF_V0_FLAGS_JAMMINGSTATE_OK = 1; //!< @todo documentation static constexpr uint8_t UBX_MON_RF_V0_FLAGS_JAMMINGSTATE_WARN = 2; //!< @todo documentation @@ -1527,9 +1579,11 @@ static constexpr uint8_t UBX_MON_RF_V0_ANTSTATUS_DONTKNOW static constexpr uint8_t UBX_MON_RF_V0_ANTSTATUS_OK = 2; //!< @todo documentation static constexpr uint8_t UBX_MON_RF_V0_ANTSTATUS_SHORT = 3; //!< @todo documentation static constexpr uint8_t UBX_MON_RF_V0_ANTSTATUS_OPEN = 4; //!< @todo documentation +inline const char * UBX_MON_RF_V0_ANTSTATUS_STR(const uint8_t antStatus) { return types::IxToStr(antStatus, "INIT", "DONTKNOW", "OK", "SHORT", "OPEN"); } //!< @todo documentation static constexpr uint8_t UBX_MON_RF_V0_ANTPOWER_OFF = 0; //!< @todo documentation static constexpr uint8_t UBX_MON_RF_V0_ANTPOWER_ON = 1; //!< @todo documentation static constexpr uint8_t UBX_MON_RF_V0_ANTPOWER_DONTKNOW = 2; //!< @todo documentation +inline const char * UBX_MON_RF_V0_ANTPOWER_STR(const uint8_t antPower) { return types::IxToStr(antPower, "OFF", "ON", "DONTKNOW"); } //!< @todo documentation static constexpr uint16_t UBX_MON_RF_V0_NOISEPERMS_MAX = 200; //!< This seems to be what u-center uses.. static constexpr uint16_t UBX_MON_RF_V0_AGCCNT_MAX = 8191; //!< @todo documentation static constexpr uint8_t UBX_MON_RF_V0_JAMIND_MAX = 255; //!< @todo documentation @@ -1621,6 +1675,7 @@ static constexpr uint8_t UBX_MON_SYS_V1_BOOTTYPE_VDDXFAIL static constexpr uint8_t UBX_MON_SYS_V1_BOOTTYPE_VDDRFFAIL = 9; //!< Boot type: VDD_RF fail static constexpr uint8_t UBX_MON_SYS_V1_BOOTTYPE_VCOREHIGHFAIL = 10; //!< Boot type: V_CORE_HIGH fail static constexpr uint8_t UBX_MON_SYS_V1_BOOTTYPE_SYSTEMRESET = 11; //!< Boot type: system reset +inline const char * UBX_MON_SYS_V1_BOOTTYPE_STR(const uint8_t bootType) { return types::IxToStr(bootType, "UNKNOWN", "COLDSTART", "WATCHDOG", "HWRESET", "HWBACKUP", "SWBACKUP", "SWRESET", "VIOFAIL", "VDDXFAIL", "VDDRFFAIL", "VCOREHIGHFAIL", "SYSTEMRESET"); } //!< @todo documentation // clang-format on ///@} @@ -1672,7 +1727,7 @@ struct UBX_MON_VER_V0_GROUP1 // clang-format off static_assert(sizeof(UBX_MON_VER_V0_GROUP1) == 30, ""); // clang-format off -static constexpr uint8_t UBX_MON_VER_V0_MIN_SIZE = sizeof(UBX_MON_VER_V0_GROUP0) + UBX_FRAME_SIZE; //!< @todo documentation +static constexpr std::size_t UBX_MON_VER_V0_MIN_SIZE = sizeof(UBX_MON_VER_V0_GROUP0) + UBX_FRAME_SIZE; //!< @todo documentation // clang-format on ///@} @@ -1820,7 +1875,7 @@ struct UBX_NAV_EELL_V0_GROUP0 // clang-format off static_assert(sizeof(UBX_NAV_EELL_V0_GROUP0) == 16, ""); // clang-format off -static constexpr uint8_t UBX_NAV_EELL_VERSION(const uint8_t* msg) { return msg[UBX_HEAD_SIZE]; } //!< @todo documentation +static constexpr uint8_t UBX_NAV_EELL_VERSION(const uint8_t* msg) { return msg[UBX_HEAD_SIZE + sizeof(uint32_t)]; } //!< @todo documentation static constexpr uint8_t UBX_NAV_EELL_V0_VERSION = 0x00; //!< @todo documentation static constexpr std::size_t UBX_NAV_EELL_V0_SIZE = sizeof(UBX_NAV_EELL_V0_GROUP0) + UBX_FRAME_SIZE; //!< @todo documentation static constexpr double UBX_NAV_EELL_V0_ITOW_SCALE = 1e-3; //!< @todo documentation @@ -2011,9 +2066,11 @@ static constexpr uint8_t UBX_NAV_PVT_V1_FIXTYPE_2D static constexpr uint8_t UBX_NAV_PVT_V1_FIXTYPE_3D = 3; //!< @todo documentation static constexpr uint8_t UBX_NAV_PVT_V1_FIXTYPE_3D_DR = 4; //!< @todo documentation static constexpr uint8_t UBX_NAV_PVT_V1_FIXTYPE_TIME = 5; //!< @todo documentation +inline const char * UBX_NAV_PVT_V1_FIXTYPE_STR(const uint8_t fixType) { return types::IxToStr(fixType, "NOFIX", "DRONLY", "2D", "3D", "3D_DR", "TIME"); } //!< @todo documentation static constexpr bool UBX_NAV_PVT_V1_FLAGS_GNSSFIXOK(const uint8_t flags) { return (flags & 0x01) == 0x01; } //!< @todo documentation static constexpr bool UBX_NAV_PVT_V1_FLAGS_DIFFSOLN(const uint8_t flags) { return (flags & 0x02) == 0x02; } //!< @todo documentation static constexpr uint8_t UBX_NAV_PVT_V1_FLAGS_PSMSTATE(const uint8_t flags) { return (flags >> 2) & 0x07; } //!< @todo documentation +inline const char * UBX_NAV_PVT_V1_FLAGS_PSMSTATE_STR(const uint8_t flags) { return types::IxToStr(UBX_NAV_PVT_V1_FLAGS_PSMSTATE(flags), "NOTACTIVE", "ENABLED", "ACQUISITION", "TRACKING", "POT", "INACTIVE"); } //!< @todo documentation static constexpr uint8_t UBX_NAV_PVT_V1_FLAGS_PSMSTATE_NOTACTIVE = 0; //!< @todo documentation static constexpr uint8_t UBX_NAV_PVT_V1_FLAGS_PSMSTATE_ENABLED = 1; //!< @todo documentation static constexpr uint8_t UBX_NAV_PVT_V1_FLAGS_PSMSTATE_ACQUISITION = 2; //!< @todo documentation @@ -2022,6 +2079,7 @@ static constexpr uint8_t UBX_NAV_PVT_V1_FLAGS_PSMSTATE_POT static constexpr uint8_t UBX_NAV_PVT_V1_FLAGS_PSMSTATE_INACTIVE = 5; //!< @todo documentation static constexpr bool UBX_NAV_PVT_V1_FLAGS_HEADVEHVALID(const uint8_t flags) { return (flags & 0x20) == 0x20; } //!< @todo documentation static constexpr uint8_t UBX_NAV_PVT_V1_FLAGS_CARRSOLN(const uint8_t flags) { return (flags >> 6) & 0x03; } //!< @todo documentation +inline const char * UBX_NAV_PVT_V1_FLAGS_CARRSOLN_STR(const uint8_t flags) { return types::IxToStr(UBX_NAV_PVT_V1_FLAGS_CARRSOLN(flags), "NO", "FLOAT", "FIXED"); } //!< @todo documentation static constexpr uint8_t UBX_NAV_PVT_V1_FLAGS_CARRSOLN_NO = 0; //!< @todo documentation static constexpr uint8_t UBX_NAV_PVT_V1_FLAGS_CARRSOLN_FLOAT = 1; //!< @todo documentation static constexpr uint8_t UBX_NAV_PVT_V1_FLAGS_CARRSOLN_FIXED = 2; //!< @todo documentation @@ -2030,6 +2088,7 @@ static constexpr bool UBX_NAV_PVT_V1_FLAGS2_CONFDATE(const uint8_t flags2 static constexpr bool UBX_NAV_PVT_V1_FLAGS2_CONFTIME(const uint8_t flags2) { return (flags2 & 0x80) == 0x80; } //!< @todo documentation static constexpr bool UBX_NAV_PVT_V1_FLAGS3_INVALIDLLH(const uint16_t flags3) { return (flags3 & 0x01) == 0x01; } //!< @todo documentation static constexpr uint8_t UBX_NAV_PVT_V1_FLAGS3_LASTCORRECTIONAGE(const uint16_t flags3) { return (flags3 >> 1) & 0x0F; } //!< @todo documentation +inline const char * UBX_NAV_PVT_V1_FLAGS3_LASTCORRECTIONAGE_STR(const uint16_t flags3) { return types::IxToStr(UBX_NAV_PVT_V1_FLAGS3_LASTCORRECTIONAGE(flags3), "NOT_AVAILABLE", "0_TO_1_SEC", "1_TO_2_SEC", "3_TO_5_SEC", "5_TO_10_SEC", "10_TO_15_SEC", "15_TO_20_SEC", "20_TO_30_SEC", "30_TO_45_SEC", "45_TO_60_SEC", "60_TO_90_SEC", "90_TO_120_SEC", "GEQ_120_SEC"); } //!< @todo documentation static constexpr uint8_t UBX_NAV_PVT_V1_FLAGS3_LASTCORRECTIONAGE_NOT_AVAILABLE = 0; //!< @todo documentation static constexpr uint8_t UBX_NAV_PVT_V1_FLAGS3_LASTCORRECTIONAGE_0_TO_1_SEC = 1; //!< @todo documentation static constexpr uint8_t UBX_NAV_PVT_V1_FLAGS3_LASTCORRECTIONAGE_1_TO_2_SEC = 2; //!< @todo documentation @@ -2044,9 +2103,11 @@ static constexpr uint8_t UBX_NAV_PVT_V1_FLAGS3_LASTCORRECTIONAGE_60_TO_90_SE static constexpr uint8_t UBX_NAV_PVT_V1_FLAGS3_LASTCORRECTIONAGE_90_TO_120_SEC = 11; //!< @todo documentation static constexpr uint8_t UBX_NAV_PVT_V1_FLAGS3_LASTCORRECTIONAGE_GEQ_120_SEC = 12; //!< @todo documentation static constexpr bool UBX_NAV_PVT_V1_FLAGS3_AUTHTIME(const uint16_t flags3) { return (flags3 & 0x2000) == 0x2000; } //!< @todo documentation +inline const char * UBX_NAV_PVT_V1_FLAGS3_AUTHTIME_STR(const uint16_t flags3) { return types::IxToStr(UBX_NAV_PVT_V1_FLAGS3_AUTHTIME(flags3) ? 1 : 0, "NOT_AUTHENTICATED", "AUTHENTICATED"); } //!< @todo documentation static constexpr uint8_t UBX_NAV_PVT_V1_FLAGS3_AUTHTIME_NOT_AUTHENTICATED = 0; //!< @todo documentation static constexpr uint8_t UBX_NAV_PVT_V1_FLAGS3_AUTHTIME_AUTHENTICATED = 1; //!< @todo documentation static constexpr bool UBX_NAV_PVT_V1_FLAGS3_NMAFIXSTATUS(const uint16_t flags3) { return (flags3 & 0x4000) == 0x4000; } //!< @todo documentation +inline const char * UBX_NAV_PVT_V1_FLAGS3_NMAFIXSTATUS_STR(const uint16_t flags3) { return types::IxToStr(UBX_NAV_PVT_V1_FLAGS3_NMAFIXSTATUS(flags3) ? 1 : 0, "NOT_VERIFIED", "VERIFIED"); } //!< @todo documentation static constexpr uint8_t UBX_NAV_PVT_V1_FLAGS3_NMAFIXSTATUS_NOT_VERIFIED = 0; //!< @todo documentation static constexpr uint8_t UBX_NAV_PVT_V1_FLAGS3_NMAFIXSTATUS_VERIFIED = 1; //!< @todo documentation static constexpr double UBX_NAV_PVT_V1_LAT_SCALE = 1e-7; //!< @todo documentation @@ -2116,6 +2177,7 @@ static constexpr bool UBX_NAV_RELPOSNED_V1_FLAGS_GNSSFIXOK(const uint32_t static constexpr bool UBX_NAV_RELPOSNED_V1_FLAGS_DIFFSOLN(const uint32_t flags) { return (flags & 0x00000002) == 0x00000002; } //!< @todo documentation static constexpr bool UBX_NAV_RELPOSNED_V1_FLAGS_RELPOSVALID(const uint32_t flags) { return (flags & 0x00000004) == 0x00000004; } //!< @todo documentation static constexpr uint8_t UBX_NAV_RELPOSNED_V1_FLAGS_CARRSOLN(const uint32_t flags) { return (flags >> 3) & 0x03; } //!< @todo documentation +inline const char * UBX_NAV_RELPOSNED_V1_FLAGS_CARRSOLN_STR(const uint32_t flags) { return types::IxToStr(UBX_NAV_RELPOSNED_V1_FLAGS_CARRSOLN(flags), "NO", "FLOAT", "FIXED"); } //!< @todo documentation static constexpr uint8_t UBX_NAV_RELPOSNED_V1_FLAGS_CARRSOLN_NO = 0; //!< @todo documentation static constexpr uint8_t UBX_NAV_RELPOSNED_V1_FLAGS_CARRSOLN_FLOAT = 1; //!< @todo documentation static constexpr uint8_t UBX_NAV_RELPOSNED_V1_FLAGS_CARRSOLN_FIXED = 2; //!< @todo documentation @@ -2165,6 +2227,7 @@ static constexpr std::size_t UBX_NAV_SAT_V1_MIN_SIZE static constexpr double UBX_NAV_SAT_V1_ITOW_SCALE = 1e-3; //!< @todo documentation // Note: only those flags relevant for a SV are defined below. All other info should be taken from UBX-NAV-SIG. //!< @todo documentation static constexpr uint8_t UBX_NAV_SAT_V1_FLAGS_ORBITSOURCE(const uint32_t flags) { return (flags >> 8) & 0x00000007; } //!< @todo documentation +inline const char * UBX_NAV_SAT_V1_FLAGS_ORBITSOURCE_STR(const uint32_t flags) { return types::IxToStr(UBX_NAV_SAT_V1_FLAGS_ORBITSOURCE(flags), "NONE", "EPH", "ALM", "ANO", "ANA", "OTHER1", "OTHER2", "OTHER3"); } //!< @todo documentation static constexpr uint8_t UBX_NAV_SAT_V1_FLAGS_ORBITSOURCE_NONE = 0; //!< @todo documentation static constexpr uint8_t UBX_NAV_SAT_V1_FLAGS_ORBITSOURCE_EPH = 1; //!< @todo documentation static constexpr uint8_t UBX_NAV_SAT_V1_FLAGS_ORBITSOURCE_ALM = 2; //!< @todo documentation @@ -2229,12 +2292,15 @@ static constexpr uint8_t UBX_NAV_SIG_V0_QUALITYIND_CODELOCK static constexpr uint8_t UBX_NAV_SIG_V0_QUALITYIND_CARRLOCK1 = 5; //!< @todo documentation static constexpr uint8_t UBX_NAV_SIG_V0_QUALITYIND_CARRLOCK2 = 6; //!< @todo documentation static constexpr uint8_t UBX_NAV_SIG_V0_QUALITYIND_CARRLOCK3 = 7; //!< @todo documentation +inline const char * UBX_NAV_SIG_V0_QUALITYIND_STR(const uint8_t qualityInd) { return types::IxToStr(qualityInd, "NOSIG", "SEARCH", "ACQUIRED", "UNUSED", "CODELOCK", "CARRLOCK1", "CARRLOCK2", "CARRLOCK3"); } //!< @todo documentation static constexpr uint8_t UBX_NAV_SIG_V0_IONOMODEL_NONE = 0; //!< @todo documentation static constexpr uint8_t UBX_NAV_SIG_V0_IONOMODEL_KLOB_GPS = 1; //!< @todo documentation static constexpr uint8_t UBX_NAV_SIG_V0_IONOMODEL_SBAS = 2; //!< @todo documentation static constexpr uint8_t UBX_NAV_SIG_V0_IONOMODEL_KLOB_BDS = 3; //!< @todo documentation static constexpr uint8_t UBX_NAV_SIG_V0_IONOMODEL_DUALFREQ = 8; //!< @todo documentation +inline const char * UBX_NAV_SIG_V0_IONOMODEL_STR(const uint8_t ionoModel) { return types::IxToStr(ionoModel, "NONE", "KLOB_GPS", "SBAS", "KLOB_BDS", "?", "?", "?", "?", "DUALFREQ"); } //!< @todo documentation static constexpr uint8_t UBX_NAV_SIG_V0_SIGFLAGS_HEALTH(const uint16_t sigFlags) { return sigFlags & 0x03; } //!< @todo documentation +inline const char * UBX_NAV_SIG_V0_SIGFLAGS_HEALTH_STR(const uint16_t sigFlags) { return types::IxToStr(UBX_NAV_SIG_V0_SIGFLAGS_HEALTH(sigFlags), "UNKNO", "HEALTHY", "UNHEALTHY"); } //!< @todo documentation static constexpr uint8_t UBX_NAV_SIG_V0_SIGFLAGS_HEALTH_UNKNO = 0; //!< @todo documentation static constexpr uint8_t UBX_NAV_SIG_V0_SIGFLAGS_HEALTH_HEALTHY = 1; //!< @todo documentation static constexpr uint8_t UBX_NAV_SIG_V0_SIGFLAGS_HEALTH_UNHEALTHY = 2; //!< @todo documentation @@ -2254,6 +2320,7 @@ static constexpr uint8_t UBX_NAV_SIG_V0_CORRSOURCE_RTCM3_OSR static constexpr uint8_t UBX_NAV_SIG_V0_CORRSOURCE_RTCM3_SSR = 5; //!< @todo documentation static constexpr uint8_t UBX_NAV_SIG_V0_CORRSOURCE_QZSS_SLAS = 6; //!< @todo documentation static constexpr uint8_t UBX_NAV_SIG_V0_CORRSOURCE_SPARTN = 7; //!< @todo documentation +inline const char * UBX_NAV_SIG_V0_CORRSOURCE_STR(const uint8_t corrSource) { return types::IxToStr(corrSource, "NONE", "SBAS", "BDS", "RTCM2", "RTCM3_OSR", "RTCM3_SSR", "QZSS_SLAS", "SPARTN"); } //!< @todo documentation static constexpr double UBX_NAV_SIG_V0_PRRES_SCALE = 1e-1; //!< @todo documentation // clang-format on @@ -2294,6 +2361,7 @@ static constexpr uint8_t UBX_NAV_TIMETRUSTED_V1_REFSYS_GPS static constexpr uint8_t UBX_NAV_TIMETRUSTED_V1_REFSYS_GAL = 2; //!< @todo documentation static constexpr uint8_t UBX_NAV_TIMETRUSTED_V1_REFSYS_BDS = 3; //!< @todo documentation static constexpr uint8_t UBX_NAV_TIMETRUSTED_V1_REFSYS_NAVIC = 15; //!< @todo documentation +inline const char * UBX_NAV_TIMETRUSTED_V1_REFSYS_STR(const uint8_t refSys) { return refSys == UBX_NAV_TIMETRUSTED_V1_REFSYS_NAVIC ? "NAVIC" : types::IxToStr(refSys, "NONE", "GPS", "GAL", "BDS"); } //!< @todo documentation static constexpr bool UBX_NAV_TIMETRUSTED_V1_VALID_TRUSTEDTIMEVALID(const uint8_t valid) { return (valid & 0x01) == 0x01; } //!< @todo documentation static constexpr bool UBX_NAV_TIMETRUSTED_V1_VALID_DELTATIMEVALID(const uint8_t valid) { return (valid & 0x02) == 0x02; } //!< @todo documentation static constexpr double UBX_NAV_TIMETRUSTED_V1_ITOW_SCALE = 1e-3; //!< @todo documentation @@ -2328,12 +2396,13 @@ static_assert(sizeof(UBX_NAV_STATUS_V0_GROUP0) == 16, ""); // clang-format off static constexpr std::size_t UBX_NAV_STATUS_V0_SIZE = sizeof(UBX_NAV_STATUS_V0_GROUP0) + UBX_FRAME_SIZE; //!< @todo documentation static constexpr double UBX_NAV_STATUS_V0_ITOW_SCALE = 1e-3; //!< @todo documentation -static constexpr uint8_t UBX_NAV_STATUS_V0_FIXTYPE_NOFIX = 0; //!< @todo documentation -static constexpr uint8_t UBX_NAV_STATUS_V0_FIXTYPE_DRONLY = 1; //!< @todo documentation -static constexpr uint8_t UBX_NAV_STATUS_V0_FIXTYPE_2D = 2; //!< @todo documentation -static constexpr uint8_t UBX_NAV_STATUS_V0_FIXTYPE_3D = 3; //!< @todo documentation -static constexpr uint8_t UBX_NAV_STATUS_V0_FIXTYPE_3D_DR = 4; //!< @todo documentation -static constexpr uint8_t UBX_NAV_STATUS_V0_FIXTYPE_TIME = 5; //!< @todo documentation +inline const char * UBX_NAV_STATUS_V0_GPSFIX_STR(const uint8_t gpsFix) { return types::IxToStr(gpsFix, "NOFIX", "DRONLY", "2D", "3D", "3D_DR", "TIME"); } //!< @todo documentation +static constexpr uint8_t UBX_NAV_STATUS_V0_GPSFIX_NOFIX = 0; //!< @todo documentation +static constexpr uint8_t UBX_NAV_STATUS_V0_GPSFIX_DRONLY = 1; //!< @todo documentation +static constexpr uint8_t UBX_NAV_STATUS_V0_GPSFIX_2D = 2; //!< @todo documentation +static constexpr uint8_t UBX_NAV_STATUS_V0_GPSFIX_3D = 3; //!< @todo documentation +static constexpr uint8_t UBX_NAV_STATUS_V0_GPSFIX_3D_DR = 4; //!< @todo documentation +static constexpr uint8_t UBX_NAV_STATUS_V0_GPSFIX_TIME = 5; //!< @todo documentation static constexpr bool UBX_NAV_STATUS_V0_FLAGS_GPSFIXOK(const uint8_t flags) { return (flags & 0x01) == 0x01; } //!< @todo documentation static constexpr bool UBX_NAV_STATUS_V0_FLAGS_DIFFSOLN(const uint8_t flags) { return (flags & 0x02) == 0x02; } //!< @todo documentation static constexpr bool UBX_NAV_STATUS_V0_FLAGS_WKNSET(const uint8_t flags) { return (flags & 0x04) == 0x04; } //!< @todo documentation @@ -2341,16 +2410,19 @@ static constexpr bool UBX_NAV_STATUS_V0_FLAGS_TOWSET(const uint8_t flags) static constexpr bool UBX_NAV_STATUS_V0_FIXSTAT_DIFFCORR(const uint8_t fixStat) { return (fixStat & 0x01) == 0x01; } //!< @todo documentation static constexpr bool UBX_NAV_STATUS_V0_FIXSTAT_CARRSOLNVALID(const uint8_t fixStat) { return (fixStat & 0x02) == 0x02; } //!< @todo documentation static constexpr uint8_t UBX_NAV_STATUS_V0_FLAGS2_PSMSTATE(const uint8_t flags2) { return flags2 & 0x03; } //!< @todo documentation +inline const char * UBX_NAV_STATUS_V0_FLAGS2_PSMSTATE_STR(const uint8_t flags2) { return types::IxToStr(UBX_NAV_STATUS_V0_FLAGS2_PSMSTATE(flags2), "ACQUISITION", "TRACKING", "POWEROPT", "INACTIVE"); } //!< @todo documentation static constexpr uint8_t UBX_NAV_STATUS_V0_FLAGS2_PSMSTATE_ACQUISITION = 0; //!< @todo documentation static constexpr uint8_t UBX_NAV_STATUS_V0_FLAGS2_PSMSTATE_TRACKING = 1; //!< @todo documentation static constexpr uint8_t UBX_NAV_STATUS_V0_FLAGS2_PSMSTATE_POWEROPT = 2; //!< @todo documentation static constexpr uint8_t UBX_NAV_STATUS_V0_FLAGS2_PSMSTATE_INACTIVE = 3; //!< @todo documentation static constexpr uint8_t UBX_NAV_STATUS_V0_FLAGS2_SPOOFDETSTATE(const uint8_t flags2) { return (flags2 >> 3) & 0x03; } //!< @todo documentation +inline const char * UBX_NAV_STATUS_V0_FLAGS2_SPOOFDETSTATE_STR(const uint8_t flags2) { return types::IxToStr(UBX_NAV_STATUS_V0_FLAGS2_SPOOFDETSTATE(flags2), "UNKNOWN", "NONE", "INDICATED", "AFFIRMED"); } //!< @todo documentation static constexpr uint8_t UBX_NAV_STATUS_V0_FLAGS2_SPOOFDETSTATE_UNKNOWN = 0; //!< @todo documentation static constexpr uint8_t UBX_NAV_STATUS_V0_FLAGS2_SPOOFDETSTATE_NONE = 1; //!< @todo documentation static constexpr uint8_t UBX_NAV_STATUS_V0_FLAGS2_SPOOFDETSTATE_INDICATED = 2; //!< @todo documentation static constexpr uint8_t UBX_NAV_STATUS_V0_FLAGS2_SPOOFDETSTATE_AFFIRMED = 3; //!< @todo documentation static constexpr uint8_t UBX_NAV_STATUS_V0_FLAGS2_CARRSOLN(const uint8_t flags2) { return (flags2 >> 6) & 0x03; } //!< @todo documentation +inline const char * UBX_NAV_STATUS_V0_FLAGS2_CARRSOLN_STR(const uint8_t flags2) { return types::IxToStr(UBX_NAV_STATUS_V0_FLAGS2_CARRSOLN(flags2), "NO", "FLOAT", "FIXED"); } //!< @todo documentation static constexpr uint8_t UBX_NAV_STATUS_V0_FLAGS2_CARRSOLN_NO = 0; //!< @todo documentation static constexpr uint8_t UBX_NAV_STATUS_V0_FLAGS2_CARRSOLN_FLOAT = 1; //!< @todo documentation static constexpr uint8_t UBX_NAV_STATUS_V0_FLAGS2_CARRSOLN_FIXED = 2; //!< @todo documentation @@ -2441,7 +2513,7 @@ struct UBX_NAV_TIMEBDS_V0_GROUP0 // clang-format off static_assert(sizeof(UBX_NAV_TIMEBDS_V0_GROUP0) == 20, ""); // clang-format off -static constexpr uint32_t UBX_NAV_TIMEBDS_V0_SIZE = sizeof(UBX_NAV_TIMEBDS_V0_GROUP0) + UBX_FRAME_SIZE; //!< @todo documentation +static constexpr std::size_t UBX_NAV_TIMEBDS_V0_SIZE = sizeof(UBX_NAV_TIMEBDS_V0_GROUP0) + UBX_FRAME_SIZE; //!< @todo documentation static constexpr double UBX_NAV_TIMEBDS_V0_ITOW_SCALE = 1e-3; //!< @todo documentation static constexpr double UBX_NAV_TIMEBDS_V0_FSOW_SCALE = 1e-9; //!< @todo documentation static constexpr double UBX_NAV_TIMEBDS_V0_TACC_SCALE = 1e-9; //!< @todo documentation @@ -2472,7 +2544,7 @@ struct UBX_NAV_TIMEGLO_V0_GROUP0 // clang-format off static_assert(sizeof(UBX_NAV_TIMEGLO_V0_GROUP0) == 20, ""); // clang-format off -static constexpr double UBX_NAV_TIMEGLO_V0_SIZE = sizeof(UBX_NAV_TIMEGLO_V0_GROUP0) + UBX_FRAME_SIZE; //!< @todo documentation +static constexpr std::size_t UBX_NAV_TIMEGLO_V0_SIZE = sizeof(UBX_NAV_TIMEGLO_V0_GROUP0) + UBX_FRAME_SIZE; //!< @todo documentation static constexpr double UBX_NAV_TIMEGLO_V0_ITOW_SCALE = 1e-3; //!< @todo documentation static constexpr double UBX_NAV_TIMEGLO_V0_FTOD_SCALE = 1e-9; //!< @todo documentation static constexpr double UBX_NAV_TIMEGLO_V0_TACC_SCALE = 1e-9; //!< @todo documentation @@ -2524,6 +2596,8 @@ static constexpr uint8_t UBX_NAV_TIMEUTC_V0_VALID_UTCSTANDARD_SU static constexpr uint8_t UBX_NAV_TIMEUTC_V0_VALID_UTCSTANDARD_NTSC = 7; //!< @todo documentation static constexpr uint8_t UBX_NAV_TIMEUTC_V0_VALID_UTCSTANDARD_NPLI = 8; //!< @todo documentation static constexpr uint8_t UBX_NAV_TIMEUTC_V0_VALID_UTCSTANDARD_UNNOWN = 15; //!< @todo documentation +inline const char * UBX_NAV_TIMEUTC_V0_VALID_UTCSTANDARD_STR(const uint8_t valid) { return UBX_NAV_TIMEUTC_V0_VALID_UTCSTANDARD(valid) == UBX_NAV_TIMEUTC_V0_VALID_UTCSTANDARD_UNNOWN ? "UNNOWN" : \ + types::IxToStr(UBX_NAV_TIMEUTC_V0_VALID_UTCSTANDARD(valid), "INFONA", "CRL", "NIST", "USNO", "BIPM", "EU", "SU", "NTSC", "NPLI"); } //!< @todo documentation // clang-format on ///@} @@ -2563,12 +2637,14 @@ static constexpr uint8_t UBX_NAV_TIMELS_V0_SRCOFCURRLS_BDS static constexpr uint8_t UBX_NAV_TIMELS_V0_SRCOFCURRLS_GAL = 5; //!< @todo documentation static constexpr uint8_t UBX_NAV_TIMELS_V0_SRCOFCURRLS_CONFIG = 7; //!< @todo documentation static constexpr uint8_t UBX_NAV_TIMELS_V0_SRCOFCURRLS_UNKNOWN = 255; //!< @todo documentation +inline const char * UBX_NAV_TIMELS_V0_SRCOFCURRLS_STR(const uint8_t srcOfCurrLs) { return srcOfCurrLs == UBX_NAV_TIMELS_V0_SRCOFCURRLS_UNKNOWN ? "UNKNOWN" : types::IxToStr(srcOfCurrLs, "DEFAULT", "GPSGLO", "GPS", "SBAS", "BDS", "GAL", "?", "CONFIG"); } //!< @todo documentation static constexpr uint8_t UBX_NAV_TIMELS_V0_SRCOFCURRLSCHANGE_NONE = 0; //!< @todo documentation static constexpr uint8_t UBX_NAV_TIMELS_V0_SRCOFCURRLSCHANGE_GPS = 2; //!< @todo documentation static constexpr uint8_t UBX_NAV_TIMELS_V0_SRCOFCURRLSCHANGE_SBAS = 3; //!< @todo documentation static constexpr uint8_t UBX_NAV_TIMELS_V0_SRCOFCURRLSCHANGE_BDS = 4; //!< @todo documentation static constexpr uint8_t UBX_NAV_TIMELS_V0_SRCOFCURRLSCHANGE_GAL = 5; //!< @todo documentation static constexpr uint8_t UBX_NAV_TIMELS_V0_SRCOFCURRLSCHANGE_GLO = 6; //!< @todo documentation +inline const char * UBX_NAV_TIMELS_V0_SRCOFCURRLSCHANGE_STR(const uint8_t srcOfLsChange) { return types::IxToStr(srcOfLsChange, "NONE", "?", "GPS", "SBAS", "BDS", "GAL", "GLO"); } //!< @todo documentation static constexpr bool UBX_NAV_TIMELS_V0_VALID_CURRLSVALID(const uint8_t valid) { return (valid & 0x01) == 0x01; } //!< @todo documentation static constexpr bool UBX_NAV_TIMELS_V0_VALID_TIMETOLSEVENTVALID(const uint8_t valid) { return (valid & 0x02) == 0x02; } //!< @todo documentation // clang-format on @@ -2690,6 +2766,7 @@ static constexpr uint8_t UBX_RXM_RTCM_V2_VERSION static constexpr std::size_t UBX_RXM_RTCM_V2_SIZE = sizeof(UBX_RXM_RTCM_V2_GROUP0) + UBX_FRAME_SIZE; //!< @todo documentation static constexpr bool UBX_RXM_RTCM_V2_FLAGS_CRCFAILED(const uint8_t flags) { return (flags & 0x01) == 0x01; } //!< @todo documentation static constexpr uint8_t UBX_RXM_RTCM_V2_FLAGS_MSGUSED(const uint8_t flags) { return (flags >> 1) & 0x03; } //!< @todo documentation +inline const char * UBX_RXM_RTCM_V2_FLAGS_MSGUSED_STR(const uint8_t flags) { return types::IxToStr(UBX_RXM_RTCM_V2_FLAGS_MSGUSED(flags), "UNKNOWN", "UNUSED", "USED"); } //!< @todo documentation static constexpr uint8_t UBX_RXM_RTCM_V2_FLAGS_MSGUSED_UNKNOWN = 0x00; //!< @todo documentation static constexpr uint8_t UBX_RXM_RTCM_V2_FLAGS_MSGUSED_UNUSED = 0x01; //!< @todo documentation static constexpr uint8_t UBX_RXM_RTCM_V2_FLAGS_MSGUSED_USED = 0x02; //!< @todo documentation @@ -2755,6 +2832,7 @@ static constexpr uint8_t UBX_RXM_SPARTN_VERSION(const uint8_t* msg) static constexpr uint8_t UBX_RXM_SPARTN_V1_VERSION = 0x01; //!< @todo documentation static constexpr std::size_t UBX_RXM_SPARTN_V1_SIZE = sizeof(UBX_RXM_SPARTN_V1_GROUP0) + UBX_FRAME_SIZE; //!< @todo documentation static constexpr uint8_t UBX_RXM_SPARTN_V1_FLAGS_MSGUSED(const uint8_t flags) { return (flags >> 1) & 0x03; } //!< @todo documentation +inline const char * UBX_RXM_SPARTN_V1_FLAGS_MSGUSED_STR(const uint8_t flags) { return types::IxToStr(UBX_RXM_SPARTN_V1_FLAGS_MSGUSED(flags), "UNKNOWN", "UNUSED", "USED"); } //!< @todo documentation static constexpr uint8_t UBX_RXM_SPARTN_V1_FLAGS_MSGUSED_UNKNOWN = 0x00; //!< @todo documentation static constexpr uint8_t UBX_RXM_SPARTN_V1_FLAGS_MSGUSED_UNUSED = 0x01; //!< @todo documentation static constexpr uint8_t UBX_RXM_SPARTN_V1_FLAGS_MSGUSED_USED = 0x02; //!< @todo documentation @@ -2800,12 +2878,14 @@ static constexpr uint8_t UBX_SEC_OSNMA_V3_VERSION static constexpr std::size_t UBX_SEC_OSNMA_V3_MIN_SIZE = sizeof(UBX_SEC_OSNMA_V3_GROUP0) + UBX_FRAME_SIZE; //!< @todo documentation static constexpr bool UBX_SEC_OSNMA_V3_NMAHEADER_HEADERAUTHSTATUS(const uint8_t nmaHeader) { return (nmaHeader & 0x01) == 0x01; } //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_NMAHEADER_NMASTATUS(const uint8_t nmaHeader) { return (nmaHeader >> 1) & 0x03; } //!< @todo documentation +inline const char * UBX_SEC_OSNMA_V3_NMAHEADER_NMASTATUS_STR(const uint8_t nmaHeader) { return types::IxToStr(UBX_SEC_OSNMA_V3_NMAHEADER_NMASTATUS(nmaHeader), "NOTAUTHENTICATED", "TEST", "OPERATIONAL", "INVALID"); } //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_NMAHEADER_NMASTATUS_NOTAUTHENTICATED = 0; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_NMAHEADER_NMASTATUS_TEST = 1; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_NMAHEADER_NMASTATUS_OPERATIONAL = 2; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_NMAHEADER_NMASTATUS_INVALID = 3; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_NMAHEADER_CHAININFORCE(const uint8_t nmaHeader) { return (nmaHeader >> 3) & 0x03; } //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_NMAHEADER_CPKS(const uint8_t nmaHeader) { return (nmaHeader >> 5) & 0x07; } //!< @todo documentation +inline const char * UBX_SEC_OSNMA_V3_NMAHEADER_CPKS_STR(const uint8_t nmaHeader) { return types::IxToStr(UBX_SEC_OSNMA_V3_NMAHEADER_CPKS(nmaHeader), "NOTAPPLICABLE", "NOMINAL", "EOC", "CREV", "NPK", "PKREV", "NMT", "AM"); } //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_NMAHEADER_CPKS_NOTAPPLICABLE = 0; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_NMAHEADER_CPKS_NOMINAL = 1; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_NMAHEADER_CPKS_EOC = 2; //!< @todo documentation @@ -2817,6 +2897,7 @@ static constexpr uint8_t UBX_SEC_OSNMA_V3_NMAHEADER_CPKS_AM static constexpr bool UBX_SEC_OSNMA_V3_OSNMAMONITORING_OSNMAENABLED(const uint16_t osnmaMonitoring) { return (osnmaMonitoring & 0x0001) == 0x0001; } //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_OSNMAMONITORING_NUMBERSVS(const uint16_t osnmaMonitoring) { return (osnmaMonitoring >> 1) & 0x1f; } //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_OSNMAMONITORING_NMAHEADERUPDATE(const uint16_t osnmaMonitoring) { return (osnmaMonitoring >> 6) & 0x03; } //!< @todo documentation +inline const char * UBX_SEC_OSNMA_V3_OSNMAMONITORING_NMAHEADERUPDATE_STR(const uint16_t osnmaMonitoring) { return types::IxToStr(UBX_SEC_OSNMA_V3_OSNMAMONITORING_NMAHEADERUPDATE(osnmaMonitoring), "SAME", "HEALTHY", "PROBLEM"); } //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_OSNMAMONITORING_NMAHEADERUPDATE_SAME = 0; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_OSNMAMONITORING_NMAHEADERUPDATE_HEALTHY = 1; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_OSNMAMONITORING_NMAHEADERUPDATE_PROBLEM = 2; //!< @todo documentation @@ -2826,12 +2907,14 @@ static constexpr bool UBX_SEC_OSNMA_V3_OSNMAMONITORING_WRONGFLXMAC(const static constexpr bool UBX_SEC_OSNMA_V3_OSNMAMONITORING_WRONGMACLT(const uint16_t osnmaMonitoring) { return (osnmaMonitoring & 0x0800) == 0x0800; } //!< @todo documentation static constexpr bool UBX_SEC_OSNMA_V3_TIMSYNCREQ_TIMSYNCENABLED(const uint8_t timSyncReq) { return (timSyncReq & 0x01) == 0x01; } //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_TIMSYNCREQ_TIMSYNCSTATUS(const uint8_t timSyncReq) { return (timSyncReq >> 1) & 0x07; } //!< @todo documentation +inline const char * UBX_SEC_OSNMA_V3_TIMSYNCREQ_TIMSYNCSTATUS_STR(const uint8_t timSyncReq) { return types::IxToStr(UBX_SEC_OSNMA_V3_TIMSYNCREQ_TIMSYNCSTATUS(timSyncReq), "NOTPERFORMED", "NOTRUSTEDTIME", "NOTACCURATE", "PASSED", "FAILED"); } //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_TIMSYNCREQ_TIMSYNCSTATUS_NOTPERFORMED = 0; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_TIMSYNCREQ_TIMSYNCSTATUS_NOTRUSTEDTIME = 1; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_TIMSYNCREQ_TIMSYNCSTATUS_NOTACCURATE = 2; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_TIMSYNCREQ_TIMSYNCSTATUS_PASSED = 3; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_TIMSYNCREQ_TIMSYNCSTATUS_FAILED = 4; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_DSMAUTHENTICATION_DSMAUTHENTICATIONSTATUS(const uint32_t dsmAuthentication) { return dsmAuthentication & 0x0000003f; } //!< @todo documentation +inline const char * UBX_SEC_OSNMA_V3_DSMAUTHENTICATION_DSMAUTHENTICATIONSTATUS_STR(const uint32_t dsmAuthentication) { return types::IxToStr(UBX_SEC_OSNMA_V3_DSMAUTHENTICATION_DSMAUTHENTICATIONSTATUS(dsmAuthentication), "NONE", "KROOT", "PKR", "ALERT", "KROOTFAILED", "PKRFAILED", "UNKNOWNPUBKEY", "DECOMPRESSFAILED", "UNSUPPORTEDCONFIG", "MISSINGMERKLEROOT"); } //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_DSMAUTHENTICATION_DSMAUTHENTICATIONSTATUS_NONE = 0; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_DSMAUTHENTICATION_DSMAUTHENTICATIONSTATUS_KROOT = 1; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_DSMAUTHENTICATION_DSMAUTHENTICATIONSTATUS_PKR = 2; //!< @todo documentation @@ -2850,6 +2933,7 @@ static constexpr uint8_t UBX_SEC_OSNMA_V3_DSMAUTHENTICATION_KEYSIZE(const ui static constexpr uint8_t UBX_SEC_OSNMA_V3_DSMAUTHENTICATION_MACSIZE(const uint32_t dsmAuthentication) { return (dsmAuthentication >> 26) & 0x0f; } //!< @todo documentation static constexpr bool UBX_SEC_OSNMA_V3_DSMAUTHENTICATION_FROMNVS(const uint32_t dsmAuthentication) { return (dsmAuthentication & 0x40000000) == 0x40000000; } //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_TESLAKEY_TESLAKEYAUTHSTATUS(const uint32_t teslaKey) { return teslaKey & 0x00000007; } //!< @todo documentation +inline const char * UBX_SEC_OSNMA_V3_TESLAKEY_TESLAKEYAUTHSTATUS_STR(const uint32_t teslaKey) { return types::IxToStr(UBX_SEC_OSNMA_V3_TESLAKEY_TESLAKEYAUTHSTATUS(teslaKey), "NONE", "AUTHENTICATED", "FAILED", "ONGOING", "KEYINPAST", "ROOTKEYTOOOLD"); } //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_TESLAKEY_TESLAKEYAUTHSTATUS_NONE = 0; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_TESLAKEY_TESLAKEYAUTHSTATUS_AUTHENTICATED = 1; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_TESLAKEY_TESLAKEYAUTHSTATUS_FAILED = 2; //!< @todo documentation @@ -2863,27 +2947,33 @@ static constexpr uint8_t UBX_SEC_OSNMA_V3_TESLAKEY_CHAINID(const uint32_t te static constexpr uint8_t UBX_SEC_OSNMA_V3_GENERALANDTIMING_AUTHSVS(const uint32_t generalAndTiming) { return generalAndTiming & 0x0000003f; } //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_GENERALANDTIMING_AUTHNUMTIM(const uint32_t generalAndTiming) { return (generalAndTiming >> 6) & 0x3f; } //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_GENERALANDTIMING_TIMINGAUTHRESULT(const uint32_t generalAndTiming) { return (generalAndTiming >> 12) & 0x03; } //!< @todo documentation +inline const char * UBX_SEC_OSNMA_V3_GENERALANDTIMING_TIMINGAUTHRESULT_STR(const uint32_t generalAndTiming) { return types::IxToStr(UBX_SEC_OSNMA_V3_GENERALANDTIMING_TIMINGAUTHRESULT(generalAndTiming), "NONE", "AUTHENTICATED", "FAILED"); } //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_GENERALANDTIMING_TIMINGAUTHRESULT_NONE = 0; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_GENERALANDTIMING_TIMINGAUTHRESULT_AUTHENTICATED = 1; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_GENERALANDTIMING_TIMINGAUTHRESULT_FAILED = 2; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_GENERALANDTIMING_MACADKDTYPE(const uint32_t generalAndTiming) { return (generalAndTiming >> 14) & 0x01; } //!< @todo documentation +inline const char * UBX_SEC_OSNMA_V3_GENERALANDTIMING_MACADKDTYPE_STR(const uint32_t generalAndTiming) { return types::IxToStr(UBX_SEC_OSNMA_V3_GENERALANDTIMING_MACADKDTYPE(generalAndTiming), "FAST", "SLOW"); } //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_GENERALANDTIMING_MACADKDTYPE_FAST = 0; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_GENERALANDTIMING_MACADKDTYPE_SLOW = 1; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_GENERALANDTIMING_PUBKEYSRC(const uint32_t generalAndTiming) { return (generalAndTiming >> 15) & 0x03; } //!< @todo documentation +inline const char * UBX_SEC_OSNMA_V3_GENERALANDTIMING_PUBKEYSRC_STR(const uint32_t generalAndTiming) { return types::IxToStr(UBX_SEC_OSNMA_V3_GENERALANDTIMING_PUBKEYSRC(generalAndTiming), "FACTORY", "SATELLITES", "AIDED", "NVS"); } //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_GENERALANDTIMING_PUBKEYSRC_FACTORY = 0; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_GENERALANDTIMING_PUBKEYSRC_SATELLITES = 1; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_GENERALANDTIMING_PUBKEYSRC_AIDED = 2; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_GENERALANDTIMING_PUBKEYSRC_NVS = 3; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_GENERALANDTIMING_MERKLEROOTSRC(const uint32_t generalAndTiming) { return (generalAndTiming >> 17) & 0x03; } //!< @todo documentation +inline const char * UBX_SEC_OSNMA_V3_GENERALANDTIMING_MERKLEROOTSRC_STR(const uint32_t generalAndTiming) { return types::IxToStr(UBX_SEC_OSNMA_V3_GENERALANDTIMING_MERKLEROOTSRC(generalAndTiming), "FACTORY", "?", "AIDED", "NVS"); } //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_GENERALANDTIMING_MERKLEROOTSRC_FACTORY = 0; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_GENERALANDTIMING_MERKLEROOTSRC_AIDED = 2; //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_GENERALANDTIMING_MERKLEROOTSRC_NVS = 3; //!< @todo documentation static constexpr bool UBX_SEC_OSNMA_V3_GENERALANDTIMING_MERKLEROOTVAL(const uint32_t generalAndTiming) { return (generalAndTiming & 0x00080000) == 0x00080000; } //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_GENERALANDTIMING_FUTUREMERKLEROOTSRC(const uint32_t generalAndTiming) { return (generalAndTiming >> 20) & 0x03; } //!< @todo documentation +inline const char * UBX_SEC_OSNMA_V3_GENERALANDTIMING_FUTUREMERKLEROOTSRC_STR(const uint32_t generalAndTiming) { return types::IxToStr(UBX_SEC_OSNMA_V3_GENERALANDTIMING_FUTUREMERKLEROOTSRC(generalAndTiming), "FACTORY", "?", "AIDED", "NVS"); } //!< @todo documentation static constexpr bool UBX_SEC_OSNMA_V3_GENERALANDTIMING_FUTUREMERKLEROOTVAL(const uint32_t generalAndTiming) { return (generalAndTiming & 0x00400000) == 0x00400000; } //!< @todo documentation static constexpr bool UBX_SEC_OSNMA_V3_GENERALANDTIMING_PUBKEYVAL(const uint32_t generalAndTiming) { return (generalAndTiming & 0x00800000) == 0x00800000; } //!< @todo documentation static constexpr bool UBX_SEC_OSNMA_V3_GENERALANDTIMING_FUTUREPUBKEYVAL(const uint32_t generalAndTiming) { return (generalAndTiming & 0x01000000) == 0x01000000; } //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_GENERALANDTIMING_FUTUREPUBKEYSRC(const uint32_t generalAndTiming) { return (generalAndTiming >> 25) & 0x03; } //!< @todo documentation +inline const char * UBX_SEC_OSNMA_V3_GENERALANDTIMING_FUTUREPUBKEYSRC_STR(const uint32_t generalAndTiming) { return types::IxToStr(UBX_SEC_OSNMA_V3_GENERALANDTIMING_FUTUREPUBKEYSRC(generalAndTiming), "FACTORY", "SATELLITES", "AIDED", "NVS"); } //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_GENERALANDTIMING_FUTUREPUBKEYID(const uint32_t generalAndTiming) { return (generalAndTiming >> 27) & 0x0f; } //!< @todo documentation static constexpr uint16_t UBX_SEC_OSNMA_V3_GROUP1_BITFIELD1_IODE(const uint16_t bitfield1) { return bitfield1 & 0x03ff; } //!< @todo documentation static constexpr uint8_t UBX_SEC_OSNMA_V3_GROUP1_BITFIELD1_AUTHNUM(const uint16_t bitfield1) { return (bitfield1 >> 10) & 0x1f; } //!< @todo documentation @@ -2946,13 +3036,16 @@ static_assert(sizeof(UBX_TIM_TM2_V0_GROUP0) == 28, ""); // clang-format off static constexpr std::size_t UBX_TIM_TM2_V0_SIZE = sizeof(UBX_TIM_TM2_V0_GROUP0) + UBX_FRAME_SIZE; //!< @todo documentation static constexpr uint8_t UBX_TIM_TM2_V0_FLAGS_MODE(const uint8_t flags) { return flags & 0x01; } //!< @todo documentation +inline const char * UBX_TIM_TM2_V0_FLAGS_MODE_STR(const uint8_t flags) { return types::IxToStr(UBX_TIM_TM2_V0_FLAGS_MODE(flags), "SINGLE", "RUNNING"); } //!< @todo documentation static constexpr uint8_t UBX_TIM_TM2_V0_FLAGS_MODE_SINGLE = 0; //!< @todo documentation static constexpr uint8_t UBX_TIM_TM2_V0_FLAGS_MODE_RUNNING = 1; //!< @todo documentation static constexpr uint8_t UBX_TIM_TM2_V0_FLAGS_RUN(const uint8_t flags) { return (flags >> 1) & 0x01; } //!< @todo documentation +inline const char * UBX_TIM_TM2_V0_FLAGS_RUN_STR(const uint8_t flags) { return types::IxToStr(UBX_TIM_TM2_V0_FLAGS_RUN(flags), "ARMED", "STOPPED"); } //!< @todo documentation static constexpr uint8_t UBX_TIM_TM2_V0_FLAGS_RUN_ARMED = 0; //!< @todo documentation static constexpr uint8_t UBX_TIM_TM2_V0_FLAGS_RUN_STOPPED = 1; //!< @todo documentation static constexpr bool UBX_TIM_TM2_V0_FLAGS_NEWFALLINGEDGE(const uint8_t flags) { return (flags & 0x04) == 0x04; } //!< @todo documentation static constexpr uint8_t UBX_TIM_TM2_V0_FLAGS_TIMEBASE(const uint8_t flags) { return (flags >> 3) & 0x03; } //!< @todo documentation +inline const char * UBX_TIM_TM2_V0_FLAGS_TIMEBASE_STR(const uint8_t flags) { return types::IxToStr(UBX_TIM_TM2_V0_FLAGS_TIMEBASE(flags), "RX", "GNSS", "UTC"); } //!< @todo documentation static constexpr uint8_t UBX_TIM_TM2_V0_FLAGS_TIMEBASE_RX = 0; //!< @todo documentation static constexpr uint8_t UBX_TIM_TM2_V0_FLAGS_TIMEBASE_GNSS = 1; //!< @todo documentation static constexpr uint8_t UBX_TIM_TM2_V0_FLAGS_TIMEBASE_UTC = 2; //!< @todo documentation @@ -2990,10 +3083,12 @@ static constexpr double UBX_TIM_TP_V0_TOWMS_SCALE static constexpr double UBX_TIM_TP_V0_TOWSUBMS_SCALE = 0x1.0624dd2f1a9fcp-42; //!< perl -e 'printf "%a", 2**-32 * 1e-3' static constexpr double UBX_TIM_TP_V0_TOWSUBMS_SCALE_APPROX = 2.3283064365386963e-18; //!< perl -e 'printf "%.18g", 2**-32 * 1e-8' static constexpr uint8_t UBX_TIM_TP_V0_FLAGS_TIMEBASE(const uint8_t flags) { return flags & 0x01; } //!< @todo documentation +inline const char * UBX_TIM_TP_V0_FLAGS_TIMEBASE_STR(const uint8_t flags) { return types::IxToStr(UBX_TIM_TP_V0_FLAGS_TIMEBASE(flags), "GNSS", "UTC"); } //!< @todo documentation static constexpr uint8_t UBX_TIM_TP_V0_FLAGS_TIMEBASE_GNSS = 0; //!< @todo documentation static constexpr uint8_t UBX_TIM_TP_V0_FLAGS_TIMEBASE_UTC = 1; //!< @todo documentation static constexpr bool UBX_TIM_TP_V0_FLAGS_UTC(const uint8_t flags) { return (flags & 0x02) == 0x02; } //!< @todo documentation static constexpr uint8_t UBX_TIM_TP_V0_FLAGS_RAIM(const uint8_t flags) { return (flags >> 2) & 0x03; } //!< @todo documentation +inline const char * UBX_TIM_TP_V0_FLAGS_RAIM_STR(const uint8_t flags) { return types::IxToStr(UBX_TIM_TP_V0_FLAGS_RAIM(flags), "NA", "INACTIVE", "ACTIVE"); } //!< @todo documentation static constexpr uint8_t UBX_TIM_TP_V0_FLAGS_RAIM_NA = 0; //!< @todo documentation static constexpr uint8_t UBX_TIM_TP_V0_FLAGS_RAIM_INACTIVE = 1; //!< @todo documentation static constexpr uint8_t UBX_TIM_TP_V0_FLAGS_RAIM_ACTIVE = 2; //!< @todo documentation @@ -3006,6 +3101,8 @@ static constexpr uint8_t UBX_TIM_TP_V0_REFINFO_TIMEREFGNSS_BDS static constexpr uint8_t UBX_TIM_TP_V0_REFINFO_TIMEREFGNSS_GAL = 3; //!< @todo documentation static constexpr uint8_t UBX_TIM_TP_V0_REFINFO_TIMEREFGNSS_NAVIC = 4; //!< @todo documentation static constexpr uint8_t UBX_TIM_TP_V0_REFINFO_TIMEREFGNSS_UNKNOWN = 15; //!< @todo documentation +inline const char * UBX_TIM_TP_V0_REFINFO_TIMEREFGNSS_STR(const uint8_t refInfo) { return UBX_TIM_TP_V0_REFINFO_TIMEREFGNSS(refInfo) == UBX_TIM_TP_V0_REFINFO_TIMEREFGNSS_UNKNOWN ? "UNKNOWN" : \ + types::IxToStr(UBX_TIM_TP_V0_REFINFO_TIMEREFGNSS(refInfo), "GPS", "GLO", "BDS", "GAL", "NAVIC"); } //!< @todo documentation static constexpr uint8_t UBX_TIM_TP_V0_REFINFO_UTCSTANDARD(const uint8_t refInfo) { return (refInfo >> 4) & 0x0f; } //!< @todo documentation static constexpr uint8_t UBX_TIM_TP_V0_REFINFO_UTCSTANDARD_INFONA = 0; //!< @todo documentation static constexpr uint8_t UBX_TIM_TP_V0_REFINFO_UTCSTANDARD_CRL = 1; //!< @todo documentation @@ -3017,6 +3114,8 @@ static constexpr uint8_t UBX_TIM_TP_V0_REFINFO_UTCSTANDARD_SU static constexpr uint8_t UBX_TIM_TP_V0_REFINFO_UTCSTANDARD_NTSC = 7; //!< @todo documentation static constexpr uint8_t UBX_TIM_TP_V0_REFINFO_UTCSTANDARD_NPLI = 8; //!< @todo documentation static constexpr uint8_t UBX_TIM_TP_V0_REFINFO_UTCSTANDARD_UNNOWN = 15; //!< @todo documentation +inline const char * UBX_TIM_TP_V0_REFINFO_UTCSTANDARD_STR(const uint8_t refInfo) { return UBX_TIM_TP_V0_REFINFO_UTCSTANDARD(refInfo) == UBX_TIM_TP_V0_REFINFO_UTCSTANDARD_UNNOWN ? "UNNOWN" : \ + types::IxToStr(UBX_TIM_TP_V0_REFINFO_UTCSTANDARD(refInfo), "INFONA", "CRL", "NIST", "USNO", "BIPM", "EU", "SU", "NTSC", "NPLI"); } //!< @todo documentation // clang-format on ///@} diff --git a/fpsdk_common/include/fpsdk_common/to_json/parser.hpp b/fpsdk_common/include/fpsdk_common/to_json/parser.hpp index 825f34e..13e52f9 100644 --- a/fpsdk_common/include/fpsdk_common/to_json/parser.hpp +++ b/fpsdk_common/include/fpsdk_common/to_json/parser.hpp @@ -20,6 +20,11 @@ /* PACKAGE */ #include "../parser/types.hpp" +#include "../string.hpp" +#include "parser_fpa.hpp" +#include "parser_fpb.hpp" +#include "parser_nmea.hpp" +#include "parser_ubx.hpp" #ifndef _DOXYGEN_ // not documenting these /* ****************************************************************************************************************** */ @@ -31,6 +36,7 @@ inline void to_json(nlohmann::json& j, const ParserMsg& m) { "_proto", ProtocolStr(m.proto_) }, { "_name", m.name_ }, { "_seq", m.seq_ }, + { "_size", m.data_.size() }, }); if (!m.info_.empty()) { @@ -47,6 +53,25 @@ inline void to_json(nlohmann::json& j, const ParserMsg& m) } } +inline nlohmann::json ParserMsgToJson(const ParserMsg& m) +{ + nlohmann::json j = m; + switch (m.proto_) { // clang-format off + case Protocol::FP_A: j.update(fpa::FpaDecodeMessage(m.data_)); break; + case Protocol::FP_B: j.update(fpb::to_json_FP_B(m)); break; + case Protocol::NMEA: j.update(nmea::NmeaDecodeMessage(m.data_)); break; + case Protocol::UBX: j.update(ubx::to_json_UBX(m)); break; + case Protocol::RTCM3: + case Protocol::UNI_B: + case Protocol::NOV_B: + case Protocol::SBF: + case Protocol::QGC: + case Protocol::SPARTN: + case Protocol::OTHER: break; + } // clang-format on + return j; +} + // --------------------------------------------------------------------------------------------------------------------- inline void to_json(nlohmann::json& j, const ParserStats s) diff --git a/fpsdk_common/include/fpsdk_common/to_json/nmea.hpp b/fpsdk_common/include/fpsdk_common/to_json/parser_nmea.hpp similarity index 100% rename from fpsdk_common/include/fpsdk_common/to_json/nmea.hpp rename to fpsdk_common/include/fpsdk_common/to_json/parser_nmea.hpp diff --git a/fpsdk_common/include/fpsdk_common/to_json/parser_ubx.hpp b/fpsdk_common/include/fpsdk_common/to_json/parser_ubx.hpp new file mode 100644 index 0000000..56e9772 --- /dev/null +++ b/fpsdk_common/include/fpsdk_common/to_json/parser_ubx.hpp @@ -0,0 +1,1582 @@ +/** + * \verbatim + * ___ ___ + * \ \ / / + * \ \/ / Copyright (c) Fixposition AG (www.fixposition.com) and contributors + * / /\ \ License: see the LICENSE file + * /__/ \__\ + * \endverbatim + * + * @file + * @brief Fixposition SDK: to_json() helpers for some fpsdk::common::parser::ubx messages + */ +#ifndef __FPSDK_COMMON_TO_JSON_PARSER_UBX_HPP__ +#define __FPSDK_COMMON_TO_JSON_PARSER_UBX_HPP__ + +/* LIBC/STL */ +#include +#include +#include + +/* EXTERNAL */ +#include + +/* PACKAGE */ +#include "../parser/ubx.hpp" +#include "../string.hpp" +#include "../types.hpp" + +#ifndef _DOXYGEN_ // not documenting these +/* ****************************************************************************************************************** */ +namespace fpsdk::common::parser::ubx { + +// UBX-ACK-ACK (ack_or_nak = true) and UBX-ACK-NAK (ack_or_nak = false), which have the same payload +inline void to_json_UBX_ACK(nlohmann::json& j, const std::vector& data, const bool ack_or_nak) +{ + if (data.size() != (ack_or_nak ? UBX_ACK_ACK_V0_SIZE : UBX_ACK_NAK_V0_SIZE)) { + return; + } + UBX_ACK_ACK_V0_GROUP0 ack; + std::memcpy(&ack, &data[UBX_HEAD_SIZE], sizeof(ack)); + j = nlohmann::json::object({ + { "clsId", ack.clsId }, + { "msgId", ack.msgId }, + }); + + // Name of the ack'ed message + const uint8_t msg[UBX_FRAME_SIZE] = { UBX_SYNC_1, UBX_SYNC_2, ack.clsId, ack.msgId, 0, 0, 0, 0 }; + char name[MAX_NAME_SIZE]; + if (UbxGetMessageName(name, sizeof(name), msg, sizeof(msg))) { + j["msgName"] = name; + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_CFG_CFG(nlohmann::json& j, const std::vector& data) +{ + if ((data.size() != UBX_CFG_CFG_V0_MIN_SIZE) && (data.size() != UBX_CFG_CFG_V0_MAX_SIZE)) { + return; + } + UBX_CFG_CFG_V0_GROUP0 cfg; + std::memcpy(&cfg, &data[UBX_HEAD_SIZE], sizeof(cfg)); + j = nlohmann::json::object({ + { "clearMask", cfg.clearMask }, + { "saveMask", cfg.saveMask }, + { "loadMask", cfg.loadMask }, + }); + + if (data.size() == UBX_CFG_CFG_V0_MAX_SIZE) { + UBX_CFG_CFG_V0_GROUP1 dev; + std::memcpy(&dev, &data[UBX_HEAD_SIZE + sizeof(cfg)], sizeof(dev)); + j["deviceBbr"] = (dev.deviceMask & UBX_CFG_CFG_V0_DEVICE_BBR) != 0; + j["deviceFlash"] = (dev.deviceMask & UBX_CFG_CFG_V0_DEVICE_FLASH) != 0; + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_CFG_RST(nlohmann::json& j, const std::vector& data) +{ + if (data.size() == UBX_CFG_RST_V0_SIZE) { + UBX_CFG_RST_V0_GROUP0 rst; + std::memcpy(&rst, &data[UBX_HEAD_SIZE], sizeof(rst)); + j = nlohmann::json::object({ + { "navBbrMask", rst.navBbrMask }, + { "resetMode", UBX_CFG_RST_V0_RESETMODE_STR(rst.resetMode) }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_CFG_VALDEL(nlohmann::json& j, const std::vector& data) +{ + if ((data.size() < UBX_CFG_VALDEL_V1_MIN_SIZE) || + (UBX_CFG_VALDEL_VERSION(data.data()) != UBX_CFG_VALDEL_V1_VERSION)) { + return; + } + UBX_CFG_VALDEL_V1_GROUP0 head; + std::memcpy(&head, &data[UBX_HEAD_SIZE], sizeof(head)); + const std::size_t offs = UBX_HEAD_SIZE + sizeof(head); + const std::size_t size = data.size() - UBX_CFG_VALDEL_V1_MIN_SIZE; + j = nlohmann::json::object({ + { "version", head.version }, + { "layerBbr", (head.layers & UBX_CFG_VALDEL_V1_LAYER_BBR) != 0 }, + { "layerFlash", (head.layers & UBX_CFG_VALDEL_V1_LAYER_FLASH) != 0 }, + { "transaction", UBX_CFG_VALDEL_V1_TRANSACTION_STR(head.transaction) }, + { "keys", string::Base64Enc(std::vector(data.cbegin() + offs, data.cbegin() + offs + size)) }, + }); +} + +// --------------------------------------------------------------------------------------------------------------------- + +// UBX-CFG-VALGET version 0 is the poll request (a list of keys), version 1 is the response (a list of key-value pairs) +inline void to_json_UBX_CFG_VALGET(nlohmann::json& j, const std::vector& data) +{ + if (data.size() < UBX_CFG_VALGET_V0_MIN_SIZE) { + return; + } + if (UBX_CFG_VALGET_VERSION(data.data()) == UBX_CFG_VALGET_V0_VERSION) { + UBX_CFG_VALGET_V0_GROUP0 head; + std::memcpy(&head, &data[UBX_HEAD_SIZE], sizeof(head)); + const std::size_t offs = UBX_HEAD_SIZE + sizeof(head); + const std::size_t size = data.size() - UBX_CFG_VALGET_V0_MIN_SIZE; + j = nlohmann::json::object({ + { "version", head.version }, + { "layer", UBX_CFG_VALGET_V0_LAYER_STR(head.layer) }, + { "position", head.position }, + { "keys", string::Base64Enc(std::vector(data.cbegin() + offs, data.cbegin() + offs + size)) }, + }); + } else if (UBX_CFG_VALGET_VERSION(data.data()) == UBX_CFG_VALGET_V1_VERSION) { + UBX_CFG_VALGET_V1_GROUP0 head; + std::memcpy(&head, &data[UBX_HEAD_SIZE], sizeof(head)); + const std::size_t offs = UBX_HEAD_SIZE + sizeof(head); + const std::size_t size = data.size() - UBX_CFG_VALGET_V1_MIN_SIZE; + j = nlohmann::json::object({ + { "version", head.version }, + { "layer", UBX_CFG_VALGET_V1_LAYER_STR(head.layer) }, + { "position", head.position }, + { "cfgData", string::Base64Enc(std::vector(data.cbegin() + offs, data.cbegin() + offs + size)) }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_CFG_VALSET(nlohmann::json& j, const std::vector& data) +{ + if (data.size() < UBX_CFG_VALSET_V0_MIN_SIZE) { + return; + } + if (UBX_CFG_VALSET_VERSION(data.data()) == UBX_CFG_VALSET_V0_VERSION) { + UBX_CFG_VALSET_V0_GROUP0 head; + std::memcpy(&head, &data[UBX_HEAD_SIZE], sizeof(head)); + const std::size_t offs = UBX_HEAD_SIZE + sizeof(head); + const std::size_t size = data.size() - UBX_CFG_VALSET_V0_MIN_SIZE; + j = nlohmann::json::object({ + { "version", head.version }, + { "layerRam", (head.layers & UBX_CFG_VALSET_V0_LAYERS_RAM) != 0 }, + { "layerBbr", (head.layers & UBX_CFG_VALSET_V0_LAYERS_BBR) != 0 }, + { "layerFlash", (head.layers & UBX_CFG_VALSET_V0_LAYERS_FLASH) != 0 }, + { "cfgData", string::Base64Enc(std::vector(data.cbegin() + offs, data.cbegin() + offs + size)) }, + }); + } else if (UBX_CFG_VALSET_VERSION(data.data()) == UBX_CFG_VALSET_V1_VERSION) { + UBX_CFG_VALSET_V1_GROUP0 head; + std::memcpy(&head, &data[UBX_HEAD_SIZE], sizeof(head)); + const std::size_t offs = UBX_HEAD_SIZE + sizeof(head); + const std::size_t size = data.size() - UBX_CFG_VALSET_V1_MIN_SIZE; + j = nlohmann::json::object({ + { "version", head.version }, + { "layerRam", (head.layers & UBX_CFG_VALSET_V1_LAYER_RAM) != 0 }, + { "layerBbr", (head.layers & UBX_CFG_VALSET_V1_LAYER_BBR) != 0 }, + { "layerFlash", (head.layers & UBX_CFG_VALSET_V1_LAYER_FLASH) != 0 }, + { "transaction", UBX_CFG_VALSET_V1_TRANSACTION_STR(head.transaction) }, + { "cfgData", string::Base64Enc(std::vector(data.cbegin() + offs, data.cbegin() + offs + size)) }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_ESF_MEAS(nlohmann::json& j, const std::vector& data) +{ + if ((data.size() < UBX_ESF_MEAS_V0_MIN_SIZE) || (data.size() != UBX_ESF_MEAS_V0_SIZE(data.data()))) { + return; + } + UBX_ESF_MEAS_V0_GROUP0 head; + std::memcpy(&head, &data[UBX_HEAD_SIZE], sizeof(head)); + + const std::size_t num_meas = UBX_ESF_MEAS_V0_FLAGS_NUMMEAS(head.flags); + std::size_t offs = UBX_HEAD_SIZE + sizeof(head); + auto meas = nlohmann::json::array(); + for (std::size_t ix = 0; ix < num_meas; ix++, offs += sizeof(UBX_ESF_MEAS_V0_GROUP1)) { + UBX_ESF_MEAS_V0_GROUP1 m; + std::memcpy(&m, &data[offs], sizeof(m)); + meas.push_back(nlohmann::json::object({ + { "dataType", UBX_ESF_MEAS_V0_DATA_DATATYPE(m.data) }, + { "dataField", UBX_ESF_MEAS_V0_DATA_DATAFIELD(m.data) }, + })); + } + + j = nlohmann::json::object({ + { "timeTag", head.timeTag }, + { "id", head.id }, + { "timeMarkSent", UBX_ESF_MEAS_V0_FLAGS_TIMEMARKSENT_STR(head.flags) }, + { "calibTtagValid", UBX_ESF_MEAS_V0_FLAGS_CALIBTTAGVALID(head.flags) }, + { "numMeas", UBX_ESF_MEAS_V0_FLAGS_NUMMEAS(head.flags) }, + { "meas", meas }, + }); + + if (UBX_ESF_MEAS_V0_FLAGS_CALIBTTAGVALID(head.flags)) { + UBX_ESF_MEAS_V0_GROUP2 g2; + std::memcpy(&g2, &data[offs], sizeof(g2)); + j["calibTtag"] = g2.calibTtag; + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_ESF_STATUS(nlohmann::json& j, const std::vector& data) +{ + if ((data.size() < UBX_ESF_STATUS_V2_MIN_SIZE) || + (UBX_ESF_STATUS_VERSION(data.data()) != UBX_ESF_STATUS_V2_VERSION)) { + return; + } + UBX_ESF_STATUS_V2_GROUP0 head; + std::memcpy(&head, &data[UBX_HEAD_SIZE], sizeof(head)); + if (data.size() != (UBX_ESF_STATUS_V2_MIN_SIZE + (head.numSens * sizeof(UBX_ESF_STATUS_V2_GROUP1)))) { + return; + } + std::size_t offs = UBX_HEAD_SIZE + sizeof(head); + auto sens = nlohmann::json::array(); + for (std::size_t ix = 0; ix < head.numSens; ix++, offs += sizeof(UBX_ESF_STATUS_V2_GROUP1)) { + UBX_ESF_STATUS_V2_GROUP1 s; + std::memcpy(&s, &data[offs], sizeof(s)); + sens.push_back(nlohmann::json::object({ + { "type", UBX_ESF_STATUS_V2_SENSSTATUS1_TYPE(s.sensStatus1) }, + { "used", (s.sensStatus1 & UBX_ESF_STATUS_V2_SENSSTATUS1_USED) != 0 }, + { "ready", (s.sensStatus1 & UBX_ESF_STATUS_V2_SENSSTATUS1_READY) != 0 }, + { "calibStatus", UBX_ESF_STATUS_V2_SENSSTATUS2_CALIBSTATUS_STR(s.sensStatus2) }, + { "timeStatus", UBX_ESF_STATUS_V2_SENSSTATUS2_TIMESTATUS_STR(s.sensStatus2) }, + { "freq", s.freq }, + { "badMeas", (s.faults & UBX_ESF_STATUS_V2_FAULTS_BADMEAS) != 0 }, + { "badTtag", (s.faults & UBX_ESF_STATUS_V2_FAULTS_BADTTAG) != 0 }, + { "missingMeas", (s.faults & UBX_ESF_STATUS_V2_FAULTS_MISSINGMEAS) != 0 }, + { "noisyMeas", (s.faults & UBX_ESF_STATUS_V2_FAULTS_NOISYMEAS) != 0 }, + })); + } + + j = nlohmann::json::object({ + { "iTOW", head.iTOW }, + { "version", head.version }, + { "numSens", head.numSens }, + { "wtInitStatus", UBX_ESF_STATUS_V2_INITSTATUS1_WTINITSTATUS_STR(head.initStatus1) }, + { "mntAlgStatus", UBX_ESF_STATUS_V2_INITSTATUS1_MNTALGSTATUS_STR(head.initStatus1) }, + { "insInitStatus", UBX_ESF_STATUS_V2_INITSTATUS1_INSINITSTATUS_STR(head.initStatus1) }, + { "imuInitStatus", UBX_ESF_STATUS_V2_INITSTATUS2_IMUINITSTATUS_STR(head.initStatus2) }, + { "fusionMode", UBX_ESF_STATUS_V2_FUSIONMODE_STR(head.fusionMode) }, + { "sens", sens }, + }); +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_MGA_GAL_OSNMA_PUBKEY(nlohmann::json& j, const std::vector& data) +{ + if (data.size() == UBX_MGA_GAL_OSNMA_PUBKEY_V0_SIZE) { + UBX_MGA_GAL_OSNMA_PUBKEY_V0_GROUP0 pk; + std::memcpy(&pk, &data[UBX_HEAD_SIZE], sizeof(pk)); + j = nlohmann::json::object({ + { "type", pk.type }, + { "version", pk.version }, + { "pubKeyId", UBX_MGA_GAL_OSNMA_PUBKEY_V0_BITFIELD0_PUBKEYID(pk.bitfield0) }, + { "pubKeyType", UBX_MGA_GAL_OSNMA_PUBKEY_V0_BITFIELD0_PUBKEYTYPE_STR(pk.bitfield0) }, + { "pubKeyPoint", + string::Base64Enc(std::vector(pk.pubKeyPoint, pk.pubKeyPoint + sizeof(pk.pubKeyPoint))) }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_MGA_GAL_OSNMA_MERKLE(nlohmann::json& j, const std::vector& data) +{ + if (data.size() == UBX_MGA_GAL_OSNMA_MERKLE_V0_SIZE) { + UBX_MGA_GAL_OSNMA_MERKLE_V0_GROUP0 mt; + std::memcpy(&mt, &data[UBX_HEAD_SIZE], sizeof(mt)); + j = nlohmann::json::object({ + { "type", mt.type }, + { "version", mt.version }, + { "applicabilityTime", UBX_MGA_GAL_OSNMA_MERKLE_V0_BITFIELD0_APPLICABILITYTIME_STR(mt.bitfield0) }, + { "treeNode", string::Base64Enc(std::vector(mt.treeNode, mt.treeNode + sizeof(mt.treeNode))) }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_MGA_INI_TIME_UTC(nlohmann::json& j, const std::vector& data) +{ + if (data.size() == UBX_MGA_INI_TIME_UTC_V0_SIZE) { + UBX_MGA_INI_TIME_UTC_V0_GROUP0 ini; + std::memcpy(&ini, &data[UBX_HEAD_SIZE], sizeof(ini)); + j = nlohmann::json::object({ + { "type", ini.type }, + { "version", ini.version }, + { "leapSecs", ini.leapSecs }, + { "year", ini.year }, + { "month", ini.month }, + { "day", ini.day }, + { "hour", ini.hour }, + { "minute", ini.minute }, + { "second", ini.second }, + { "ns", ini.ns }, + { "tAccS", ini.tAccS }, + { "tAccNs", ini.tAccNs }, + { "source", UBX_MGA_INI_TIME_UTC_V0_REF_SOURCE_STR(ini.ref) }, + { "fall", UBX_MGA_INI_TIME_UTC_V0_REF_FALL(ini.ref) }, + { "last", UBX_MGA_INI_TIME_UTC_V0_REF_LAST(ini.ref) }, + { "trustedSource", UBX_MGA_INI_TIME_UTC_V0_BITFIELD0_TRUSTEDSOURCE(ini.bitfield0) }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_MGA_INI_TIME_GNSS(nlohmann::json& j, const std::vector& data) +{ + if (data.size() == UBX_MGA_INI_TIME_GNSS_V0_SIZE) { + UBX_MGA_INI_TIME_GNSS_V0_GROUP0 ini; + std::memcpy(&ini, &data[UBX_HEAD_SIZE], sizeof(ini)); + j = nlohmann::json::object({ + { "type", ini.type }, + { "version", ini.version }, + { "week", ini.week }, + { "tow", ini.tow }, + { "ns", ini.ns }, + { "tAccS", ini.tAccS }, + { "tAccNs", ini.tAccNs }, + { "gnssId", UBX_GNSSID_STR(ini.gnssId) }, + { "source", UBX_MGA_INI_TIME_GNSS_V0_REF_SOURCE_STR(ini.ref) }, + { "fall", UBX_MGA_INI_TIME_GNSS_V0_REF_FALL(ini.ref) }, + { "last", UBX_MGA_INI_TIME_GNSS_V0_REF_LAST(ini.ref) }, + { "trustedSource", UBX_MGA_INI_TIME_GNSS_V0_BITFIELD0_TRUSTEDSOURCE(ini.bitfield0) }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_MON_COMMS(nlohmann::json& j, const std::vector& data) +{ + if ((data.size() < UBX_MON_COMMS_V0_MIN_SIZE) || (UBX_MON_COMMS_VERSION(data.data()) != UBX_MON_COMMS_V0_VERSION)) { + return; + } + UBX_MON_COMMS_V0_GROUP0 head; + std::memcpy(&head, &data[UBX_HEAD_SIZE], sizeof(head)); + if (data.size() != (UBX_MON_COMMS_V0_MIN_SIZE + (head.nPorts * sizeof(UBX_MON_COMMS_V0_GROUP1)))) { + return; + } + auto prot_ids = nlohmann::json::array(); + for (std::size_t ix = 0; ix < types::NumOf(head.protIds); ix++) { + prot_ids.push_back(UBX_MON_COMMS_V0_PROTIDS_STR(head.protIds[ix])); + } + + std::size_t offs = UBX_HEAD_SIZE + sizeof(head); + auto ports = nlohmann::json::array(); + for (std::size_t ix = 0; ix < head.nPorts; ix++, offs += sizeof(UBX_MON_COMMS_V0_GROUP1)) { + UBX_MON_COMMS_V0_GROUP1 p; + std::memcpy(&p, &data[offs], sizeof(p)); + ports.push_back(nlohmann::json::object({ + { "portId", p.portId }, + { "txPending", p.txPending }, + { "txBytes", p.txBytes }, + { "txUsage", p.txUsage }, + { "txPeakUsage", p.txPeakUsage }, + { "rxPending", p.rxPending }, + { "rxBytes", p.rxBytes }, + { "rxUsage", p.rxUsage }, + { "rxPeakUsage", p.rxPeakUsage }, + { "overrunErrors", p.overrunErrors }, + { "msgs", nlohmann::json::array({ p.msgs[0], p.msgs[1], p.msgs[2], p.msgs[3] }) }, + { "skipped", p.skipped }, + })); + } + + j = nlohmann::json::object({ + { "version", head.version }, + { "nPorts", head.nPorts }, + { "txErrorsMem", UBX_MON_COMMS_V0_TXERRORS_MEM(head.txErrors) }, + { "txErrorsAlloc", UBX_MON_COMMS_V0_TXERRORS_ALLOC(head.txErrors) }, + { "txErrorsOutputPort", UBX_MON_COMMS_V0_TXERRORS_OUTPUTPORT_STR(head.txErrors) }, + { "protIds", prot_ids }, + { "ports", ports }, + }); +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_MON_HW(nlohmann::json& j, const std::vector& data) +{ + if (data.size() == UBX_MON_HW_V0_SIZE) { + UBX_MON_HW_V0_GROUP0 hw; + std::memcpy(&hw, &data[UBX_HEAD_SIZE], sizeof(hw)); + j = nlohmann::json::object({ + { "pinSel", hw.pinSel }, + { "pinBank", hw.pinBank }, + { "pinDir", hw.pinDir }, + { "pinVal", hw.pinVal }, + { "noisePerMS", hw.noisePerMS }, + { "agcCnt", hw.agcCnt }, + { "usedMask", hw.usedMask }, + { "jamInd", hw.jamInd }, + { "pinIrq", hw.pinIrq }, + { "pullH", hw.pullH }, + { "pullL", hw.pullL }, + { "aStatus", UBX_MON_HW_V0_ASTATUS_STR(hw.aStatus) }, + { "aPower", UBX_MON_HW_V0_APOWER_STR(hw.aPower) }, + { "rtcCalib", (hw.flags & UBX_MON_HW_V0_FLAGS_RTCCALIB) != 0 }, + { "safeBoot", (hw.flags & UBX_MON_HW_V0_FLAGS_SAFEBOOT) != 0 }, + { "jammingState", UBX_MON_HW_V0_FLAGS_JAMMINGSTATE_STR(hw.flags) }, + { "xtalAbsent", (hw.flags & UBX_MON_HW_V0_FLAGS_XTALABSENT) != 0 }, + { "VP", hw.VP }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_MON_HW2(nlohmann::json& j, const std::vector& data) +{ + if (data.size() == UBX_MON_HW2_V0_SIZE) { + UBX_MON_HW2_V0_GROUP0 hw2; + std::memcpy(&hw2, &data[UBX_HEAD_SIZE], sizeof(hw2)); + j = nlohmann::json::object({ + { "ofsI", hw2.ofsI }, + { "magI", hw2.magI }, + { "ofsQ", hw2.ofsQ }, + { "magQ", hw2.magQ }, + { "lowLevCfg", hw2.lowLevCfg }, + { "postStatus", hw2.postStatus }, + { "cfgSource", UBX_MON_HW2_V0_CFGSOURCE_STR(hw2.cfgSource) }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_MON_HW3(nlohmann::json& j, const std::vector& data) +{ + if ((data.size() < UBX_MON_HW3_V0_MIN_SIZE) || (UBX_MON_HW3_VERSION(data.data()) != UBX_MON_HW3_V0_VERSION)) { + return; + } + UBX_MON_HW3_V0_GROUP0 head; + std::memcpy(&head, &data[UBX_HEAD_SIZE], sizeof(head)); + if (data.size() != (UBX_MON_HW3_V0_MIN_SIZE + (head.nPins * sizeof(UBX_MON_HW3_V0_GROUP1)))) { + return; + } + char hw_version[sizeof(head.hwVersion) + 1] = { 0 }; + std::memcpy(hw_version, head.hwVersion, sizeof(head.hwVersion)); + + std::size_t offs = UBX_HEAD_SIZE + sizeof(head); + auto pins = nlohmann::json::array(); + for (std::size_t ix = 0; ix < head.nPins; ix++, offs += sizeof(UBX_MON_HW3_V0_GROUP1)) { + UBX_MON_HW3_V0_GROUP1 p; + std::memcpy(&p, &data[offs], sizeof(p)); + // The struct is packed, so we cannot use the fields directly + const uint16_t pin_id = p.pinId; + const uint16_t pin_mask = p.pinMask; + const uint8_t vp = p.VP; + pins.push_back(nlohmann::json::object({ + { "pinId", pin_id }, + { "periphPio", UBX_MON_HW3_V0_PINMASK_PERIPHPIO_STR(pin_mask) }, + { "pinBank", UBX_MON_HW3_V0_PINMASK_PINBANK_STR(pin_mask) }, + { "direction", UBX_MON_HW3_V0_PINMASK_DIRECTION_STR(pin_mask) }, + { "value", UBX_MON_HW3_V0_PINMASK_VALUE(pin_mask) }, + { "vpManager", UBX_MON_HW3_V0_PINMASK_VPMANAGER(pin_mask) }, + { "pioIrq", UBX_MON_HW3_V0_PINMASK_PIOIRQ(pin_mask) }, + { "pioPullHigh", UBX_MON_HW3_V0_PINMASK_PIOPULLHIGH(pin_mask) }, + { "pioPullLow", UBX_MON_HW3_V0_PINMASK_PIOPULLLOW(pin_mask) }, + { "VP", vp }, + })); + } + + j = nlohmann::json::object({ + { "version", head.version }, + { "nPins", head.nPins }, + { "rtcCalib", UBX_MON_HW3_V0_FLAGS_RTCCALIB(head.flags) }, + { "safeBoot", UBX_MON_HW3_V0_FLAGS_SAFEBOOT(head.flags) }, + { "xtalAbsent", UBX_MON_HW3_V0_FLAGS_XTALABSENT(head.flags) }, + { "hwVersion", hw_version }, + { "pins", pins }, + }); +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_MON_RF(nlohmann::json& j, const std::vector& data) +{ + if ((data.size() < UBX_MON_RF_V0_MIN_SIZE) || (UBX_MON_RF_VERSION(data.data()) != UBX_MON_RF_V0_VERSION)) { + return; + } + UBX_MON_RF_V0_GROUP0 head; + std::memcpy(&head, &data[UBX_HEAD_SIZE], sizeof(head)); + if (data.size() != (UBX_MON_RF_V0_MIN_SIZE + (head.nBlocks * sizeof(UBX_MON_RF_V0_GROUP1)))) { + return; + } + + std::size_t offs = UBX_HEAD_SIZE + sizeof(head); + auto blocks = nlohmann::json::array(); + for (std::size_t ix = 0; ix < head.nBlocks; ix++, offs += sizeof(UBX_MON_RF_V0_GROUP1)) { + UBX_MON_RF_V0_GROUP1 b; + std::memcpy(&b, &data[offs], sizeof(b)); + blocks.push_back(nlohmann::json::object({ + { "blockId", b.blockId }, + { "jammingState", UBX_MON_RF_V0_FLAGS_JAMMINGSTATE_STR(b.flags) }, + { "antStatus", UBX_MON_RF_V0_ANTSTATUS_STR(b.antStatus) }, + { "antPower", UBX_MON_RF_V0_ANTPOWER_STR(b.antPower) }, + { "postStatus", b.postStatus }, + { "noisePerMS", b.noisePerMS }, + { "agcCnt", b.agcCnt }, + { "jamInd", b.jamInd }, + { "ofsI", b.ofsI }, + { "magI", b.magI }, + { "ofsQ", b.ofsQ }, + { "magQ", b.magQ }, + })); + } + + j = nlohmann::json::object({ + { "version", head.version }, + { "nBlocks", head.nBlocks }, + { "blocks", blocks }, + }); +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_MON_SPAN(nlohmann::json& j, const std::vector& data) +{ + if ((data.size() < UBX_MON_SPAN_V0_MIN_SIZE) || (UBX_MON_SPAN_VERSION(data.data()) != UBX_MON_SPAN_V0_VERSION) || + (data.size() != UBX_MON_SPAN_V0_SIZE(data.data()))) { + return; + } + UBX_MON_SPAN_V0_GROUP0 head; + std::memcpy(&head, &data[UBX_HEAD_SIZE], sizeof(head)); + + std::size_t offs = UBX_HEAD_SIZE + sizeof(head); + auto blocks = nlohmann::json::array(); + for (std::size_t ix = 0; ix < head.numRfBlocks; ix++, offs += sizeof(UBX_MON_SPAN_V0_GROUP1)) { + UBX_MON_SPAN_V0_GROUP1 b; + std::memcpy(&b, &data[offs], sizeof(b)); + auto spectrum = nlohmann::json::array(); + for (std::size_t bin = 0; bin < types::NumOf(b.spectrum); bin++) { + spectrum.push_back(b.spectrum[bin]); + } + blocks.push_back(nlohmann::json::object({ + { "span", b.span }, + { "res", b.res }, + { "center", b.center }, + { "pga", b.pga }, + { "spectrum", spectrum }, + })); + } + + j = nlohmann::json::object({ + { "version", head.version }, + { "numRfBlocks", head.numRfBlocks }, + { "blocks", blocks }, + }); +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_MON_SYS(nlohmann::json& j, const std::vector& data) +{ + if ((data.size() == UBX_MON_SYS_V1_SIZE) && (UBX_MON_SYS_VERSION(data.data()) == UBX_MON_SYS_V1_VERSION)) { + UBX_MON_SYS_V1_GROUP0 sys; + std::memcpy(&sys, &data[UBX_HEAD_SIZE], sizeof(sys)); + j = nlohmann::json::object({ + { "msgVer", sys.msgVer }, + { "cpuLoad", sys.cpuLoad }, + { "cpuLoadMax", sys.cpuLoadMax }, + { "memUsage", sys.memUsage }, + { "memUsageMax", sys.memUsageMax }, + { "ioUsage", sys.ioUsage }, + { "ioUsageMax", sys.ioUsageMax }, + { "runTime", sys.runTime }, + { "noticeCount", sys.noticeCount }, + { "warnCount", sys.warnCount }, + { "errorCount", sys.errorCount }, + { "tempValue", sys.tempValue }, + { "bootType", UBX_MON_SYS_V1_BOOTTYPE_STR(sys.bootType) }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_MON_TEMP(nlohmann::json& j, const std::vector& data) +{ + if ((data.size() == UBX_MON_TEMP_V0_SIZE) && (UBX_MON_TEMP_VERSION(data.data()) == UBX_MON_TEMP_V0_VERSION)) { + UBX_MON_TEMP_V0_GROUP0 temp; + std::memcpy(&temp, &data[UBX_HEAD_SIZE], sizeof(temp)); + j = nlohmann::json::object({ + { "version", temp.version }, + { "temperature", temp.temperature }, + { "unknown", temp.unknown }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_MON_VER(nlohmann::json& j, const std::vector& data) +{ + if ((data.size() < UBX_MON_VER_V0_MIN_SIZE) || + (((data.size() - UBX_MON_VER_V0_MIN_SIZE) % sizeof(UBX_MON_VER_V0_GROUP1)) != 0)) { + return; + } + UBX_MON_VER_V0_GROUP0 head; + std::memcpy(&head, &data[UBX_HEAD_SIZE], sizeof(head)); + char sw_version[sizeof(head.swVersion) + 1] = { 0 }; + char hw_version[sizeof(head.hwVersion) + 1] = { 0 }; + std::memcpy(sw_version, head.swVersion, sizeof(head.swVersion)); + std::memcpy(hw_version, head.hwVersion, sizeof(head.hwVersion)); + + const std::size_t num_ext = (data.size() - UBX_MON_VER_V0_MIN_SIZE) / sizeof(UBX_MON_VER_V0_GROUP1); + std::size_t offs = UBX_HEAD_SIZE + sizeof(head); + auto extensions = nlohmann::json::array(); + for (std::size_t ix = 0; ix < num_ext; ix++, offs += sizeof(UBX_MON_VER_V0_GROUP1)) { + UBX_MON_VER_V0_GROUP1 e; + std::memcpy(&e, &data[offs], sizeof(e)); + char extension[sizeof(e.extension) + 1] = { 0 }; + std::memcpy(extension, e.extension, sizeof(e.extension)); + extensions.push_back(extension); + } + + j = nlohmann::json::object({ + { "swVersion", sw_version }, + { "hwVersion", hw_version }, + { "extensions", extensions }, + }); +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_NAV_ATT(nlohmann::json& j, const std::vector& data) +{ + if ((data.size() == UBX_NAV_ATT_V0_SIZE) && (UBX_NAV_ATT_VERSION(data.data()) == UBX_NAV_ATT_V0_VERSION)) { + UBX_NAV_ATT_V0_GROUP0 att; + std::memcpy(&att, &data[UBX_HEAD_SIZE], sizeof(att)); + j = nlohmann::json::object({ + { "iTOW", att.iTOW }, + { "version", att.version }, + { "roll", att.roll }, + { "pitch", att.pitch }, + { "heading", att.heading }, + { "accRoll", att.accRoll }, + { "accPitch", att.accPitch }, + { "accHeading", att.accHeading }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_NAV_CLOCK(nlohmann::json& j, const std::vector& data) +{ + if (data.size() == UBX_NAV_CLOCK_V0_SIZE) { + UBX_NAV_CLOCK_V0_GROUP0 clock; + std::memcpy(&clock, &data[UBX_HEAD_SIZE], sizeof(clock)); + j = nlohmann::json::object({ + { "iTow", clock.iTow }, + { "clkB", clock.clkB }, + { "clkD", clock.clkD }, + { "tAcc", clock.tAcc }, + { "fAcc", clock.fAcc }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_NAV_COV(nlohmann::json& j, const std::vector& data) +{ + if ((data.size() == UBX_NAV_COV_V0_SIZE) && (UBX_NAV_COV_VERSION(data.data()) == UBX_NAV_COV_V0_VERSION)) { + UBX_NAV_COV_V0_GROUP0 cov; + std::memcpy(&cov, &data[UBX_HEAD_SIZE], sizeof(cov)); + j = nlohmann::json::object({ + { "iTOW", cov.iTOW }, + { "version", cov.version }, + { "posCovNN", cov.posCovNN }, + { "posCovNE", cov.posCovNE }, + { "posCovND", cov.posCovND }, + { "posCovEE", cov.posCovEE }, + { "posCovED", cov.posCovED }, + { "posCovDD", cov.posCovDD }, + { "velCovNN", cov.velCovNN }, + { "velCovNE", cov.velCovNE }, + { "velCovND", cov.velCovND }, + { "velCovEE", cov.velCovEE }, + { "velCovED", cov.velCovED }, + { "velCovDD", cov.velCovDD }, + { "posCovValid", cov.posCovValid != 0 }, + { "velCovValid", cov.velCovValid != 0 }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_NAV_DOP(nlohmann::json& j, const std::vector& data) +{ + if (data.size() == UBX_NAV_DOP_V0_SIZE) { + UBX_NAV_DOP_V0_GROUP0 dop; + std::memcpy(&dop, &data[UBX_HEAD_SIZE], sizeof(dop)); + // The struct is packed, so we cannot use the fields directly + j = nlohmann::json::object({ + { "iTOW", (uint32_t)dop.iTOW }, + { "gDOP", (uint16_t)dop.gDOP }, + { "pDOP", (uint16_t)dop.pDOP }, + { "tDOP", (uint16_t)dop.tDOP }, + { "vDOP", (uint16_t)dop.vDOP }, + { "hDOP", (uint16_t)dop.hDOP }, + { "nDOP", (uint16_t)dop.nDOP }, + { "eDOP", (uint16_t)dop.eDOP }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_NAV_EELL(nlohmann::json& j, const std::vector& data) +{ + if ((data.size() == UBX_NAV_EELL_V0_SIZE) && (UBX_NAV_EELL_VERSION(data.data()) == UBX_NAV_EELL_V0_VERSION)) { + UBX_NAV_EELL_V0_GROUP0 eell; + std::memcpy(&eell, &data[UBX_HEAD_SIZE], sizeof(eell)); + j = nlohmann::json::object({ + { "iTOW", eell.iTOW }, + { "version", eell.version }, + { "errEllipseOrient", eell.errEllipseOrient }, + { "errEllipseMajor", eell.errEllipseMajor }, + { "errEllipseMinor", eell.errEllipseMinor }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_NAV_EOE(nlohmann::json& j, const std::vector& data) +{ + if (data.size() == UBX_NAV_EOE_V0_SIZE) { + UBX_NAV_EOE_V0_GROUP0 eoe; + std::memcpy(&eoe, &data[UBX_HEAD_SIZE], sizeof(eoe)); + j = nlohmann::json::object({ + { "iTOW", eoe.iTOW }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_NAV_HPPOSECEF(nlohmann::json& j, const std::vector& data) +{ + if ((data.size() == UBX_NAV_HPPOSECEF_V0_SIZE) && + (UBX_NAV_HPPOSECEF_VERSION(data.data()) == UBX_NAV_HPPOSECEF_V0_VERSION)) { + UBX_NAV_HPPOSECEF_V0_GROUP0 pos; + std::memcpy(&pos, &data[UBX_HEAD_SIZE], sizeof(pos)); + j = nlohmann::json::object({ + { "version", pos.version }, + { "iTOW", pos.iTOW }, + { "ecefX", pos.ecefX }, + { "ecefY", pos.ecefY }, + { "ecefZ", pos.ecefZ }, + { "ecefXHp", pos.ecefXHp }, + { "ecefYHp", pos.ecefYHp }, + { "ecefZHp", pos.ecefZHp }, + { "pAcc", pos.pAcc }, + { "invalidEcef", UBX_NAV_HPPOSECEF_V0_FLAGS_INVALIDECEF(pos.flags) }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_NAV_HPPOSLLH(nlohmann::json& j, const std::vector& data) +{ + if ((data.size() == UBX_NAV_HPPOSLLH_V0_SIZE) && + (UBX_NAV_HPPOSLLH_VERSION(data.data()) == UBX_NAV_HPPOSLLH_V0_VERSION)) { + UBX_NAV_HPPOSLLH_V0_GROUP0 pos; + std::memcpy(&pos, &data[UBX_HEAD_SIZE], sizeof(pos)); + j = nlohmann::json::object({ + { "version", pos.version }, + { "iTOW", pos.iTOW }, + { "lon", pos.lon }, + { "lat", pos.lat }, + { "height", pos.height }, + { "hMSL", pos.hMSL }, + { "lonHp", pos.lonHp }, + { "latHp", pos.latHp }, + { "heightHp", pos.heightHp }, + { "hMSLHp", pos.hMSLHp }, + { "hAcc", pos.hAcc }, + { "vAcc", pos.vAcc }, + { "invalidLlh", (pos.flags & UBX_NAV_HPPOSLLH_V0_FLAGS_INVALIDLLH) != 0 }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_NAV_POSECEF(nlohmann::json& j, const std::vector& data) +{ + if (data.size() == UBX_NAV_POSECEF_V0_SIZE) { + UBX_NAV_POSECEF_V0_GROUP0 pos; + std::memcpy(&pos, &data[UBX_HEAD_SIZE], sizeof(pos)); + j = nlohmann::json::object({ + { "iTOW", pos.iTOW }, + { "ecefX", pos.ecefX }, + { "ecefY", pos.ecefY }, + { "ecefZ", pos.ecefZ }, + { "pAcc", pos.pAcc }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_NAV_PVT(nlohmann::json& j, const std::vector& data) +{ + if (data.size() == UBX_NAV_PVT_V1_SIZE) { + UBX_NAV_PVT_V1_GROUP0 pvt; + std::memcpy(&pvt, &data[UBX_HEAD_SIZE], sizeof(pvt)); + j = nlohmann::json::object({ + { "iTOW", pvt.iTOW }, + { "year", pvt.year }, + { "month", pvt.month }, + { "day", pvt.day }, + { "hour", pvt.hour }, + { "min", pvt.min }, + { "sec", pvt.sec }, + { "tAcc", pvt.tAcc }, + { "nano", pvt.nano }, + { "numSV", pvt.numSV }, + { "lon", pvt.lon }, + { "lat", pvt.lat }, + { "height", pvt.height }, + { "hMSL", pvt.hMSL }, + { "hAcc", pvt.hAcc }, + { "vAcc", pvt.vAcc }, + { "velN", pvt.velN }, + { "velE", pvt.velE }, + { "velD", pvt.velD }, + { "gSpeed", pvt.gSpeed }, + { "headMot", pvt.headMot }, + { "sAcc", pvt.sAcc }, + { "headAcc", pvt.headAcc }, + { "pDOP", pvt.pDOP }, + { "headVeh", pvt.headVeh }, + { "magDec", pvt.magDec }, + { "magAcc", pvt.magAcc }, + { "validDate", UBX_NAV_PVT_V1_VALID_VALIDDATE(pvt.valid) }, + { "validTime", UBX_NAV_PVT_V1_VALID_VALIDTIME(pvt.valid) }, + { "fullyResolved", UBX_NAV_PVT_V1_VALID_FULLYRESOLVED(pvt.valid) }, + { "validMag", UBX_NAV_PVT_V1_VALID_VALIDMAG(pvt.valid) }, + { "fixType", UBX_NAV_PVT_V1_FIXTYPE_STR(pvt.fixType) }, + { "gnssFixOk", UBX_NAV_PVT_V1_FLAGS_GNSSFIXOK(pvt.flags) }, + { "diffSoln", UBX_NAV_PVT_V1_FLAGS_DIFFSOLN(pvt.flags) }, + { "psmState", UBX_NAV_PVT_V1_FLAGS_PSMSTATE_STR(pvt.flags) }, + { "headVehValid", UBX_NAV_PVT_V1_FLAGS_HEADVEHVALID(pvt.flags) }, + { "carrSoln", UBX_NAV_PVT_V1_FLAGS_CARRSOLN_STR(pvt.flags) }, + { "confAvail", UBX_NAV_PVT_V1_FLAGS2_CONFAVAIL(pvt.flags2) }, + { "confDate", UBX_NAV_PVT_V1_FLAGS2_CONFDATE(pvt.flags2) }, + { "confTime", UBX_NAV_PVT_V1_FLAGS2_CONFTIME(pvt.flags2) }, + { "invalidLlh", UBX_NAV_PVT_V1_FLAGS3_INVALIDLLH(pvt.flags3) }, + { "lastCorrectionAge", UBX_NAV_PVT_V1_FLAGS3_LASTCORRECTIONAGE_STR(pvt.flags3) }, + { "authTime", UBX_NAV_PVT_V1_FLAGS3_AUTHTIME_STR(pvt.flags3) }, + { "nmaFixStatus", UBX_NAV_PVT_V1_FLAGS3_NMAFIXSTATUS_STR(pvt.flags3) }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_NAV_RELPOSNED(nlohmann::json& j, const std::vector& data) +{ + if ((data.size() == UBX_NAV_RELPOSNED_V1_SIZE) && + (UBX_NAV_RELPOSNED_VERSION(data.data()) == UBX_NAV_RELPOSNED_V1_VERSION)) { + UBX_NAV_RELPOSNED_V1_GROUP0 rel; + std::memcpy(&rel, &data[UBX_HEAD_SIZE], sizeof(rel)); + j = nlohmann::json::object({ + { "version", rel.version }, + { "refStationId", rel.refStationId }, + { "iTOW", rel.iTOW }, + { "relPosN", rel.relPosN }, + { "relPosE", rel.relPosE }, + { "relPosD", rel.relPosD }, + { "relPosLength", rel.relPosLength }, + { "relPosHeading", rel.relPosHeading }, + { "relPosHPN", rel.relPosHPN }, + { "relPosHPE", rel.relPosHPE }, + { "relPosHPD", rel.relPosHPD }, + { "relPosHPLength", rel.relPosHPLength }, + { "accN", rel.accN }, + { "accE", rel.accE }, + { "accD", rel.accD }, + { "accLength", rel.accLength }, + { "accHeading", rel.accHeading }, + { "gnssFixOk", UBX_NAV_RELPOSNED_V1_FLAGS_GNSSFIXOK(rel.flags) }, + { "diffSoln", UBX_NAV_RELPOSNED_V1_FLAGS_DIFFSOLN(rel.flags) }, + { "relPosValid", UBX_NAV_RELPOSNED_V1_FLAGS_RELPOSVALID(rel.flags) }, + { "carrSoln", UBX_NAV_RELPOSNED_V1_FLAGS_CARRSOLN_STR(rel.flags) }, + { "isMoving", UBX_NAV_RELPOSNED_V1_FLAGS_ISMOVING(rel.flags) }, + { "refPosMiss", UBX_NAV_RELPOSNED_V1_FLAGS_REFPOSMISS(rel.flags) }, + { "refObsMiss", UBX_NAV_RELPOSNED_V1_FLAGS_REFOBSMISS(rel.flags) }, + { "relPosHeadingValid", UBX_NAV_RELPOSNED_V1_FLAGS_RELPOSHEADINGVALID(rel.flags) }, + { "relPosNormalized", UBX_NAV_RELPOSNED_V1_FLAGS_RELPOSNORMALIZED(rel.flags) }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_NAV_SAT(nlohmann::json& j, const std::vector& data) +{ + if ((data.size() < UBX_NAV_SAT_V1_MIN_SIZE) || (UBX_NAV_SAT_VERSION(data.data()) != UBX_NAV_SAT_V1_VERSION)) { + return; + } + UBX_NAV_SAT_V1_GROUP0 head; + std::memcpy(&head, &data[UBX_HEAD_SIZE], sizeof(head)); + if (data.size() != (UBX_NAV_SAT_V1_MIN_SIZE + (head.numSvs * sizeof(UBX_NAV_SAT_V1_GROUP1)))) { + return; + } + + std::size_t offs = UBX_HEAD_SIZE + sizeof(head); + auto svs = nlohmann::json::array(); + for (std::size_t ix = 0; ix < head.numSvs; ix++, offs += sizeof(UBX_NAV_SAT_V1_GROUP1)) { + UBX_NAV_SAT_V1_GROUP1 s; + std::memcpy(&s, &data[offs], sizeof(s)); + svs.push_back(nlohmann::json::object({ + { "gnssId", UBX_GNSSID_STR(s.gnssId) }, + { "svId", s.svId }, + { "cno", s.cno }, + { "elev", s.elev }, + { "azim", s.azim }, + { "prRes", s.prRes }, + { "orbitSource", UBX_NAV_SAT_V1_FLAGS_ORBITSOURCE_STR(s.flags) }, + { "ephAvail", UBX_NAV_SAT_V1_FLAGS_EPHAVAIL(s.flags) }, + { "almAvail", UBX_NAV_SAT_V1_FLAGS_ALMAVAIL(s.flags) }, + { "anoAvail", UBX_NAV_SAT_V1_FLAGS_ANOAVAIL(s.flags) }, + { "aopAvail", UBX_NAV_SAT_V1_FLAGS_AOPAVAIL(s.flags) }, + })); + } + + j = nlohmann::json::object({ + { "iTOW", head.iTOW }, + { "version", head.version }, + { "numSvs", head.numSvs }, + { "svs", svs }, + }); +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_NAV_SIG(nlohmann::json& j, const std::vector& data) +{ + if ((data.size() < UBX_NAV_SIG_V0_MIN_SIZE) || (UBX_NAV_SIG_VERSION(data.data()) != UBX_NAV_SIG_V0_VERSION)) { + return; + } + UBX_NAV_SIG_V0_GROUP0 head; + std::memcpy(&head, &data[UBX_HEAD_SIZE], sizeof(head)); + if (data.size() != (UBX_NAV_SIG_V0_MIN_SIZE + (head.numSigs * sizeof(UBX_NAV_SIG_V0_GROUP1)))) { + return; + } + + std::size_t offs = UBX_HEAD_SIZE + sizeof(head); + auto sigs = nlohmann::json::array(); + for (std::size_t ix = 0; ix < head.numSigs; ix++, offs += sizeof(UBX_NAV_SIG_V0_GROUP1)) { + UBX_NAV_SIG_V0_GROUP1 s; + std::memcpy(&s, &data[offs], sizeof(s)); + sigs.push_back(nlohmann::json::object({ + { "gnssId", UBX_GNSSID_STR(s.gnssId) }, + { "svId", s.svId }, + { "sigId", UBX_SIGID_STR(s.gnssId, s.sigId) }, + { "freqId", (int)s.freqId - (int)UBX_NAV_SIG_V0_FREQID_OFFS }, + { "prRes", s.prRes }, + { "cno", s.cno }, + { "qualityInd", UBX_NAV_SIG_V0_QUALITYIND_STR(s.qualityInd) }, + { "corrSource", UBX_NAV_SIG_V0_CORRSOURCE_STR(s.corrSource) }, + { "ionoModel", UBX_NAV_SIG_V0_IONOMODEL_STR(s.ionoModel) }, + { "health", UBX_NAV_SIG_V0_SIGFLAGS_HEALTH_STR(s.sigFlags) }, + { "prSmoothed", UBX_NAV_SIG_V0_SIGFLAGS_PR_SMOOTHED(s.sigFlags) }, + { "prUsed", UBX_NAV_SIG_V0_SIGFLAGS_PR_USED(s.sigFlags) }, + { "crUsed", UBX_NAV_SIG_V0_SIGFLAGS_CR_USED(s.sigFlags) }, + { "doUsed", UBX_NAV_SIG_V0_SIGFLAGS_DO_USED(s.sigFlags) }, + { "prCorrUsed", UBX_NAV_SIG_V0_SIGFLAGS_PR_CORR_USED(s.sigFlags) }, + { "crCorrUsed", UBX_NAV_SIG_V0_SIGFLAGS_CR_CORR_USED(s.sigFlags) }, + { "doCorrUsed", UBX_NAV_SIG_V0_SIGFLAGS_DO_CORR_USED(s.sigFlags) }, + { "authStatus", UBX_NAV_SIG_V0_SIGFLAGS_AUTH_STATUS(s.sigFlags) }, + })); + } + + j = nlohmann::json::object({ + { "iTOW", head.iTOW }, + { "version", head.version }, + { "numSigs", head.numSigs }, + { "sigs", sigs }, + }); +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_NAV_STATUS(nlohmann::json& j, const std::vector& data) +{ + if (data.size() == UBX_NAV_STATUS_V0_SIZE) { + UBX_NAV_STATUS_V0_GROUP0 sta; + std::memcpy(&sta, &data[UBX_HEAD_SIZE], sizeof(sta)); + j = nlohmann::json::object({ + { "iTow", sta.iTow }, + { "ttff", sta.ttff }, + { "msss", sta.msss }, + { "gpsFix", UBX_NAV_STATUS_V0_GPSFIX_STR(sta.gpsFix) }, + { "gpsFixOk", UBX_NAV_STATUS_V0_FLAGS_GPSFIXOK(sta.flags) }, + { "diffSoln", UBX_NAV_STATUS_V0_FLAGS_DIFFSOLN(sta.flags) }, + { "wknSet", UBX_NAV_STATUS_V0_FLAGS_WKNSET(sta.flags) }, + { "towSet", UBX_NAV_STATUS_V0_FLAGS_TOWSET(sta.flags) }, + { "diffCorr", UBX_NAV_STATUS_V0_FIXSTAT_DIFFCORR(sta.fixStat) }, + { "carrSolnValid", UBX_NAV_STATUS_V0_FIXSTAT_CARRSOLNVALID(sta.fixStat) }, + { "psmState", UBX_NAV_STATUS_V0_FLAGS2_PSMSTATE_STR(sta.flags2) }, + { "spoofDetState", UBX_NAV_STATUS_V0_FLAGS2_SPOOFDETSTATE_STR(sta.flags2) }, + { "carrSoln", UBX_NAV_STATUS_V0_FLAGS2_CARRSOLN_STR(sta.flags2) }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_NAV_TIMEBDS(nlohmann::json& j, const std::vector& data) +{ + if (data.size() == UBX_NAV_TIMEBDS_V0_SIZE) { + UBX_NAV_TIMEBDS_V0_GROUP0 time; + std::memcpy(&time, &data[UBX_HEAD_SIZE], sizeof(time)); + j = nlohmann::json::object({ + { "iTow", time.iTow }, + { "SOW", time.SOW }, + { "fSOW", time.fSOW }, + { "week", time.week }, + { "leapS", time.leapS }, + { "tAcc", time.tAcc }, + { "sowValid", UBX_NAV_TIMEBDS_V0_VALID_SOWVALID(time.valid) }, + { "weekValid", UBX_NAV_TIMEBDS_V0_VALID_WEEKVALID(time.valid) }, + { "leapSValid", UBX_NAV_TIMEBDS_V0_VALID_LEAPSVALID(time.valid) }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_NAV_TIMEGAL(nlohmann::json& j, const std::vector& data) +{ + if (data.size() == UBX_NAV_TIMEGAL_V0_SIZE) { + UBX_NAV_TIMEGAL_V0_GROUP0 time; + std::memcpy(&time, &data[UBX_HEAD_SIZE], sizeof(time)); + j = nlohmann::json::object({ + { "iTow", time.iTow }, + { "galTow", time.galTow }, + { "fGalTow", time.fGalTow }, + { "galWno", time.galWno }, + { "leapS", time.leapS }, + { "tAcc", time.tAcc }, + { "galTowValid", UBX_NAV_TIMEGAL_V0_VALID_GALTOWVALID(time.valid) }, + { "galWnoValid", UBX_NAV_TIMEGAL_V0_VALID_GALWNOVALID(time.valid) }, + { "leapSValid", UBX_NAV_TIMEGAL_V0_VALID_LEAPSVALID(time.valid) }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_NAV_TIMEGLO(nlohmann::json& j, const std::vector& data) +{ + if (data.size() == UBX_NAV_TIMEGLO_V0_SIZE) { + UBX_NAV_TIMEGLO_V0_GROUP0 time; + std::memcpy(&time, &data[UBX_HEAD_SIZE], sizeof(time)); + j = nlohmann::json::object({ + { "iTow", time.iTow }, + { "TOD", time.TOD }, + { "fTOD", time.fTOD }, + { "Nt", time.Nt }, + { "N4", time.N4 }, + { "tAcc", time.tAcc }, + { "todValid", UBX_NAV_TIMEGLO_V0_VALID_TODVALID(time.valid) }, + { "dateValid", UBX_NAV_TIMEGLO_V0_VALID_DATEVALID(time.valid) }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_NAV_TIMEGPS(nlohmann::json& j, const std::vector& data) +{ + if (data.size() == UBX_NAV_TIMEGPS_V0_SIZE) { + UBX_NAV_TIMEGPS_V0_GROUP0 time; + std::memcpy(&time, &data[UBX_HEAD_SIZE], sizeof(time)); + j = nlohmann::json::object({ + { "iTow", time.iTow }, + { "fTOW", time.fTOW }, + { "week", time.week }, + { "leapS", time.leapS }, + { "tAcc", time.tAcc }, + { "towValid", UBX_NAV_TIMEGPS_V0_VALID_TOWVALID(time.valid) }, + { "weekValid", UBX_NAV_TIMEGPS_V0_VALID_WEEKVALID(time.valid) }, + { "leapSValid", UBX_NAV_TIMEGPS_V0_VALID_LEAPSVALID(time.valid) }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_NAV_TIMETRUSTED(nlohmann::json& j, const std::vector& data) +{ + if ((data.size() == UBX_NAV_TIMETRUSTED_V1_SIZE) && + (UBX_NAV_TIMETRUSTED_VERSION(data.data()) == UBX_NAV_TIMETRUSTED_V1_VERSION)) { + UBX_NAV_TIMETRUSTED_V1_GROUP0 tt; + std::memcpy(&tt, &data[UBX_HEAD_SIZE], sizeof(tt)); + j = nlohmann::json::object({ + { "version", tt.version }, + { "iTOW", tt.iTOW }, + { "iniWno", tt.iniWno }, + { "propWno", tt.propWno }, + { "iniTow", tt.iniTow }, + { "propTow", tt.propTow }, + { "iniTAcc", tt.iniTAcc }, + { "propTAcc", tt.propTAcc }, + { "deltaS", tt.deltaS }, + { "deltaMs", tt.deltaMs }, + { "refSys", UBX_NAV_TIMETRUSTED_V1_REFSYS_STR(tt.refSys) }, + { "trustedTimeValid", UBX_NAV_TIMETRUSTED_V1_VALID_TRUSTEDTIMEVALID(tt.valid) }, + { "deltaTimeValid", UBX_NAV_TIMETRUSTED_V1_VALID_DELTATIMEVALID(tt.valid) }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_NAV_TIMEUTC(nlohmann::json& j, const std::vector& data) +{ + if (data.size() == UBX_NAV_TIMEUTC_V0_SIZE) { + UBX_NAV_TIMEUTC_V0_GROUP0 utc; + std::memcpy(&utc, &data[UBX_HEAD_SIZE], sizeof(utc)); + j = nlohmann::json::object({ + { "iTow", utc.iTow }, + { "tAcc", utc.tAcc }, + { "nano", utc.nano }, + { "year", utc.year }, + { "month", utc.month }, + { "day", utc.day }, + { "hour", utc.hour }, + { "min", utc.min }, + { "sec", utc.sec }, + { "validTow", UBX_NAV_TIMEUTC_V0_VALID_VALIDTOW(utc.valid) != 0 }, + { "validWkn", UBX_NAV_TIMEUTC_V0_VALID_VALIDWKN(utc.valid) != 0 }, + { "validUtc", UBX_NAV_TIMEUTC_V0_VALID_VALIDUTC(utc.valid) != 0 }, + { "authStatus", UBX_NAV_TIMEUTC_V0_VALID_AUTHSTATUS(utc.valid) }, + { "utcStandard", UBX_NAV_TIMEUTC_V0_VALID_UTCSTANDARD_STR(utc.valid) }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_NAV_TIMELS(nlohmann::json& j, const std::vector& data) +{ + if (data.size() == UBX_NAV_TIMELS_V0_SIZE) { + UBX_NAV_TIMELS_V0_GROUP0 ls; + std::memcpy(&ls, &data[UBX_HEAD_SIZE], sizeof(ls)); + j = nlohmann::json::object({ + { "iTOW", ls.iTOW }, + { "version", ls.version }, + { "currLs", ls.currLs }, + { "lsChange", ls.lsChange }, + { "timeToLsEvent", ls.timeToLsEvent }, + { "dateOfLsGpsWn", ls.dateOfLsGpsWn }, + { "dateOfLsGpsDn", ls.dateOfLsGpsDn }, + { "srcOfCurrLs", UBX_NAV_TIMELS_V0_SRCOFCURRLS_STR(ls.srcOfCurrLs) }, + { "srcOfLsChange", UBX_NAV_TIMELS_V0_SRCOFCURRLSCHANGE_STR(ls.srcOfLsChange) }, + { "currLsValid", UBX_NAV_TIMELS_V0_VALID_CURRLSVALID(ls.valid) }, + { "timeToLsEventValid", UBX_NAV_TIMELS_V0_VALID_TIMETOLSEVENTVALID(ls.valid) }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_NAV_VELECEF(nlohmann::json& j, const std::vector& data) +{ + if (data.size() == UBX_NAV_VELECEF_V0_SIZE) { + UBX_NAV_VELECEF_V0_GROUP0 vel; + std::memcpy(&vel, &data[UBX_HEAD_SIZE], sizeof(vel)); + j = nlohmann::json::object({ + { "iTOW", vel.iTOW }, + { "ecefVX", vel.ecefVX }, + { "ecefVY", vel.ecefVY }, + { "ecefVZ", vel.ecefVZ }, + { "sAcc", vel.sAcc }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_RXM_RAWX(nlohmann::json& j, const std::vector& data) +{ + if ((data.size() < UBX_RXM_RAWX_V1_MIN_SIZE) || (UBX_RXM_RAWX_VERSION(data.data()) != UBX_RXM_RAWX_V1_VERSION) || + (data.size() != UBX_RXM_RAWX_V1_SIZE(data.data()))) { + return; + } + UBX_RXM_RAWX_V1_GROUP0 head; + std::memcpy(&head, &data[UBX_HEAD_SIZE], sizeof(head)); + + std::size_t offs = UBX_HEAD_SIZE + sizeof(head); + auto meas = nlohmann::json::array(); + for (std::size_t ix = 0; ix < head.numMeas; ix++, offs += sizeof(UBX_RXM_RAWX_V1_GROUP1)) { + UBX_RXM_RAWX_V1_GROUP1 m; + std::memcpy(&m, &data[offs], sizeof(m)); + meas.push_back(nlohmann::json::object({ + { "prMeas", m.prMeas }, + { "cpMeas", m.cpMeas }, + { "doMeas", m.doMeas }, + { "gnssId", UBX_GNSSID_STR(m.gnssId) }, + { "svId", m.svId }, + { "sigId", UBX_SIGID_STR(m.gnssId, m.sigId) }, + { "freqId", UBX_RXM_RAWX_V1_GROUP1_FREQID_TO_SLOT(m.freqId) }, + { "locktime", m.locktime }, + { "cno", m.cno }, + { "prStdev", UBX_RXM_RAWX_V1_PRSTDEV_PRSTD(m.prStdev) }, + { "cpStdev", UBX_RXM_RAWX_V1_CPSTDEV_CPSTD(m.cpStdev) }, + { "doStdev", UBX_RXM_RAWX_V1_DOSTDEV_DOSTD(m.doStdev) }, + { "prValid", UBX_RXM_RAWX_V1_TRKSTAT_PRVALID(m.trkStat) }, + { "cpValid", UBX_RXM_RAWX_V1_TRKSTAT_CPVALID(m.trkStat) }, + { "halfCyc", UBX_RXM_RAWX_V1_TRKSTAT_HALFCYC(m.trkStat) }, + { "subHalfCyc", UBX_RXM_RAWX_V1_TRKSTAT_SUBHALFCYC(m.trkStat) }, + })); + } + + j = nlohmann::json::object({ + { "rcvTow", head.rcvTow }, + { "week", head.week }, + { "leapS", head.leapS }, + { "numMeas", head.numMeas }, + { "version", head.version }, + { "leapSec", UBX_RXM_RAWX_V1_RECSTAT_LEAPSEC(head.recStat) }, + { "clkReset", UBX_RXM_RAWX_V1_RECSTAT_CLKRESET(head.recStat) }, + { "meas", meas }, + }); +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_RXM_RTCM(nlohmann::json& j, const std::vector& data) +{ + if ((data.size() == UBX_RXM_RTCM_V2_SIZE) && (UBX_RXM_RTCM_VERSION(data.data()) == UBX_RXM_RTCM_V2_VERSION)) { + UBX_RXM_RTCM_V2_GROUP0 rtcm; + std::memcpy(&rtcm, &data[UBX_HEAD_SIZE], sizeof(rtcm)); + j = nlohmann::json::object({ + { "version", rtcm.version }, + { "subType", rtcm.subType }, + { "refStation", rtcm.refStation }, + { "msgType", rtcm.msgType }, + { "crcFailed", UBX_RXM_RTCM_V2_FLAGS_CRCFAILED(rtcm.flags) }, + { "msgUsed", UBX_RXM_RTCM_V2_FLAGS_MSGUSED_STR(rtcm.flags) }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_RXM_SFRBX(nlohmann::json& j, const std::vector& data) +{ + if ((data.size() < UBX_RXM_SFRBX_V2_MIN_SIZE) || (UBX_RXM_SFRBX_VERSION(data.data()) != UBX_RXM_SFRBX_V2_VERSION)) { + return; + } + UBX_RXM_SFRBX_V2_GROUP0 head; + std::memcpy(&head, &data[UBX_HEAD_SIZE], sizeof(head)); + if (data.size() != (UBX_RXM_SFRBX_V2_MIN_SIZE + (head.numWords * sizeof(UBX_RXM_SFRBX_V2_GROUP1)))) { + return; + } + std::size_t offs = UBX_HEAD_SIZE + sizeof(head); + auto dwrds = nlohmann::json::array(); + for (std::size_t ix = 0; ix < head.numWords; ix++, offs += sizeof(UBX_RXM_SFRBX_V2_GROUP1)) { + UBX_RXM_SFRBX_V2_GROUP1 w; + std::memcpy(&w, &data[offs], sizeof(w)); + dwrds.push_back(string::Sprintf("%08x", w.dwrd)); + } + + j = nlohmann::json::object({ + { "gnssId", UBX_GNSSID_STR(head.gnssId) }, + { "svId", head.svId }, + { "sigId", UBX_SIGID_STR(head.gnssId, head.sigId) }, + { "freqId", UBX_RXM_SFRBX_V2_GROUP0_FREQID_TO_SLOT(head.freqId) }, + { "numWords", head.numWords }, + { "chn", head.chn }, + { "version", head.version }, + { "dwrds", dwrds }, + }); +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_RXM_SPARTN(nlohmann::json& j, const std::vector& data) +{ + if ((data.size() == UBX_RXM_SPARTN_V1_SIZE) && (UBX_RXM_SPARTN_VERSION(data.data()) == UBX_RXM_SPARTN_V1_VERSION)) { + UBX_RXM_SPARTN_V1_GROUP0 spartn; + std::memcpy(&spartn, &data[UBX_HEAD_SIZE], sizeof(spartn)); + j = nlohmann::json::object({ + { "version", spartn.version }, + { "subType", spartn.subType }, + { "msgType", spartn.msgType }, + { "msgUsed", UBX_RXM_SPARTN_V1_FLAGS_MSGUSED_STR(spartn.flags) }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_SEC_OSNMA(nlohmann::json& j, const std::vector& data) +{ + if ((data.size() < UBX_SEC_OSNMA_V3_MIN_SIZE) || (UBX_SEC_OSNMA_VERSION(data.data()) != UBX_SEC_OSNMA_V3_VERSION)) { + return; + } + UBX_SEC_OSNMA_V3_GROUP0 head; + std::memcpy(&head, &data[UBX_HEAD_SIZE], sizeof(head)); + const std::size_t num_svs = UBX_SEC_OSNMA_V3_GENERALANDTIMING_AUTHSVS(head.generalAndTiming); + if (data.size() != (UBX_SEC_OSNMA_V3_MIN_SIZE + (num_svs * sizeof(UBX_SEC_OSNMA_V3_GROUP1)))) { + return; + } + std::size_t offs = UBX_HEAD_SIZE + sizeof(head); + auto svs = nlohmann::json::array(); + for (std::size_t ix = 0; ix < num_svs; ix++, offs += sizeof(UBX_SEC_OSNMA_V3_GROUP1)) { + UBX_SEC_OSNMA_V3_GROUP1 s; + std::memcpy(&s, &data[offs], sizeof(s)); + svs.push_back(nlohmann::json::object({ + { "svId", s.svId }, + { "iode", UBX_SEC_OSNMA_V3_GROUP1_BITFIELD1_IODE(s.bitfield1) }, + { "authNum", UBX_SEC_OSNMA_V3_GROUP1_BITFIELD1_AUTHNUM(s.bitfield1) }, + { "authStatus", UBX_SEC_OSNMA_V3_GROUP1_BITFIELD1_AUTHSTATUS(s.bitfield1) }, + })); + } + + j = nlohmann::json::object({ + { "version", head.version }, + { "headerAuthStatus", UBX_SEC_OSNMA_V3_NMAHEADER_HEADERAUTHSTATUS(head.nmaHeader) }, + { "nmaStatus", UBX_SEC_OSNMA_V3_NMAHEADER_NMASTATUS_STR(head.nmaHeader) }, + { "chainInForce", UBX_SEC_OSNMA_V3_NMAHEADER_CHAININFORCE(head.nmaHeader) }, + { "cpks", UBX_SEC_OSNMA_V3_NMAHEADER_CPKS_STR(head.nmaHeader) }, + { "osnmaEnabled", UBX_SEC_OSNMA_V3_OSNMAMONITORING_OSNMAENABLED(head.osnmaMonitoring) }, + { "numberSvs", UBX_SEC_OSNMA_V3_OSNMAMONITORING_NUMBERSVS(head.osnmaMonitoring) }, + { "nmaHeaderUpdate", UBX_SEC_OSNMA_V3_OSNMAMONITORING_NMAHEADERUPDATE_STR(head.osnmaMonitoring) }, + { "noData", UBX_SEC_OSNMA_V3_OSNMAMONITORING_NODATA(head.osnmaMonitoring) }, + { "wrongData", UBX_SEC_OSNMA_V3_OSNMAMONITORING_WRONGDATA(head.osnmaMonitoring) }, + { "wrongFlxMac", UBX_SEC_OSNMA_V3_OSNMAMONITORING_WRONGFLXMAC(head.osnmaMonitoring) }, + { "wrongMacLt", UBX_SEC_OSNMA_V3_OSNMAMONITORING_WRONGMACLT(head.osnmaMonitoring) }, + { "timSyncEnabled", UBX_SEC_OSNMA_V3_TIMSYNCREQ_TIMSYNCENABLED(head.timSyncReq) }, + { "timSyncStatus", UBX_SEC_OSNMA_V3_TIMSYNCREQ_TIMSYNCSTATUS_STR(head.timSyncReq) }, + { "timSyncReqDiff", head.timSyncReqDiff }, + { "dsmAuthenticationStatus", + UBX_SEC_OSNMA_V3_DSMAUTHENTICATION_DSMAUTHENTICATIONSTATUS_STR(head.dsmAuthentication) }, + { "hashFunction", UBX_SEC_OSNMA_V3_DSMAUTHENTICATION_HASHFUNCTION(head.dsmAuthentication) }, + { "macFunction", UBX_SEC_OSNMA_V3_DSMAUTHENTICATION_MACFUNCTION(head.dsmAuthentication) }, + { "pubKeyId", UBX_SEC_OSNMA_V3_DSMAUTHENTICATION_PUBKEYID(head.dsmAuthentication) }, + { "macLookupTable", UBX_SEC_OSNMA_V3_DSMAUTHENTICATION_MACLOOKUPTABLE(head.dsmAuthentication) }, + { "keySize", UBX_SEC_OSNMA_V3_DSMAUTHENTICATION_KEYSIZE(head.dsmAuthentication) }, + { "macSize", UBX_SEC_OSNMA_V3_DSMAUTHENTICATION_MACSIZE(head.dsmAuthentication) }, + { "fromNvs", UBX_SEC_OSNMA_V3_DSMAUTHENTICATION_FROMNVS(head.dsmAuthentication) }, + { "teslaKeyAuthStatus", UBX_SEC_OSNMA_V3_TESLAKEY_TESLAKEYAUTHSTATUS_STR(head.teslaKey) }, + { "wnSf", UBX_SEC_OSNMA_V3_TESLAKEY_WNSF(head.teslaKey) }, + { "towSf", UBX_SEC_OSNMA_V3_TESLAKEY_TOWSF(head.teslaKey) }, + { "chainId", UBX_SEC_OSNMA_V3_TESLAKEY_CHAINID(head.teslaKey) }, + { "authSvs", UBX_SEC_OSNMA_V3_GENERALANDTIMING_AUTHSVS(head.generalAndTiming) }, + { "authNumTim", UBX_SEC_OSNMA_V3_GENERALANDTIMING_AUTHNUMTIM(head.generalAndTiming) }, + { "timingAuthResult", UBX_SEC_OSNMA_V3_GENERALANDTIMING_TIMINGAUTHRESULT_STR(head.generalAndTiming) }, + { "macAdkdType", UBX_SEC_OSNMA_V3_GENERALANDTIMING_MACADKDTYPE_STR(head.generalAndTiming) }, + { "pubKeySrc", UBX_SEC_OSNMA_V3_GENERALANDTIMING_PUBKEYSRC_STR(head.generalAndTiming) }, + { "merkleRootSrc", UBX_SEC_OSNMA_V3_GENERALANDTIMING_MERKLEROOTSRC_STR(head.generalAndTiming) }, + { "merkleRootVal", UBX_SEC_OSNMA_V3_GENERALANDTIMING_MERKLEROOTVAL(head.generalAndTiming) }, + { "futureMerkleRootSrc", UBX_SEC_OSNMA_V3_GENERALANDTIMING_FUTUREMERKLEROOTSRC_STR(head.generalAndTiming) }, + { "futureMerkleRootVal", UBX_SEC_OSNMA_V3_GENERALANDTIMING_FUTUREMERKLEROOTVAL(head.generalAndTiming) }, + { "pubKeyVal", UBX_SEC_OSNMA_V3_GENERALANDTIMING_PUBKEYVAL(head.generalAndTiming) }, + { "futurePubKeyVal", UBX_SEC_OSNMA_V3_GENERALANDTIMING_FUTUREPUBKEYVAL(head.generalAndTiming) }, + { "futurePubKeySrc", UBX_SEC_OSNMA_V3_GENERALANDTIMING_FUTUREPUBKEYSRC_STR(head.generalAndTiming) }, + { "futurePubKeyId", UBX_SEC_OSNMA_V3_GENERALANDTIMING_FUTUREPUBKEYID(head.generalAndTiming) }, + { "svs", svs }, + }); +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_TIM_SVIN(nlohmann::json& j, const std::vector& data) +{ + if (data.size() == UBX_TIM_SVIN_V0_SIZE) { + UBX_TIM_SVIN_V0_GROUP0 svin; + std::memcpy(&svin, &data[UBX_HEAD_SIZE], sizeof(svin)); + j = nlohmann::json::object({ + { "dur", svin.dur }, + { "meanX", svin.meanX }, + { "meanY", svin.meanY }, + { "meanZ", svin.meanZ }, + { "meanV", svin.meanV }, + { "obs", svin.obs }, + { "valid", svin.valid != 0 }, + { "active", svin.active != 0 }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_TIM_TM2(nlohmann::json& j, const std::vector& data) +{ + if (data.size() == UBX_TIM_TM2_V0_SIZE) { + UBX_TIM_TM2_V0_GROUP0 tm2; + std::memcpy(&tm2, &data[UBX_HEAD_SIZE], sizeof(tm2)); + j = nlohmann::json::object({ + { "ch", tm2.ch }, + { "count", tm2.count }, + { "wnR", tm2.wnR }, + { "wnF", tm2.wnF }, + { "towMsR", tm2.towMsR }, + { "towSubMsR", tm2.towSubMsR }, + { "towMsF", tm2.towMsF }, + { "towSubMsF", tm2.towSubMsF }, + { "accEst", tm2.accEst }, + { "mode", UBX_TIM_TM2_V0_FLAGS_MODE_STR(tm2.flags) }, + { "run", UBX_TIM_TM2_V0_FLAGS_RUN_STR(tm2.flags) }, + { "newFallingEdge", UBX_TIM_TM2_V0_FLAGS_NEWFALLINGEDGE(tm2.flags) }, + { "timeBase", UBX_TIM_TM2_V0_FLAGS_TIMEBASE_STR(tm2.flags) }, + { "utcAcAvail", UBX_TIM_TM2_V0_FLAGS_UTCACAVAIL(tm2.flags) }, + { "timeValid", UBX_TIM_TM2_V0_FLAGS_TIMEVALID(tm2.flags) }, + { "newRisingEdge", UBX_TIM_TM2_V0_FLAGS_NEWRISINGEDGE(tm2.flags) }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline void to_json_UBX_TIM_TP(nlohmann::json& j, const std::vector& data) +{ + if (data.size() == UBX_TIM_TP_V0_SIZE) { + UBX_TIM_TP_V0_GROUP0 tp; + std::memcpy(&tp, &data[UBX_HEAD_SIZE], sizeof(tp)); + j = nlohmann::json::object({ + { "towMs", tp.towMs }, + { "towSubMs", tp.towSubMs }, + { "qErr", tp.qErr }, + { "week", tp.week }, + { "timeBase", UBX_TIM_TP_V0_FLAGS_TIMEBASE_STR(tp.flags) }, + { "utc", UBX_TIM_TP_V0_FLAGS_UTC(tp.flags) }, + { "raim", UBX_TIM_TP_V0_FLAGS_RAIM_STR(tp.flags) }, + { "qErrInvalid", UBX_TIM_TP_V0_FLAGS_QERRINVALID(tp.flags) }, + { "tpNotLocked", UBX_TIM_TP_V0_FLAGS_TPNOTLOCKED(tp.flags) }, + { "timeRefGnss", UBX_TIM_TP_V0_REFINFO_TIMEREFGNSS_STR(tp.refInfo) }, + { "utcStandard", UBX_TIM_TP_V0_REFINFO_UTCSTANDARD_STR(tp.refInfo) }, + }); + } +} + +// --------------------------------------------------------------------------------------------------------------------- + +// UBX-MGA-GAL and UBX-MGA-INI are multiplexed on the payload type byte +inline void to_json_UBX_MGA_GAL(nlohmann::json& j, const std::vector& data) +{ + if (data.size() < (UBX_HEAD_SIZE + 1)) { + return; + } + switch (data[UBX_HEAD_SIZE]) { // clang-format off + case UBX_MGA_GAL_OSNMA_PUBKEY_TYPE: to_json_UBX_MGA_GAL_OSNMA_PUBKEY(j, data); break; + case UBX_MGA_GAL_OSNMA_MERKLE_TYPE: to_json_UBX_MGA_GAL_OSNMA_MERKLE(j, data); break; + } // clang-format on +} + +inline void to_json_UBX_MGA_INI(nlohmann::json& j, const std::vector& data) +{ + if (data.size() < (UBX_HEAD_SIZE + 1)) { + return; + } + switch (data[UBX_HEAD_SIZE]) { // clang-format off + case UBX_MGA_INI_TIME_UTC_TYPE: to_json_UBX_MGA_INI_TIME_UTC(j, data); break; + case UBX_MGA_INI_TIME_GNSS_TYPE: to_json_UBX_MGA_INI_TIME_GNSS(j, data); break; + } // clang-format on +} + +// --------------------------------------------------------------------------------------------------------------------- + +inline nlohmann::json to_json_UBX(const ParserMsg& msg) +{ + auto j = nlohmann::json::object(); + switch (UbxClsId(msg.Data())) { // clang-format off + case UBX_ACK_CLSID: switch (UbxMsgId(msg.Data())) { + case UBX_ACK_ACK_MSGID: to_json_UBX_ACK(j, msg.data_, true); break; + case UBX_ACK_NAK_MSGID: to_json_UBX_ACK(j, msg.data_, false); break; } break; + case UBX_CFG_CLSID: switch (UbxMsgId(msg.Data())) { + case UBX_CFG_CFG_MSGID: to_json_UBX_CFG_CFG(j, msg.data_); break; + case UBX_CFG_RST_MSGID: to_json_UBX_CFG_RST(j, msg.data_); break; + case UBX_CFG_VALDEL_MSGID: to_json_UBX_CFG_VALDEL(j, msg.data_); break; + case UBX_CFG_VALGET_MSGID: to_json_UBX_CFG_VALGET(j, msg.data_); break; + case UBX_CFG_VALSET_MSGID: to_json_UBX_CFG_VALSET(j, msg.data_); break; } break; + case UBX_ESF_CLSID: switch (UbxMsgId(msg.Data())) { + case UBX_ESF_MEAS_MSGID: to_json_UBX_ESF_MEAS(j, msg.data_); break; + case UBX_ESF_STATUS_MSGID: to_json_UBX_ESF_STATUS(j, msg.data_); break; } break; + case UBX_MGA_CLSID: switch (UbxMsgId(msg.Data())) { + case UBX_MGA_GAL_MSGID: to_json_UBX_MGA_GAL(j, msg.data_); break; + case UBX_MGA_INI_MSGID: to_json_UBX_MGA_INI(j, msg.data_); break; } break; + case UBX_MON_CLSID: switch (UbxMsgId(msg.Data())) { + case UBX_MON_COMMS_MSGID: to_json_UBX_MON_COMMS(j, msg.data_); break; + case UBX_MON_HW_MSGID: to_json_UBX_MON_HW(j, msg.data_); break; + case UBX_MON_HW2_MSGID: to_json_UBX_MON_HW2(j, msg.data_); break; + case UBX_MON_HW3_MSGID: to_json_UBX_MON_HW3(j, msg.data_); break; + case UBX_MON_RF_MSGID: to_json_UBX_MON_RF(j, msg.data_); break; + case UBX_MON_SPAN_MSGID: to_json_UBX_MON_SPAN(j, msg.data_); break; + case UBX_MON_SYS_MSGID: to_json_UBX_MON_SYS(j, msg.data_); break; + case UBX_MON_TEMP_MSGID: to_json_UBX_MON_TEMP(j, msg.data_); break; + case UBX_MON_VER_MSGID: to_json_UBX_MON_VER(j, msg.data_); break; } break; + case UBX_NAV_CLSID: switch (UbxMsgId(msg.Data())) { + case UBX_NAV_ATT_MSGID: to_json_UBX_NAV_ATT(j, msg.data_); break; + case UBX_NAV_CLOCK_MSGID: to_json_UBX_NAV_CLOCK(j, msg.data_); break; + case UBX_NAV_COV_MSGID: to_json_UBX_NAV_COV(j, msg.data_); break; + case UBX_NAV_DOP_MSGID: to_json_UBX_NAV_DOP(j, msg.data_); break; + case UBX_NAV_EELL_MSGID: to_json_UBX_NAV_EELL(j, msg.data_); break; + case UBX_NAV_EOE_MSGID: to_json_UBX_NAV_EOE(j, msg.data_); break; + case UBX_NAV_HPPOSECEF_MSGID: to_json_UBX_NAV_HPPOSECEF(j, msg.data_); break; + case UBX_NAV_HPPOSLLH_MSGID: to_json_UBX_NAV_HPPOSLLH(j, msg.data_); break; + case UBX_NAV_POSECEF_MSGID: to_json_UBX_NAV_POSECEF(j, msg.data_); break; + case UBX_NAV_PVT_MSGID: to_json_UBX_NAV_PVT(j, msg.data_); break; + case UBX_NAV_RELPOSNED_MSGID: to_json_UBX_NAV_RELPOSNED(j, msg.data_); break; + case UBX_NAV_SAT_MSGID: to_json_UBX_NAV_SAT(j, msg.data_); break; + case UBX_NAV_SIG_MSGID: to_json_UBX_NAV_SIG(j, msg.data_); break; + case UBX_NAV_STATUS_MSGID: to_json_UBX_NAV_STATUS(j, msg.data_); break; + case UBX_NAV_TIMEBDS_MSGID: to_json_UBX_NAV_TIMEBDS(j, msg.data_); break; + case UBX_NAV_TIMEGAL_MSGID: to_json_UBX_NAV_TIMEGAL(j, msg.data_); break; + case UBX_NAV_TIMEGLO_MSGID: to_json_UBX_NAV_TIMEGLO(j, msg.data_); break; + case UBX_NAV_TIMEGPS_MSGID: to_json_UBX_NAV_TIMEGPS(j, msg.data_); break; + case UBX_NAV_TIMELS_MSGID: to_json_UBX_NAV_TIMELS(j, msg.data_); break; + case UBX_NAV_TIMETRUSTED_MSGID: to_json_UBX_NAV_TIMETRUSTED(j, msg.data_); break; + case UBX_NAV_TIMEUTC_MSGID: to_json_UBX_NAV_TIMEUTC(j, msg.data_); break; + case UBX_NAV_VELECEF_MSGID: to_json_UBX_NAV_VELECEF(j, msg.data_); break; } break; + case UBX_NAV2_CLSID: switch (UbxMsgId(msg.Data())) { + case UBX_NAV2_CLOCK_MSGID: to_json_UBX_NAV_CLOCK(j, msg.data_); break; + case UBX_NAV2_COV_MSGID: to_json_UBX_NAV_COV(j, msg.data_); break; + case UBX_NAV2_DOP_MSGID: to_json_UBX_NAV_DOP(j, msg.data_); break; + case UBX_NAV2_EOE_MSGID: to_json_UBX_NAV_EOE(j, msg.data_); break; + case UBX_NAV2_POSECEF_MSGID: to_json_UBX_NAV_POSECEF(j, msg.data_); break; + case UBX_NAV2_PVT_MSGID: to_json_UBX_NAV_PVT(j, msg.data_); break; + case UBX_NAV2_SAT_MSGID: to_json_UBX_NAV_SAT(j, msg.data_); break; + case UBX_NAV2_SIG_MSGID: to_json_UBX_NAV_SIG(j, msg.data_); break; + case UBX_NAV2_STATUS_MSGID: to_json_UBX_NAV_STATUS(j, msg.data_); break; + case UBX_NAV2_TIMEBDS_MSGID: to_json_UBX_NAV_TIMEBDS(j, msg.data_); break; + case UBX_NAV2_TIMEGAL_MSGID: to_json_UBX_NAV_TIMEGAL(j, msg.data_); break; + case UBX_NAV2_TIMEGLO_MSGID: to_json_UBX_NAV_TIMEGLO(j, msg.data_); break; + case UBX_NAV2_TIMEGPS_MSGID: to_json_UBX_NAV_TIMEGPS(j, msg.data_); break; + case UBX_NAV2_TIMELS_MSGID: to_json_UBX_NAV_TIMELS(j, msg.data_); break; + case UBX_NAV2_TIMEUTC_MSGID: to_json_UBX_NAV_TIMEUTC(j, msg.data_); break; + case UBX_NAV2_VELECEF_MSGID: to_json_UBX_NAV_VELECEF(j, msg.data_); break; } break; + case UBX_RXM_CLSID: switch (UbxMsgId(msg.Data())) { + case UBX_RXM_RAWX_MSGID: to_json_UBX_RXM_RAWX(j, msg.data_); break; + case UBX_RXM_RTCM_MSGID: to_json_UBX_RXM_RTCM(j, msg.data_); break; + case UBX_RXM_SFRBX_MSGID: to_json_UBX_RXM_SFRBX(j, msg.data_); break; + case UBX_RXM_SPARTN_MSGID: to_json_UBX_RXM_SPARTN(j, msg.data_); break; } break; + case UBX_SEC_CLSID: switch (UbxMsgId(msg.Data())) { + case UBX_SEC_OSNMA_MSGID: to_json_UBX_SEC_OSNMA(j, msg.data_); break; } break; + case UBX_TIM_CLSID: switch (UbxMsgId(msg.Data())) { + case UBX_TIM_SVIN_MSGID: to_json_UBX_TIM_SVIN(j, msg.data_); break; + case UBX_TIM_TM2_MSGID: to_json_UBX_TIM_TM2(j, msg.data_); break; + case UBX_TIM_TP_MSGID: to_json_UBX_TIM_TP(j, msg.data_); break; } break; + } // clang-format on + return j; +} + +} // namespace fpsdk::common::parser::ubx +/* ****************************************************************************************************************** */ +#endif // !_DOXYGEN_ +#endif // __FPSDK_COMMON_TO_JSON_PARSER_UBX_HPP__ diff --git a/fpsdk_common/include/fpsdk_common/types.hpp b/fpsdk_common/include/fpsdk_common/types.hpp index 8833b5a..b97ed2f 100644 --- a/fpsdk_common/include/fpsdk_common/types.hpp +++ b/fpsdk_common/include/fpsdk_common/types.hpp @@ -131,6 +131,23 @@ class NoCopyNoMove // clang-format off # define _CONCAT(a, b) a##b #endif +/** + * @brief Get string in list of strings by index + * + * @param[in] ix Index + * @param[in] args List of strings + * + * @returns the string, or "?" if index is too large + */ +template +constexpr const char* IxToStr(std::size_t ix, Args... args) +{ + static_assert((std::is_convertible_v && ...), "args must be const char*"); + constexpr std::size_t N = sizeof...(Args); + const std::array strs = { args... }; + return ix < N ? strs[ix] : "?"; +} + /* ****************************************************************************************************************** */ } // namespace types } // namespace common diff --git a/fpsdk_common/src/app.cpp b/fpsdk_common/src/app.cpp index 89dd324..809a3a8 100644 --- a/fpsdk_common/src/app.cpp +++ b/fpsdk_common/src/app.cpp @@ -397,9 +397,9 @@ void ProgramOptions::PrintVersion() const void ProgramOptions::LogVersion() const { - INFO("%s%s%s (fpsdk: %s, %s, %s)\n%s\n%s\n", app_name_.c_str(), version_str_.empty() ? "" : " ", - version_str_.empty() ? "" : version_str_.c_str(), BUILDSTR, ROSSTR, utils::GetVersionString(), - copy_str_.empty() ? utils::GetCopyrightString() : copy_str_.c_str(), + INFO("%s%s%s (fpsdk: %s%s%s%s, %s)\n%s\n%s\n", app_name_.c_str(), version_str_.empty() ? "" : " ", + version_str_.empty() ? "" : version_str_.c_str(), BUILDSTR, ROSSTR, PROJSTR, FFMPEGSTR, + utils::GetVersionString(), copy_str_.empty() ? utils::GetCopyrightString() : copy_str_.c_str(), lic_str_.empty() ? utils::GetLicenseString() : lic_str_.c_str()); } diff --git a/fpsdk_common/src/codegen.pl b/fpsdk_common/src/codegen.pl index 3f80e46..f7477a6 100755 --- a/fpsdk_common/src/codegen.pl +++ b/fpsdk_common/src/codegen.pl @@ -282,6 +282,7 @@ { class => 'SEC', name => 'SIG', msgid => 0x09 }, { class => 'SEC', name => 'SIGLOG', msgid => 0x10 }, { class => 'SEC', name => 'UNIQID', msgid => 0x03 }, + { class => 'TIM', name => 'SVIN', msgid => 0x04 }, { class => 'TIM', name => 'TM2', msgid => 0x03 }, { class => 'TIM', name => 'TP', msgid => 0x01 }, { class => 'TIM', name => 'VRFY', msgid => 0x06 }, diff --git a/fpsdk_common/src/parser/ubx.cpp b/fpsdk_common/src/parser/ubx.cpp index da19ceb..61b2a0d 100644 --- a/fpsdk_common/src/parser/ubx.cpp +++ b/fpsdk_common/src/parser/ubx.cpp @@ -186,6 +186,7 @@ static const UbxMessagesInfo MSG_INFO = { UBX_SEC_CLSID, UBX_SEC_SIG_MSGID, UBX_SEC_SIG_STRID }, { UBX_SEC_CLSID, UBX_SEC_SIGLOG_MSGID, UBX_SEC_SIGLOG_STRID }, { UBX_SEC_CLSID, UBX_SEC_UNIQID_MSGID, UBX_SEC_UNIQID_STRID }, + { UBX_TIM_CLSID, UBX_TIM_SVIN_MSGID, UBX_TIM_SVIN_STRID }, { UBX_TIM_CLSID, UBX_TIM_TM2_MSGID, UBX_TIM_TM2_STRID }, { UBX_TIM_CLSID, UBX_TIM_TP_MSGID, UBX_TIM_TP_STRID }, { UBX_TIM_CLSID, UBX_TIM_VRFY_MSGID, UBX_TIM_VRFY_STRID }, diff --git a/fpsdk_common/test/types_test.cpp b/fpsdk_common/test/types_test.cpp index 73c60e9..b406855 100644 --- a/fpsdk_common/test/types_test.cpp +++ b/fpsdk_common/test/types_test.cpp @@ -81,6 +81,25 @@ TEST(TypesTest, Macros) EXPECT_EQ(SIZEOF_FIELD(SomeStruct, b), 3 * sizeof(uint8_t)); } +// --------------------------------------------------------------------------------------------------------------------- + +inline const char* IxToStrFunc(const std::size_t ix) +{ + return IxToStr(ix, "bla", "bla"); +} + +TEST(IxToStr, NumOf) +{ + ASSERT_EQ(std::string(IxToStr(0, "foo", "bar", "baz")), std::string("foo")); + ASSERT_EQ(std::string(IxToStr(1, "foo", "bar", "baz")), std::string("bar")); + ASSERT_EQ(std::string(IxToStr(2, "foo", "bar", "baz")), std::string("baz")); + ASSERT_EQ(std::string(IxToStr(3, "foo", "bar", "baz")), std::string("?")); + ASSERT_EQ(std::string(IxToStrFunc(0)), std::string("bla")); + const char* s1 = IxToStrFunc(1); + const char* s2 = IxToStrFunc(1); + ASSERT_EQ(s1, s2); +} + /* ****************************************************************************************************************** */ } // namespace diff --git a/fpsdk_doc/Doxyfile b/fpsdk_doc/Doxyfile index 9f6ae41..04cccc6 100644 --- a/fpsdk_doc/Doxyfile +++ b/fpsdk_doc/Doxyfile @@ -1087,7 +1087,6 @@ EXAMPLE_PATH = fpsdk_doc \ fpsdk_common/doc \ fpsdk_ros1 \ fpsdk_ros1/doc \ - fpsdk_ros1/msg \ fpsdk_ros2 \ fpsdk_ros2/doc \ fpsdk_apps \