From 8f6e2ac9972151318bf6883d45ee099a5013ae1e Mon Sep 17 00:00:00 2001 From: michael-west Date: Sat, 10 May 2014 19:40:15 -0700 Subject: Fix for BUG #469: Bad/Empty GPS NMEA strings returned when the queries are made in a random wait iterative fashion Fix for BUG #460: X300: GPGGA sensor most often empty, while RMC is usually OK - Added checksum verification of NMEA strings - Improved handling of short or malformed strings - Fixed GPSDO data synchronization between X300 firmware and host --- host/lib/usrp/gps_ctrl.cpp | 39 +++++++++++++--- host/lib/usrp/x300/x300_fw_uart.cpp | 89 ++++++++++++++++++++++++++++++------- 2 files changed, 108 insertions(+), 20 deletions(-) (limited to 'host/lib') diff --git a/host/lib/usrp/gps_ctrl.cpp b/host/lib/usrp/gps_ctrl.cpp index d327a84f9..b211ba027 100644 --- a/host/lib/usrp/gps_ctrl.cpp +++ b/host/lib/usrp/gps_ctrl.cpp @@ -62,6 +62,20 @@ private: return std::string(); } + static bool is_nmea_checksum_ok(std::string nmea) + { + if (nmea.length() < 5 || nmea[0] != '$' || nmea[nmea.length()-3] != '*') + return false; + + uint8_t string_crc = uint8_t(strtol(nmea.substr(nmea.length()-2, 2).c_str(), NULL, 16)); + uint8_t calculated_crc = 0; + + for (size_t i = 1; i < nmea.length()-3; i++) + calculated_crc ^= nmea[i]; + + return (string_crc == calculated_crc); + } + std::string update_cached_sensors(const std::string sensor) { if(not gps_detected() || (gps_type != GPS_TYPE_INTERNAL_GPSDO)) { UHD_MSG(error) << "get_stat(): unsupported GPS or no GPS detected"; @@ -70,24 +84,40 @@ private: const std::list list = boost::assign::list_of("GPGGA")("GPRMC")("SERVO"); static const boost::regex status_regex("\\d\\d-\\d\\d-\\d\\d"); + static const boost::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(); msg.length(); msg = _recv()) { - if (msg.length() < 6) - continue; - // Strip any end of line characters erase_all(msg, "\r"); erase_all(msg, "\n"); + if (msg.length() < 6) + { +#ifdef DEBUG_GPS + UHD_MSG(error) << __FUNCTION__ << ": Short NMEA string: " << msg << std::endl; +#endif + continue; + } + // Look for SERVO message if (boost::regex_search(msg, status_regex, boost::regex_constants::match_continuous)) + { msgs["SERVO"] = msg; - else + } + else if (boost::regex_match(msg, gp_msg_regex) && is_nmea_checksum_ok(msg)) + { msgs[msg.substr(1,5)] = msg; + } +#ifdef DEBUG_GPS + else + { + UHD_MSG(error) << __FUNCTION__ << ": Malformed NMEA string: " << msg << std::endl; + } +#endif } boost::system_time time = boost::get_system_time(); @@ -131,7 +161,6 @@ public: } else if(reply.substr(0, 3) == "$GP") i_heard_some_nmea = true; //but keep looking for that "Command Error" response else if(reply.length() != 0) i_heard_something_weird = true; //probably wrong baud rate - sleep(milliseconds(GPS_TIMEOUT_DELAY_MS)); } if((i_heard_some_nmea) && (gps_type != GPS_TYPE_INTERNAL_GPSDO)) gps_type = GPS_TYPE_GENERIC_NMEA; diff --git a/host/lib/usrp/x300/x300_fw_uart.cpp b/host/lib/usrp/x300/x300_fw_uart.cpp index 943b2d9fa..4bf103c5a 100644 --- a/host/lib/usrp/x300/x300_fw_uart.cpp +++ b/host/lib/usrp/x300/x300_fw_uart.cpp @@ -38,6 +38,8 @@ struct x300_uart_iface : uart_iface rxpool = _iface->peek32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_UART_RX_ADDR)); txpool = _iface->peek32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_UART_TX_ADDR)); poolsize = _iface->peek32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_UART_WORDS32)); + _rxcache.resize(poolsize); + _last_device_rxoffset = rxoffset; //this->write_uart("HELLO UART\n"); //this->read_uart(0.1); } @@ -63,39 +65,96 @@ struct x300_uart_iface : uart_iface int getchar(void) { - if (_iface->peek32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_UART_RX_INDEX)) != rxoffset) + if (rxoffset == _last_device_rxoffset) + return -1; + + rxoffset++; + return int(_rxcache[((rxoffset)/4) % poolsize] >> ((rxoffset%4)*8) & 0xFF); + } + + void update_cache(void) + { + uint32_t device_rxoffset = _iface->peek32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_UART_RX_INDEX)); + uint32_t delta = device_rxoffset - rxoffset; + + while (delta) { - const int shift = ((rxoffset%4) * 8); - const char ch = _iface->peek32(SR_ADDR(rxpool, rxoffset/4)) >> shift; - rxoffset = (rxoffset + 1) % (poolsize*4); - return ch; + if (delta >= poolsize*4) + { + // all the data is new - reload the entire cache + for (uint32_t i = 0; i < poolsize; i++) + _rxcache[i] = _iface->peek32(SR_ADDR(rxpool, i)); + + // set rxoffset to the end of the first string + rxoffset = device_rxoffset - (poolsize*4) + 1; + while (uint8_t(_rxcache[(rxoffset/4) % poolsize] >> ((rxoffset % 4) * 8)) != '\n') + ++rxoffset; + + // clear the partial string in the buffer; + _rxbuff.clear(); + } + else if (rxoffset == _last_device_rxoffset) + { + // new data was added - refresh the portion of the cache that was updated + for (uint32_t i = ((_last_device_rxoffset+1)/4) % poolsize; i != (((device_rxoffset)/4)+1) % poolsize; i = (i+1) % poolsize) + { + _rxcache[i] = _iface->peek32(SR_ADDR(rxpool, i)); + } + } else { + // there is new data, but we aren't done with what we have - check back later + break; + } + + _last_device_rxoffset = device_rxoffset; + + // check again to see if anything changed while we were updating the cache + device_rxoffset = _iface->peek32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_UART_RX_INDEX)); + delta = device_rxoffset - rxoffset; } - return -1; } std::string read_uart(double timeout) { const boost::system_time exit_time = boost::get_system_time() + boost::posix_time::microseconds(long(timeout*1e6)); std::string buff; + while (true) { - const int ch = this->getchar(); - if (ch == -1) + // Update cache + this->update_cache(); + + // Get available characters + for (int ch = this->getchar(); ch != -1; ch = this->getchar()) { - if (boost::get_system_time() > exit_time) break; - boost::this_thread::sleep(boost::posix_time::milliseconds(1)); - continue; + // skip carriage returns + if (ch == '\r') + continue; + + // store character to buffer + _rxbuff += std::string(1, (char)ch); + + // newline found - return string + if (ch == '\n') + { + buff = _rxbuff; + _rxbuff.clear(); + return buff; + } } - if (ch == '\r') continue; - buff += std::string(1, (char)ch); - if (ch == '\n') break; + + // no more characters - check time + if (boost::get_system_time() > exit_time) + break; } - //UHD_VAR(buff); + return buff; } wb_iface::sptr _iface; boost::uint32_t rxoffset, txoffset, txword32, rxpool, txpool, poolsize; + boost::uint32_t _last_device_rxoffset; + std::vector _rxcache; + std::string _rxbuff; }; uart_iface::sptr x300_make_uart_iface(wb_iface::sptr iface) -- cgit v1.2.3 From 208d85167838b0bb90d0938c791c1eae4b788e4d Mon Sep 17 00:00:00 2001 From: michael-west Date: Thu, 12 Jun 2014 14:41:02 -0700 Subject: Addressing comments from review. - Corrected types of some variables to be boost types. - Removed debugging code accidentally left in. - Changed some compiled out error messages to log messages. --- firmware/x300/x300/x300_main.c | 11 ++--------- host/lib/usrp/gps_ctrl.cpp | 20 ++++++++++++-------- host/lib/usrp/x300/x300_fw_uart.cpp | 16 +++++++++------- 3 files changed, 23 insertions(+), 24 deletions(-) (limited to 'host/lib') diff --git a/firmware/x300/x300/x300_main.c b/firmware/x300/x300/x300_main.c index 8717bf690..d865e1d09 100644 --- a/firmware/x300/x300/x300_main.c +++ b/firmware/x300/x300/x300_main.c @@ -1,4 +1,4 @@ -// Copyright 2013 Ettus Research LLC +// Copyright 2013-2014 Ettus Research LLC #include "x300_init.h" #include "x300_defs.h" @@ -445,24 +445,17 @@ int main(void) static const uint32_t tick_delta = CPU_CLOCK/1000; if (ticks_passed > tick_delta) { -// handle_link_state(); //deal with router table update + handle_link_state(); //deal with router table update handle_claim(); //deal with the host claim register -handle_uarts(); //udp_uart_poll(); update_leds(); //run the link and activity leds -handle_uarts(); //udp_uart_poll(); garp(); //send periodic garps -handle_uarts(); //udp_uart_poll(); xge_poll_sfpp_status(0); // Every so often poll XGE Phy to look for SFP+ hotplug events. -handle_uarts(); //udp_uart_poll(); xge_poll_sfpp_status(1); // Every so often poll XGE Phy to look for SFP+ hotplug events. -handle_uarts(); //udp_uart_poll(); last_cronjob = wb_peek32(SR_ADDR(RB0_BASE, RB_COUNTER)); } -//handle_uarts(); //udp_uart_poll(); //run the network stack - poll and handle u3_net_stack_handle_one(); -handle_uarts(); //udp_uart_poll(); //run the PCIe listener - poll and fwd to wishbone forward_pcie_user_xact_to_wb(); diff --git a/host/lib/usrp/gps_ctrl.cpp b/host/lib/usrp/gps_ctrl.cpp index b211ba027..3d7684849 100644 --- a/host/lib/usrp/gps_ctrl.cpp +++ b/host/lib/usrp/gps_ctrl.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -67,12 +68,19 @@ private: if (nmea.length() < 5 || nmea[0] != '$' || nmea[nmea.length()-3] != '*') return false; - uint8_t string_crc = uint8_t(strtol(nmea.substr(nmea.length()-2, 2).c_str(), NULL, 16)); - uint8_t calculated_crc = 0; + std::stringstream ss; + boost::uint8_t string_crc; + boost::uint8_t calculated_crc = 0; + // get crc from string + ss << std::hex << nmea.substr(nmea.length()-2, 2); + ss >> string_crc; + + // calculate crc for (size_t i = 1; i < nmea.length()-3; i++) calculated_crc ^= nmea[i]; + // return comparison return (string_crc == calculated_crc); } @@ -97,9 +105,7 @@ private: if (msg.length() < 6) { -#ifdef DEBUG_GPS - UHD_MSG(error) << __FUNCTION__ << ": Short NMEA string: " << msg << std::endl; -#endif + UHD_LOGV(regularly) << __FUNCTION__ << ": Short NMEA string: " << msg << std::endl; continue; } @@ -112,12 +118,10 @@ private: { msgs[msg.substr(1,5)] = msg; } -#ifdef DEBUG_GPS else { - UHD_MSG(error) << __FUNCTION__ << ": Malformed NMEA string: " << msg << std::endl; + UHD_LOGV(regularly) << __FUNCTION__ << ": Malformed NMEA string: " << msg << std::endl; } -#endif } boost::system_time time = boost::get_system_time(); diff --git a/host/lib/usrp/x300/x300_fw_uart.cpp b/host/lib/usrp/x300/x300_fw_uart.cpp index 4bf103c5a..d87b9ab9f 100644 --- a/host/lib/usrp/x300/x300_fw_uart.cpp +++ b/host/lib/usrp/x300/x300_fw_uart.cpp @@ -69,25 +69,25 @@ struct x300_uart_iface : uart_iface return -1; rxoffset++; - return int(_rxcache[((rxoffset)/4) % poolsize] >> ((rxoffset%4)*8) & 0xFF); + return static_cast(_rxcache[(rxoffset/4) % poolsize] >> ((rxoffset%4)*8) & 0xFF); } void update_cache(void) { - uint32_t device_rxoffset = _iface->peek32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_UART_RX_INDEX)); - uint32_t delta = device_rxoffset - rxoffset; + boost::uint32_t device_rxoffset = _iface->peek32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_UART_RX_INDEX)); + boost::uint32_t delta = device_rxoffset - rxoffset; while (delta) { if (delta >= poolsize*4) { // all the data is new - reload the entire cache - for (uint32_t i = 0; i < poolsize; i++) + for (boost::uint32_t i = 0; i < poolsize; i++) _rxcache[i] = _iface->peek32(SR_ADDR(rxpool, i)); // set rxoffset to the end of the first string rxoffset = device_rxoffset - (poolsize*4) + 1; - while (uint8_t(_rxcache[(rxoffset/4) % poolsize] >> ((rxoffset % 4) * 8)) != '\n') + while (static_cast((_rxcache[(rxoffset/4) % poolsize] >> ((rxoffset%4)*8) & 0xFF)) != '\n') ++rxoffset; // clear the partial string in the buffer; @@ -96,7 +96,7 @@ struct x300_uart_iface : uart_iface else if (rxoffset == _last_device_rxoffset) { // new data was added - refresh the portion of the cache that was updated - for (uint32_t i = ((_last_device_rxoffset+1)/4) % poolsize; i != (((device_rxoffset)/4)+1) % poolsize; i = (i+1) % poolsize) + for (boost::uint32_t i = ((_last_device_rxoffset+1)/4) % poolsize; i != (((device_rxoffset)/4)+1) % poolsize; i = (i+1) % poolsize) { _rxcache[i] = _iface->peek32(SR_ADDR(rxpool, i)); } @@ -115,6 +115,7 @@ struct x300_uart_iface : uart_iface std::string read_uart(double timeout) { + boost::mutex::scoped_lock(_read_mutex); const boost::system_time exit_time = boost::get_system_time() + boost::posix_time::microseconds(long(timeout*1e6)); std::string buff; @@ -153,8 +154,9 @@ struct x300_uart_iface : uart_iface wb_iface::sptr _iface; boost::uint32_t rxoffset, txoffset, txword32, rxpool, txpool, poolsize; boost::uint32_t _last_device_rxoffset; - std::vector _rxcache; + std::vector _rxcache; std::string _rxbuff; + boost::mutex _read_mutex; }; uart_iface::sptr x300_make_uart_iface(wb_iface::sptr iface) -- cgit v1.2.3 From 863953d972f19f38fb82eb17d1fe923a0337b0ed Mon Sep 17 00:00:00 2001 From: michael-west Date: Thu, 12 Jun 2014 16:07:42 -0700 Subject: - Changed variables from uint8_t to uint32_t so parsing of hex strings would work properly. --- host/lib/usrp/gps_ctrl.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'host/lib') diff --git a/host/lib/usrp/gps_ctrl.cpp b/host/lib/usrp/gps_ctrl.cpp index 3d7684849..6b3f73cf6 100644 --- a/host/lib/usrp/gps_ctrl.cpp +++ b/host/lib/usrp/gps_ctrl.cpp @@ -69,8 +69,8 @@ private: return false; std::stringstream ss; - boost::uint8_t string_crc; - boost::uint8_t calculated_crc = 0; + boost::uint32_t string_crc; + boost::uint32_t calculated_crc = 0; // get crc from string ss << std::hex << nmea.substr(nmea.length()-2, 2); @@ -114,7 +114,7 @@ private: { msgs["SERVO"] = msg; } - else if (boost::regex_match(msg, gp_msg_regex) && is_nmea_checksum_ok(msg)) + else if (boost::regex_match(msg, gp_msg_regex) and is_nmea_checksum_ok(msg)) { msgs[msg.substr(1,5)] = msg; } -- cgit v1.2.3 From 6e740108bf2c32632d8dc107270b49b6de3ba16d Mon Sep 17 00:00:00 2001 From: michael-west Date: Tue, 15 Jul 2014 15:18:47 -0700 Subject: Fix for BUG #469 - Added mutex for write_uart() --- host/lib/usrp/x300/x300_fw_uart.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'host/lib') diff --git a/host/lib/usrp/x300/x300_fw_uart.cpp b/host/lib/usrp/x300/x300_fw_uart.cpp index d87b9ab9f..b0fae124d 100644 --- a/host/lib/usrp/x300/x300_fw_uart.cpp +++ b/host/lib/usrp/x300/x300_fw_uart.cpp @@ -56,6 +56,7 @@ struct x300_uart_iface : uart_iface void write_uart(const std::string &buff) { + boost::mutex::scoped_lock(_write_mutex); BOOST_FOREACH(const char ch, buff) { if (ch == '\n') this->putchar('\r'); @@ -157,6 +158,7 @@ struct x300_uart_iface : uart_iface std::vector _rxcache; std::string _rxbuff; boost::mutex _read_mutex; + boost::mutex _write_mutex; }; uart_iface::sptr x300_make_uart_iface(wb_iface::sptr iface) -- cgit v1.2.3 From afb4cb4d4a3869131530fa6c5d76b812d6fea0aa Mon Sep 17 00:00:00 2001 From: michael-west Date: Thu, 17 Jul 2014 11:58:33 -0700 Subject: Updated copyright year. --- host/lib/usrp/gps_ctrl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'host/lib') diff --git a/host/lib/usrp/gps_ctrl.cpp b/host/lib/usrp/gps_ctrl.cpp index 6b3f73cf6..f4d5cd8e8 100644 --- a/host/lib/usrp/gps_ctrl.cpp +++ b/host/lib/usrp/gps_ctrl.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-2011,2014 Ettus Research LLC // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by -- cgit v1.2.3