aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2018-02-10 18:18:25 +0100
committerMatthias P. Braendli <matthias.braendli@mpb.li>2022-08-17 10:52:09 +0200
commitf24a67182541b41ebf924e983660c9dc48c8bbd8 (patch)
tree041fb98170ee3e1ab21e482d52482a6c48ac7084
parent321295fba49fb66ede365afbd9ef62971cdfbfca (diff)
downloaduhd-f24a67182541b41ebf924e983660c9dc48c8bbd8.tar.gz
uhd-f24a67182541b41ebf924e983660c9dc48c8bbd8.tar.bz2
uhd-f24a67182541b41ebf924e983660c9dc48c8bbd8.zip
Add support for LEA-M8F GPSDO boardlea-m8f-v4.2.0.1
-rw-r--r--host/include/uhd/usrp/gps_ctrl.hpp9
-rw-r--r--host/lib/include/uhdlib/usrp/common/adf4001_ctrl.hpp1
-rw-r--r--host/lib/usrp/b200/b200_cores.cpp8
-rw-r--r--host/lib/usrp/b200/b200_cores.hpp1
-rw-r--r--host/lib/usrp/b200/b200_impl.cpp16
-rw-r--r--host/lib/usrp/common/adf4001_ctrl.cpp15
-rw-r--r--host/lib/usrp/gps_ctrl.cpp338
-rw-r--r--host/utils/query_gpsdo_sensors.cpp53
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<std::string>(mb_path / "clock_source/value").set("internal");
_tree->access<std::string>(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
@@ -38,6 +38,114 @@ 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<char> gps_data_input;
+
+ std::string parse_ubx() {
+ // Assumptions:
+ // The deque now contains an UBX message in the format
+ // \xb6\x62<CLASS><ID><LEN><PAYLOAD><CRC>
+ // where
+ // <CLASS> is 1 byte
+ // <ID> is 1 byte
+ // <LEN> is 2 bytes (little-endian), length of <PAYLOAD>
+ // <CRC> 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 <CLASS><ID><LEN><PAYLOAD>
+ 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<CR><LF>
+ // the checksum XX is dropped from the message
+
+ std::deque<char>::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<CR><LF>
+ gps_data_input.erase(gps_data_input.begin(), star);
+ return msg;
+ }
+
+ return std::string();
+ }
+
+public:
+ template <class InputIterator>
+ 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<std::string, std::tuple<std::string, boost::system_time, bool>> 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<std::string> 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<std::string, std::string> 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<std::string> keys;
+ std::map<std::string,std::string> 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<const char *>(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<std::string> 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<std::string, std::string> 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<std::string> get_sensors(void) override
{
std::vector<std::string> 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<const char *>(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<const char *>(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<std::string> 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")