From f24a67182541b41ebf924e983660c9dc48c8bbd8 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sat, 10 Feb 2018 18:18:25 +0100 Subject: Add support for LEA-M8F GPSDO board --- host/include/uhd/usrp/gps_ctrl.hpp | 9 +- .../include/uhdlib/usrp/common/adf4001_ctrl.hpp | 1 + host/lib/usrp/b200/b200_cores.cpp | 8 + host/lib/usrp/b200/b200_cores.hpp | 1 + host/lib/usrp/b200/b200_impl.cpp | 16 +- host/lib/usrp/common/adf4001_ctrl.cpp | 15 + host/lib/usrp/gps_ctrl.cpp | 338 ++++++++++++++++++--- host/utils/query_gpsdo_sensors.cpp | 53 +++- 8 files changed, 389 insertions(+), 52 deletions(-) diff --git a/host/include/uhd/usrp/gps_ctrl.hpp b/host/include/uhd/usrp/gps_ctrl.hpp index b7c3814f9..e1fa55a41 100644 --- a/host/include/uhd/usrp/gps_ctrl.hpp +++ b/host/include/uhd/usrp/gps_ctrl.hpp @@ -43,7 +43,14 @@ public: */ virtual bool gps_detected(void) = 0; - // TODO: other fun things you can do with a GPS. + /*! + * Return what reference clock the GPSDO outputs. + * \return 0 if not GPSDO available. Frequency in kHz if a GPSDO is installed. + */ + virtual int gps_refclock_frequency(void) = 0; + + //TODO: other fun things you can do with a GPS. + }; } // namespace uhd diff --git a/host/lib/include/uhdlib/usrp/common/adf4001_ctrl.hpp b/host/lib/include/uhdlib/usrp/common/adf4001_ctrl.hpp index 49a69bdbf..d1e9deece 100644 --- a/host/lib/include/uhdlib/usrp/common/adf4001_ctrl.hpp +++ b/host/lib/include/uhdlib/usrp/common/adf4001_ctrl.hpp @@ -107,6 +107,7 @@ public: adf4001_ctrl(uhd::spi_iface::sptr _spi, int slaveno); virtual ~adf4001_ctrl() = default; virtual void set_lock_to_ext_ref(bool external); + virtual bool set_refclk_frequency(int refclk_kHz); private: uhd::spi_iface::sptr spi_iface; diff --git a/host/lib/usrp/b200/b200_cores.cpp b/host/lib/usrp/b200/b200_cores.cpp index 3c55d3995..b076b9476 100644 --- a/host/lib/usrp/b200/b200_cores.cpp +++ b/host/lib/usrp/b200/b200_cores.cpp @@ -61,6 +61,14 @@ void b200_ref_pll_ctrl::set_lock_to_ext_ref(bool external) _spi->restore_perif(); } +bool b200_ref_pll_ctrl::set_refclk_frequency(int refclk_kHz) +{ + _spi->change_perif(b200_local_spi_core::PLL); + bool success = adf4001_ctrl::set_refclk_frequency(refclk_kHz); + _spi->restore_perif(); + return success; +} + b200_local_spi_core::sptr b200_local_spi_core::make( uhd::wb_iface::sptr iface, b200_local_spi_core::perif_t default_perif) diff --git a/host/lib/usrp/b200/b200_cores.hpp b/host/lib/usrp/b200/b200_cores.hpp index 1042cf422..a29e18796 100644 --- a/host/lib/usrp/b200/b200_cores.hpp +++ b/host/lib/usrp/b200/b200_cores.hpp @@ -49,6 +49,7 @@ public: b200_ref_pll_ctrl(b200_local_spi_core::sptr spi); void set_lock_to_ext_ref(bool external) override; + virtual bool set_refclk_frequency(int refclk_kHz); private: b200_local_spi_core::sptr _spi; diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index 6de161e87..6b0960a62 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -518,8 +518,12 @@ b200_impl::b200_impl( //////////////////////////////////////////////////////////////////// // Create the GPSDO control //////////////////////////////////////////////////////////////////// - if (_gpsdo_capable) { - if ((_local_ctrl->peek32(RB32_CORE_STATUS) & 0xff) != B200_GPSDO_ST_NONE) { + if (_gpsdo_capable) + { + + // Do not check this flag, I don't see why it is needed + //if ((_local_ctrl->peek32(RB32_CORE_STATUS) & 0xff) != B200_GPSDO_ST_NONE) + { UHD_LOGGER_INFO("B200") << "Detecting internal GPSDO.... " << std::flush; try { _gps = gps_ctrl::make(_async_task_data->gpsdo_uart); @@ -838,6 +842,14 @@ b200_impl::b200_impl( _tree->access(mb_path / "clock_source/value").set("internal"); _tree->access(mb_path / "time_source/value").set("internal"); + //GPS installed: use external ref, time, and init time spec + if (_gps and _gps->gps_detected()) { + const int freq = _gps->gps_refclock_frequency(); + if (not _adf4001_iface->set_refclk_frequency(freq)) { + throw uhd::value_error("Could not set refclk frequency"); + } + } + // Set the DSP chains to some safe value for (size_t i = 0; i < _radio_perifs.size(); i++) { _radio_perifs[i].ddc->set_host_rate( diff --git a/host/lib/usrp/common/adf4001_ctrl.cpp b/host/lib/usrp/common/adf4001_ctrl.cpp index a9f3c1fdb..8d080b294 100644 --- a/host/lib/usrp/common/adf4001_ctrl.cpp +++ b/host/lib/usrp/common/adf4001_ctrl.cpp @@ -116,6 +116,21 @@ void adf4001_ctrl::set_lock_to_ext_ref(bool external) program_regs(); } +bool adf4001_ctrl::set_refclk_frequency(int refclk_kHz) { + if (refclk_kHz == 30720) { + adf4001_regs.ref_counter = 96; + adf4001_regs.n = 125; + } else if (refclk_kHz == 10000) { + adf4001_regs.ref_counter = 1; + adf4001_regs.n = 4; + } else { + return false; + } + + program_regs(); + return true; +} + void adf4001_ctrl::program_regs(void) { // no control over CE, only LE, therefore we use the initialization latch method diff --git a/host/lib/usrp/gps_ctrl.cpp b/host/lib/usrp/gps_ctrl.cpp index 8026b32a2..dcd4df99c 100644 --- a/host/lib/usrp/gps_ctrl.cpp +++ b/host/lib/usrp/gps_ctrl.cpp @@ -37,6 +37,114 @@ constexpr int GPS_TIMEOUT_DELAY_MS = 200; constexpr int GPSDO_COMMAND_DELAY_MS = 200; } // namespace +/*! + * A NMEA and UBX Parser for the LEA-M8F and other GPSDOs + */ +class gps_ctrl_parser { +private: + std::deque gps_data_input; + + std::string parse_ubx() { + // Assumptions: + // The deque now contains an UBX message in the format + // \xb6\x62 + // where + // is 1 byte + // is 1 byte + // is 2 bytes (little-endian), length of + // is 2 bytes + + uint8_t ck_a = 0; + uint8_t ck_b = 0; + + if (gps_data_input.size() >= 8) { + uint8_t len_lo = gps_data_input[4]; + uint8_t len_hi = gps_data_input[5]; + size_t len = len_lo | (len_hi << 8); + + if (gps_data_input.size() >= len + 8) { + /* + std::cerr << "DATA: "; + for (size_t i=0; i < gps_data_input.size(); i++) { + uint8_t dat = gps_data_input[i]; + std::cerr << boost::format("%02x ") % (unsigned int)dat; + } + std::cerr << std::endl; // */ + + uint8_t ck_a_packet = gps_data_input[len+6]; + uint8_t ck_b_packet = gps_data_input[len+7]; + + // Range over which CRC is calculated is + for (size_t i = 2; i < len+6; i++) { + ck_a += (uint8_t)(gps_data_input[i]); + ck_b += ck_a; + } + + std::string msg(gps_data_input.begin(), gps_data_input.begin() + (len + 8)); + gps_data_input.erase(gps_data_input.begin(), gps_data_input.begin() + (len + 8)); + + if (ck_a == ck_a_packet and ck_b == ck_b_packet) { + return msg; + } + } + } + + return std::string(); + } + + std::string parse_nmea() { + // Assumptions: + // The deque now contains an NMEA message in the format + // $G.................*XX + // the checksum XX is dropped from the message + + std::deque::iterator star; + star = std::find(gps_data_input.begin() + 2, gps_data_input.end(), '*'); + if (star != gps_data_input.end()) { + std::string msg(gps_data_input.begin(), star); + + // The parser will take care of the leftover *XX + gps_data_input.erase(gps_data_input.begin(), star); + return msg; + } + + return std::string(); + } + +public: + template + void push_data(InputIterator first, InputIterator last) { + gps_data_input.insert(gps_data_input.end(), first, last); + } + + std::string get_next_message() { + while (gps_data_input.size() >= 2) { + char header1 = gps_data_input[0]; + char header2 = gps_data_input[1]; + + std::string parsed; + + if (header1 == '$' and header2 == 'G') { + parsed = parse_nmea(); + } + else if (header1 == '\xb5' and header2 == '\x62') { + parsed = parse_ubx(); + } + + if (parsed.empty()) { + gps_data_input.pop_front(); + } + else { + return parsed; + } + } + return std::string(); + } + + size_t size() { return gps_data_input.size(); } +}; + + /*! * A control for GPSDO devices */ @@ -52,6 +160,7 @@ private: std::map> sentences; std::mutex cache_mutex; boost::system_time _last_cache_update; + gps_ctrl_parser _gps_parser; std::string get_sentence(const std::string which, const int max_age_ms, @@ -135,38 +244,131 @@ private: return; } - const std::list keys{"GPGGA", "GPRMC", "SERVO"}; - static const std::regex servo_regex("^\\d\\d-\\d\\d-\\d\\d.*$"); - static const std::regex gp_msg_regex("^\\$GP.*,\\*[0-9A-F]{2}$"); - std::map msgs; - - // Get all GPSDO messages available - // Creating a map here because we only want the latest of each message type - for (std::string msg = _recv(0); not msg.empty(); msg = _recv(0)) { - // Strip any end of line characters - erase_all(msg, "\r"); - erase_all(msg, "\n"); - - if (msg.empty()) { - // Ignore empty strings - continue; + std::list keys; + std::map msgs; + + if (_gps_type == GPS_TYPE_LEA_M8F) { + keys = {"GNGGA", "GNRMC", "TIMELOCK", "DISCSRC"}; + + // Concatenate all incoming data into the deque + for (std::string msg = _recv(); msg.length() > 0; msg = _recv()) + { + _gps_parser.push_data(msg.begin(), msg.end()); } - if (msg.length() < 6) { - UHD_LOGGER_WARNING("GPS") - << UHD_FUNCTION << "(): Short GPSDO string: " << msg; - continue; + // Get all GPSDO messages available + // Creating a map here because we only want the latest of each message type + for (std::string msg = _gps_parser.get_next_message(); + not msg.empty(); + msg = _gps_parser.get_next_message()) + { + /* if (msg[0] != '$') { + std::stringstream ss; + ss << "Got message "; + for (size_t m = 0; m < msg.size(); m++) { + ss << std::hex << (unsigned int)(unsigned char)msg[m] << " " << std::dec; + } + std::cerr << ss.str() << "\n"; + } // */ + + const uint8_t tim_tos_head[4] = {0xb5, 0x62, 0x0D, 0x12}; + const std::string tim_tos_head_str(reinterpret_cast(tim_tos_head), 4); + + // Try to get NMEA first + if (msg[0] == '$') { + msgs[msg.substr(1,5)] = msg; + } + else if (msg.find(tim_tos_head_str) == 0 and msg.length() == 56 + 8) { + // header size == 6, field offset == 4, 32-bit field + uint8_t flags1 = msg[6 + 4]; + uint8_t flags2 = msg[6 + 5]; + uint8_t flags3 = msg[6 + 5]; + uint8_t flags4 = msg[6 + 5]; + + uint32_t flags = flags1 | (flags2 << 8) | (flags3 << 16) | (flags4 << 24); + /* bits in flags are: + leapNow 0 + leapSoon 1 + leapPositive 2 + timeInLimit 3 + intOscInLimit 4 + extOscInLimit 5 + gnssTimeValid 6 + UTCTimeValid 7 + DiscSrc 10 + raim 11 + cohPulse 12 + lockedPulse 13 + */ + + bool lockedPulse = (flags & (1 << 13)); + bool timeInLimit = (flags & (1 << 3)); + bool intOscInLimit = (flags & (1 << 4)); + uint8_t discSrc = (flags >> 8) & 0x07; + + if (lockedPulse and timeInLimit and intOscInLimit) { + msgs["TIMELOCK"] = "TIME LOCKED"; + } + else { + std::stringstream ss; + ss << + (lockedPulse ? "" : "no" ) << "lockedPulse " << + (timeInLimit ? "" : "no" ) << "timeInLimit " << + (intOscInLimit ? "" : "no" ) << "intOscInLimit "; + msgs["TIMELOCK"] = ss.str(); + } + + switch (discSrc) { + case 0: msgs["DISCSRC"] = "internal"; break; + case 1: msgs["DISCSRC"] = "gnss"; break; + default: msgs["DISCSRC"] = "other"; break; + } + } + else if (msg[0] == '\xb5' and msg[1] == '\x62') { /* Ignore unsupported UBX message */ } + else { + std::stringstream ss; + ss << "Unknown message "; + for (size_t m = 0; m < msg.size(); m++) { + ss << std::hex << (unsigned int)(unsigned char)msg[m] << " " << std::dec; + } + UHD_LOGGER_WARNING("GPS") << ss.str() << ":" << msg << std::endl; + } } + } + else { + const std::list keys{"GPGGA", "GPRMC", "SERVO"}; + static const std::regex servo_regex("^\\d\\d-\\d\\d-\\d\\d.*$"); + static const std::regex gp_msg_regex("^\\$GP.*,\\*[0-9A-F]{2}$"); + std::map msgs; + + // Get all GPSDO messages available + // Creating a map here because we only want the latest of each message type + for (std::string msg = _recv(0); not msg.empty(); msg = _recv(0)) { + // Strip any end of line characters + erase_all(msg, "\r"); + erase_all(msg, "\n"); + + if (msg.empty()) { + // Ignore empty strings + continue; + } - // Look for SERVO message - if (std::regex_search( - msg, servo_regex, std::regex_constants::match_continuous)) { - msgs["SERVO"] = msg; - } else if (std::regex_match(msg, gp_msg_regex) and is_nmea_checksum_ok(msg)) { - msgs[msg.substr(1, 5)] = msg; - } else { - UHD_LOGGER_WARNING("GPS") - << UHD_FUNCTION << "(): Malformed GPSDO string: " << msg; + if (msg.length() < 6) { + UHD_LOGGER_WARNING("GPS") + << UHD_FUNCTION << "(): Short GPSDO string: " << msg; + continue; + } + + // Look for SERVO message + if (std::regex_search( + msg, servo_regex, std::regex_constants::match_continuous)) { + msgs["SERVO"] = msg; + } else if (std::regex_match(msg, gp_msg_regex) and is_nmea_checksum_ok(msg)) { + msgs[msg.substr(1, 5)] = msg; + } else { + UHD_LOGGER_WARNING("GPS") + << UHD_FUNCTION << "(): Malformed GPSDO string: " << msg; + } } } @@ -192,12 +394,13 @@ public: _flush(); // get whatever junk is in the rx buffer right now, and throw it away _send("*IDN?\r\n"); // request identity from the GPSDO + _send("\xB5\x62\x0A\x04\x00\x00\x0E\x34"); // poll UBX-MON-VER - // then we loop until we either timeout, or until we get a response that indicates - // we're a JL device maximum response time was measured at ~320ms, so we set the - // timeout at 650ms + //then we loop until we either timeout, or until we get a response that indicates we're a JL device + //maximum response time was measured at ~320ms, so we set the timeout at 650ms + // For the LEA-M8F, increase the timeout to over one second to increase detection likelihood. const boost::system_time comm_timeout = - boost::get_system_time() + milliseconds(650); + boost::get_system_time() + milliseconds(1200); while (boost::get_system_time() < comm_timeout) { reply = _recv(); // known devices are JL "FireFly", "GPSTCXO", and "LC_XO" @@ -208,13 +411,25 @@ public: break; } else if (reply.substr(0, 3) == "$GP") { i_heard_some_nmea = true; // but keep looking + } else if (reply.substr(0, 3) == "$GN") { + // The u-blox LEA-M8F outputs UBX and GNxxx messages + UHD_LOGGER_DEBUG("GPS") << "Heard $GNxxx message, assume LEA-M8F"; + _gps_type = GPS_TYPE_LEA_M8F; + break; + } else if (reply.substr(0, 2) == "\xB5""\x62") { + // The u-blox LEA-M8F outputs UBX and GNxxx messages + UHD_LOGGER_DEBUG("GPS") << "Heard UBX message, assume LEA-M8F"; + _gps_type = GPS_TYPE_LEA_M8F; + break; } else if (not reply.empty()) { // wrong baud rate or firmware still initializing i_heard_something_weird = true; _send("*IDN?\r\n"); // re-send identity request + _send("\xB5\x62\x0A\x04\x00\x00\x0E\x34"); // poll UBX-MON-VER } else { // _recv timed out _send("*IDN?\r\n"); // re-send identity request + _send("\xB5\x62\x0A\x04\x00\x00\x0E\x34"); // poll UBX-MON-VER } } @@ -239,6 +454,11 @@ public: UHD_LOGGER_INFO("GPS") << "Found a generic NMEA GPS device"; break; + case GPS_TYPE_LEA_M8F: + UHD_LOGGER_INFO("GPS") << "Found a LEA-M8F GPS device"; + init_lea_m8f(); + break; + case GPS_TYPE_NONE: default: UHD_LOGGER_INFO("GPS") << "No GPSDO found"; @@ -258,13 +478,18 @@ public: std::vector get_sensors(void) override { std::vector ret{ - "gps_gpgga", "gps_gprmc", "gps_time", "gps_locked", "gps_servo"}; + "gps_gngga", "gps_gnrmc", "gps_timelock", "gps_discsrc", + "gps_gpgga", "gps_gprmc", "gps_time", "gps_locked", "gps_servo"}; return ret; } uhd::sensor_value_t get_sensor(std::string key) override { - if (key == "gps_gpgga" or key == "gps_gprmc") { + if (key == "gps_gpgga" or key == "gps_gprmc" + or key == "gps_gngga" + or key == "gps_gnrmc" + or key == "gps_timelock" + or key == "gps_discsrc") { return sensor_value_t(boost::to_upper_copy(key), get_sentence(boost::to_upper_copy(key.substr(4, 8)), GPS_NMEA_NORMAL_FRESHNESS, @@ -306,6 +531,15 @@ private: } } + void init_lea_m8f(void) { + // Enable the UBX-TIM-TOS and the $GNRMC messages + const uint8_t en_tim_tos[11] = {0xb5, 0x62, 0x06, 0x01, 0x03, 0x00, 0x0d, 0x12, 0x01, 0x2a, 0x8b}; + _send(std::string(reinterpret_cast(en_tim_tos), sizeof(en_tim_tos))); + + const uint8_t en_gnrmc[11] = {0xb5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xf0, 0x04, 0x01, 0xff, 0x18}; + _send(std::string(reinterpret_cast(en_gnrmc), sizeof(en_gnrmc))); + } + // helper function to retrieve a field from an NMEA sentence std::string get_token(std::string sentence, size_t offset) { @@ -325,11 +559,11 @@ private: { int error_cnt = 0; ptime gps_time; + const std::string rmc = (_gps_type == GPS_TYPE_LEA_M8F) ? "GNRMC" : "GPRMC"; while (error_cnt < 2) { try { // wait for next GPRMC string - std::string reply = get_sentence( - "GPRMC", GPS_NMEA_NORMAL_FRESHNESS, GPS_COMM_TIMEOUT_MS, true); + std::string reply = get_sentence(rmc, GPS_NMEA_NORMAL_FRESHNESS, GPS_COMM_TIMEOUT_MS, true); std::string datestr = get_token(reply, 9); std::string timestr = get_token(reply, 1); @@ -374,17 +608,35 @@ private: return (_gps_type != GPS_TYPE_NONE); } + int gps_refclock_frequency(void) + { + if (_gps_type == GPS_TYPE_LEA_M8F) { + return 30720; + } + else if (_gps_type != GPS_TYPE_NONE) { + return 10000; + } + return 0; + } + bool locked(void) { int error_cnt = 0; + const std::string locksentence = (_gps_type == GPS_TYPE_LEA_M8F) ? "TIMELOCK" : "GPGGA"; while (error_cnt < 3) { try { std::string reply = - get_sentence("GPGGA", GPS_LOCK_FRESHNESS, GPS_COMM_TIMEOUT_MS); + get_sentence(locksentence, GPS_LOCK_FRESHNESS, GPS_COMM_TIMEOUT_MS); if (reply.empty()) error_cnt++; - else - return (get_token(reply, 6) != "0"); + else { + if (_gps_type == GPS_TYPE_LEA_M8F) { + return reply == "TIME LOCKED"; + } + else { + return (get_token(reply, 6) != "0"); + } + } } catch (std::exception& e) { UHD_LOGGER_DEBUG("GPS") << "locked: " << e.what(); error_cnt++; @@ -412,7 +664,12 @@ private: return _uart->write_uart(buf); } - enum { GPS_TYPE_INTERNAL_GPSDO, GPS_TYPE_GENERIC_NMEA, GPS_TYPE_NONE } _gps_type; + enum { + GPS_TYPE_INTERNAL_GPSDO, + GPS_TYPE_GENERIC_NMEA, + GPS_TYPE_LEA_M8F, + GPS_TYPE_NONE + } _gps_type; }; /*********************************************************************** @@ -422,3 +679,4 @@ gps_ctrl::sptr gps_ctrl::make(uart_iface::sptr uart) { return sptr(new gps_ctrl_impl(uart)); } + diff --git a/host/utils/query_gpsdo_sensors.cpp b/host/utils/query_gpsdo_sensors.cpp index 51ea15686..f22624a7b 100644 --- a/host/utils/query_gpsdo_sensors.cpp +++ b/host/utils/query_gpsdo_sensors.cpp @@ -26,6 +26,9 @@ namespace po = boost::program_options; namespace fs = boost::filesystem; +const size_t WARMUP_TIMEOUT_MS = 30000; +const size_t LOCK_TIMEOUT_MS = 60000; + void print_notes(void) { // Helpful notes @@ -58,16 +61,31 @@ int query_clock_sensors(const std::string& args) // Print NMEA strings try { - uhd::sensor_value_t gga_string = clock->get_sensor("gps_gpgga"); - uhd::sensor_value_t rmc_string = clock->get_sensor("gps_gprmc"); + uhd::sensor_value_t gpgga_string = clock->get_sensor("gps_gpgga"); + uhd::sensor_value_t gprmc_string = clock->get_sensor("gps_gprmc"); uhd::sensor_value_t servo_string = clock->get_sensor("gps_servo"); - std::cout << "\nPrinting available NMEA strings:\n"; - std::cout << boost::format("%s\n%s\n") % gga_string.to_pp_string() - % rmc_string.to_pp_string(); - std::cout << "\nPrinting GPS servo status:\n"; + std::cout << boost::format("\nPrinting available NMEA strings:\n"); + std::cout << boost::format("%s\n%s\n") % gpgga_string.to_pp_string() + % gprmc_string.to_pp_string(); + std::cout << boost::format("\nPrinting GPS servo status:\n"); std::cout << boost::format("%s\n\n") % servo_string.to_pp_string(); } catch (const uhd::lookup_error&) { - std::cout << "NMEA strings not implemented for this device." << std::endl; + std::cout << "GPxxx NMEA strings not implemented for this device." << std::endl; + } + + try { + uhd::sensor_value_t gngga_string = clock->get_sensor("gps_gngga"); + uhd::sensor_value_t gnrmc_string = clock->get_sensor("gps_gnrmc"); + uhd::sensor_value_t timelock_string = clock->get_sensor("gps_timelock"); + uhd::sensor_value_t discsrc_string = clock->get_sensor("gps_discsrc"); + std::cout << boost::format("%s\n%s\n") % gngga_string.to_pp_string() + % gnrmc_string.to_pp_string(); + std::cout << boost::format("\nPrinting GPS timelock:\n"); + std::cout << boost::format("%s\n\n") % timelock_string.to_pp_string(); + std::cout << boost::format("%s\n\n") % discsrc_string.to_pp_string(); + + } catch (const uhd::lookup_error&) { + std::cout << "GNxxx NMEA strings or timelock not implemented for this device." << std::endl; } std::cout << boost::format("GPS Epoch time: %.5f seconds\n") % clock->get_sensor("gps_time").to_real(); @@ -119,6 +137,11 @@ int UHD_SAFE_MAIN(int argc, char* argv[]) // Verify GPS sensors are present (i.e. EEPROM has been burnt) std::vector sensor_names = usrp->get_mboard_sensor_names(0); + std::cout << " Sensors: " << std::endl; + for (const auto& name : sensor_names) { + std::cout << " Sensor: " << name << std::endl; + } + if (std::find(sensor_names.begin(), sensor_names.end(), "gps_locked") == sensor_names.end()) { std::cout << "\ngps_locked sensor not found. This could mean that " @@ -247,14 +270,26 @@ int UHD_SAFE_MAIN(int argc, char* argv[]) std::cout << "Printing available NMEA strings:\n"; try { std::cout << usrp->get_mboard_sensor("gps_gpgga").to_pp_string() << std::endl; - } catch (uhd::lookup_error&) { + } catch (uhd::value_error&) { std::cout << "GPGGA string not available for this device." << std::endl; } try { std::cout << usrp->get_mboard_sensor("gps_gprmc").to_pp_string() << std::endl; - } catch (uhd::lookup_error&) { + } catch (uhd::value_error&) { std::cout << "GPRMC string not available for this device." << std::endl; } + + try { + std::cout << usrp->get_mboard_sensor("gps_gngga").to_pp_string() << std::endl; + } catch (uhd::value_error&) { + std::cout << "GNGGA string not available for this device." << std::endl; + } + try { + std::cout << usrp->get_mboard_sensor("gps_gnrmc").to_pp_string() << std::endl; + } catch (uhd::value_error&) { + std::cout << "GNRMC string not available for this device." << std::endl; + } + std::cout << boost::format("GPS Epoch time at last PPS: %.5f seconds\n") % usrp->get_mboard_sensor("gps_time").to_real(); std::cout << boost::format("UHD Device time last PPS: %.5f seconds\n") -- cgit v1.2.3