#pragma once #include #include #include #include #include #include #include #include "cereal/messaging/messaging.h" #include "common/util.h" #include "system/ubloxd/generated/gps.h" #include "system/ubloxd/generated/glonass.h" #include "system/ubloxd/generated/ubx.h" using namespace std::string_literals; const int SECS_IN_MIN = 60; const int SECS_IN_HR = 60 * SECS_IN_MIN; const int SECS_IN_DAY = 24 * SECS_IN_HR; const int SECS_IN_WEEK = 7 * SECS_IN_DAY; // protocol constants namespace ublox { const uint8_t PREAMBLE1 = 0xb5; const uint8_t PREAMBLE2 = 0x62; const int UBLOX_HEADER_SIZE = 6; const int UBLOX_CHECKSUM_SIZE = 2; const int UBLOX_MAX_MSG_SIZE = 65536; struct ubx_mga_ini_time_utc_t { uint8_t type; uint8_t version; uint8_t ref; int8_t leapSecs; uint16_t year; uint8_t month; uint8_t day; uint8_t hour; uint8_t minute; uint8_t second; uint8_t reserved1; uint32_t ns; uint16_t tAccS; uint16_t reserved2; uint32_t tAccNs; } __attribute__((packed)); inline std::string ubx_add_checksum(const std::string &msg) { assert(msg.size() > 2); uint8_t ck_a = 0, ck_b = 0; for (int i = 2; i < msg.size(); i++) { ck_a = (ck_a + msg[i]) & 0xFF; ck_b = (ck_b + ck_a) & 0xFF; } std::string r = msg; r.push_back(ck_a); r.push_back(ck_b); return r; } inline std::string build_ubx_mga_ini_time_utc(struct tm time) { ublox::ubx_mga_ini_time_utc_t payload = { .type = 0x10, .version = 0x0, .ref = 0x0, .leapSecs = -128, // Unknown .year = (uint16_t)(1900 + time.tm_year), .month = (uint8_t)(1 + time.tm_mon), .day = (uint8_t)time.tm_mday, .hour = (uint8_t)time.tm_hour, .minute = (uint8_t)time.tm_min, .second = (uint8_t)time.tm_sec, .reserved1 = 0x0, .ns = 0, .tAccS = 30, .reserved2 = 0x0, .tAccNs = 0, }; assert(sizeof(payload) == 24); std::string msg = "\xb5\x62\x13\x40\x18\x00"s; msg += std::string((char*)&payload, sizeof(payload)); return ubx_add_checksum(msg); } } class UbloxMsgParser { public: bool add_data(float log_time, const uint8_t *incoming_data, uint32_t incoming_data_len, size_t &bytes_consumed); inline void reset() {bytes_in_parse_buf = 0;} inline int needed_bytes(); inline std::string data() {return std::string((const char*)msg_parse_buf, bytes_in_parse_buf);} std::pair> gen_msg(); kj::Array gen_nav_pvt(ubx_t::nav_pvt_t *msg); kj::Array gen_rxm_sfrbx(ubx_t::rxm_sfrbx_t *msg); kj::Array gen_rxm_rawx(ubx_t::rxm_rawx_t *msg); kj::Array gen_mon_hw(ubx_t::mon_hw_t *msg); kj::Array gen_mon_hw2(ubx_t::mon_hw2_t *msg); kj::Array gen_nav_sat(ubx_t::nav_sat_t *msg); private: inline bool valid_cheksum(); inline bool valid(); inline bool valid_so_far(); kj::Array parse_gps_ephemeris(ubx_t::rxm_sfrbx_t *msg); kj::Array parse_glonass_ephemeris(ubx_t::rxm_sfrbx_t *msg); std::unordered_map> gps_subframes; float last_log_time = 0.0; size_t bytes_in_parse_buf = 0; uint8_t msg_parse_buf[ublox::UBLOX_HEADER_SIZE + ublox::UBLOX_MAX_MSG_SIZE]; // user range accuracy in meters const std::unordered_map glonass_URA_lookup = {{ 0, 1}, { 1, 2}, { 2, 2.5}, { 3, 4}, { 4, 5}, {5, 7}, { 6, 10}, { 7, 12}, { 8, 14}, { 9, 16}, {10, 32}, {11, 64}, {12, 128}, {13, 256}, {14, 512}, {15, 1024}}; std::unordered_map> glonass_strings; std::unordered_map> glonass_string_times; std::unordered_map> glonass_string_superframes; };