From 196e93a387dea47ab8a3ad600b90446e98840a54 Mon Sep 17 00:00:00 2001 From: michael-west Date: Thu, 14 Jul 2016 17:57:15 -0700 Subject: Add thread safety to gps_ctrl cached sensors --- host/lib/usrp/gps_ctrl.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/gps_ctrl.cpp b/host/lib/usrp/gps_ctrl.cpp index 207ef10ab..32ed80dc3 100644 --- a/host/lib/usrp/gps_ctrl.cpp +++ b/host/lib/usrp/gps_ctrl.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "boost/tuple/tuple.hpp" #include "boost/foreach.hpp" @@ -49,8 +50,10 @@ gps_ctrl::~gps_ctrl(void){ class gps_ctrl_impl : public gps_ctrl{ private: std::map > sensors; + boost::mutex cache_mutex; std::string get_cached_sensor(const std::string sensor, const int freshness, const bool once, const bool touch=true) { + boost::mutex::scoped_lock lock(cache_mutex); boost::system_time time = boost::get_system_time(); try { // this is nasty ... -- cgit v1.2.3 From 59ed6e1a0f9710c7bfca0a348d07f8c96f9f6bc0 Mon Sep 17 00:00:00 2001 From: michael-west Date: Mon, 18 Jul 2016 14:34:00 -0700 Subject: GPSDO: Make sure read_uart() returns only complete strings for all devices. --- host/include/uhd/types/serial.hpp | 15 +++++++-------- host/lib/transport/udp_simple.cpp | 14 +++++++++++--- host/lib/usrp/b200/b200_uart.cpp | 23 +++++++++++++---------- host/lib/usrp/e100/e100_ctrl.cpp | 17 ++++++++++++----- host/lib/usrp/x300/x300_fw_uart.cpp | 4 ++++ host/lib/usrp_clock/octoclock/octoclock_uart.cpp | 1 + 6 files changed, 48 insertions(+), 26 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/include/uhd/types/serial.hpp b/host/include/uhd/types/serial.hpp index 7b565c633..dca0cfb2a 100644 --- a/host/include/uhd/types/serial.hpp +++ b/host/include/uhd/types/serial.hpp @@ -124,7 +124,7 @@ namespace uhd{ */ spi_config_t(edge_t edge = EDGE_RISE); }; - + /*! * The SPI interface class. * Provides routines to transact SPI and do other useful things which haven't been defined yet. @@ -151,12 +151,12 @@ namespace uhd{ size_t num_bits, bool readback ) = 0; - + /*! * Read from the SPI bus. * \param which_slave the slave device number * \param config spi config args - * \param data the bits to write out (be sure to set write bit) + * \param data the bits to write out (be sure to set write bit) * \param num_bits how many bits in data * \return spi data */ @@ -166,7 +166,7 @@ namespace uhd{ boost::uint32_t data, size_t num_bits ); - + /*! * Write to the SPI bus. * \param which_slave the slave device number @@ -183,7 +183,7 @@ namespace uhd{ }; /*! - * UART interface to write and read bytes. + * UART interface to write and read strings. */ class UHD_API uart_iface{ public: @@ -198,10 +198,9 @@ namespace uhd{ virtual void write_uart(const std::string &buf) = 0; /*! - * Read from a serial port. - * Reads until complete line or timeout. + * Read a line from a serial port. * \param timeout the timeout in seconds - * \return the data read from the serial port + * \return the line or empty string upon timeout */ virtual std::string read_uart(double timeout) = 0; }; diff --git a/host/lib/transport/udp_simple.cpp b/host/lib/transport/udp_simple.cpp index 347373c71..8b6e5eb2b 100644 --- a/host/lib/transport/udp_simple.cpp +++ b/host/lib/transport/udp_simple.cpp @@ -114,9 +114,16 @@ public: do{ //drain anything in current buffer while (_off < _len){ - const char ch = _buf[_off]; _off++; - line += std::string(1, ch); - if (ch == '\n' or ch == '\r') return line; + const char ch = _buf[_off++]; + if (ch == '\r') continue; + if (ch == '\n' and _line.empty()) continue; + _line += ch; + if (ch == '\n') + { + line = _line; + _line.clear(); + return line; + } } //recv a new packet into the buffer @@ -131,6 +138,7 @@ private: udp_simple::sptr _udp; size_t _len, _off; boost::uint8_t _buf[udp_simple::mtu]; + std::string _line; }; uhd::uart_iface::sptr udp_simple::make_uart(sptr udp){ diff --git a/host/lib/usrp/b200/b200_uart.cpp b/host/lib/usrp/b200/b200_uart.cpp index 4682a79b9..f86b41609 100644 --- a/host/lib/usrp/b200/b200_uart.cpp +++ b/host/lib/usrp/b200/b200_uart.cpp @@ -32,7 +32,7 @@ struct b200_uart_impl : b200_uart _xport(xport), _sid(sid), _count(0), - _char_queue(4096) + _line_queue(4096) { //this default baud divider is over 9000 this->set_baud_divider(9001); @@ -77,13 +77,7 @@ struct b200_uart_impl : b200_uart std::string read_uart(double timeout) { std::string line; - char ch = '\0'; - while (_char_queue.pop_with_timed_wait(ch, timeout)) - { - if (ch == '\r') continue; - line += std::string(&ch, 1); - if (ch == '\n') return line; - } + _line_queue.pop_with_timed_wait(line, timeout); return line; } @@ -95,7 +89,15 @@ struct b200_uart_impl : b200_uart packet_info.num_packet_words32 = buff->size()/sizeof(boost::uint32_t); vrt::if_hdr_unpack_le(packet_buff, packet_info); const char ch = char(uhd::wtohx(packet_buff[packet_info.num_header_words32+1])); - _char_queue.push_with_pop_on_full(ch); + if (ch != '\r') + _line += ch; + if (ch == '\n') + { + // Don't store empty strings + if (_line.length() > 1) + _line_queue.push_with_pop_on_full(_line); + _line.clear(); + } } void set_baud_divider(const double baud_div) @@ -107,7 +109,8 @@ struct b200_uart_impl : b200_uart const boost::uint32_t _sid; size_t _count; size_t _baud_div; - bounded_buffer _char_queue; + bounded_buffer _line_queue; + std::string _line; }; diff --git a/host/lib/usrp/e100/e100_ctrl.cpp b/host/lib/usrp/e100/e100_ctrl.cpp index cdbbff6dd..3b59a93e1 100644 --- a/host/lib/usrp/e100/e100_ctrl.cpp +++ b/host/lib/usrp/e100/e100_ctrl.cpp @@ -232,10 +232,15 @@ public: //got a character -> process it if (ret == 1){ - const bool flush = ch == '\n' or ch == '\r'; - if (flush and line.empty()) continue; //avoid flushing on empty lines - line += std::string(1, ch); - if (flush) break; + if (ch == '\r') continue; + if (ch == '\n' and _line.empty()) continue; + _line += ch; + if (ch == '\n') + { + line = _line; + _line.clear(); + break; + } } //didnt get a character, check the timeout @@ -251,7 +256,9 @@ public: return line; } -private: int _node_fd; +private: + int _node_fd; + std::string _line; }; uhd::uart_iface::sptr e100_ctrl::make_gps_uart_iface(const std::string &node){ diff --git a/host/lib/usrp/x300/x300_fw_uart.cpp b/host/lib/usrp/x300/x300_fw_uart.cpp index b0fae124d..86141ca9a 100644 --- a/host/lib/usrp/x300/x300_fw_uart.cpp +++ b/host/lib/usrp/x300/x300_fw_uart.cpp @@ -132,6 +132,10 @@ struct x300_uart_iface : uart_iface if (ch == '\r') continue; + // avoid returning empty strings + if (ch == '\n' and _rxbuff.empty()) + continue; + // store character to buffer _rxbuff += std::string(1, (char)ch); diff --git a/host/lib/usrp_clock/octoclock/octoclock_uart.cpp b/host/lib/usrp_clock/octoclock/octoclock_uart.cpp index 221a7e471..538ee066e 100644 --- a/host/lib/usrp_clock/octoclock/octoclock_uart.cpp +++ b/host/lib/usrp_clock/octoclock/octoclock_uart.cpp @@ -100,6 +100,7 @@ namespace uhd{ for(char ch = _getchar(); ch != 0; ch = _getchar()){ if(ch == '\r') continue; //Skip carriage returns + if(ch == '\n' and _rxbuff.empty()) continue; //Skip empty lines _rxbuff += ch; //If newline found, return string -- cgit v1.2.3 From 90a5d3153e04b6d0b95e51bc84cf396a4e009c07 Mon Sep 17 00:00:00 2001 From: michael-west Date: Mon, 18 Jul 2016 14:35:39 -0700 Subject: gps_ctrl: Multiple fixes - Check for updates if cached data is older than one millisecond - Removed timeouts when checking for updated data from UART - Subscribe to SERVO:TRACe message every second and process like NMEA strings - Refactored code for simplification --- host/lib/usrp/gps_ctrl.cpp | 240 +++++++++++++++++++++++---------------------- 1 file changed, 125 insertions(+), 115 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/gps_ctrl.cpp b/host/lib/usrp/gps_ctrl.cpp index 32ed80dc3..908f84a00 100644 --- a/host/lib/usrp/gps_ctrl.cpp +++ b/host/lib/usrp/gps_ctrl.cpp @@ -49,26 +49,68 @@ gps_ctrl::~gps_ctrl(void){ class gps_ctrl_impl : public gps_ctrl{ private: - std::map > sensors; + std::map > sentences; boost::mutex cache_mutex; + boost::system_time _last_cache_update; - std::string get_cached_sensor(const std::string sensor, const int freshness, const bool once, const bool touch=true) { - boost::mutex::scoped_lock lock(cache_mutex); - boost::system_time time = boost::get_system_time(); - try { - // this is nasty ... - //std::cout << boost::format("Requested %s - seen? ") % sensor << sensors[sensor].get<2>() << " once? " << once << std::endl; - if(time - sensors[sensor].get<1>() < milliseconds(freshness) && (!once or !sensors[sensor].get<2>())) { - sensors[sensor] = boost::make_tuple(sensors[sensor].get<0>(), sensors[sensor].get<1>(), touch); - return sensors[sensor].get<0>(); - } else { - return update_cached_sensors(sensor); - } - } catch(std::exception &e) { - UHD_MSG(warning) << "get_cached_sensor: " << e.what(); + std::string get_sentence(const std::string which, const int max_age_ms, const int timeout, const bool wait_for_next = false) + { + std::string sentence; + boost::system_time now = boost::get_system_time(); + boost::system_time exit_time = now + milliseconds(timeout); + boost::posix_time::time_duration age; + + if (wait_for_next) + { + boost::lock_guard lock(cache_mutex); + update_cache(); + //mark sentence as touched + if (sentences.find(which) != sentences.end()) + sentences[which].get<2>() = true; + } + while (1) + { + try + { + boost::lock_guard lock(cache_mutex); + + // update cache if older than a millisecond + if (now - _last_cache_update > milliseconds(1)) + { + update_cache(); + } + + if (sentences.find(which) == sentences.end()) + { + age = milliseconds(max_age_ms); + } else { + age = boost::get_system_time() - sentences[which].get<1>(); + } + if (age < milliseconds(max_age_ms) and (not (wait_for_next and sentences[which].get<2>()))) + { + sentence = sentences[which].get<0>(); + sentences[which].get<2>() = true; + } + } catch(std::exception &e) { + UHD_MSG(warning) << "get_sentence: " << e.what(); + } + + if (not sentence.empty() or now > exit_time) + { + break; + } + + sleep(boost::posix_time::milliseconds(1)); + now = boost::get_system_time(); + } + + if (sentence.empty()) + { + throw uhd::value_error("gps ctrl: No " + which + " message found"); + } + + return sentence; } - return std::string(); - } static bool is_nmea_checksum_ok(std::string nmea) { @@ -91,33 +133,39 @@ private: return (string_crc == calculated_crc); } - std::string update_cached_sensors(const std::string sensor) { - if(not gps_detected() || (gps_type != GPS_TYPE_INTERNAL_GPSDO)) { + void update_cache() { + if(not gps_detected() or (_gps_type != GPS_TYPE_INTERNAL_GPSDO)) { UHD_MSG(error) << "get_stat(): unsupported GPS or no GPS detected"; - return std::string(); + return; } - const std::list list = boost::assign::list_of("GPGGA")("GPRMC")("SERVO"); - static const boost::regex status_regex("\\d\\d-\\d\\d-\\d\\d"); + const std::list keys = boost::assign::list_of("GPGGA")("GPRMC")("SERVO"); + static const boost::regex servo_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()) + 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; + } + if (msg.length() < 6) { - UHD_LOGV(regularly) << __FUNCTION__ << ": Short NMEA string: " << msg << std::endl; + UHD_LOGV(regularly) << __FUNCTION__ << ": Short GPSDO string: " << msg << std::endl; continue; } // Look for SERVO message - if (boost::regex_search(msg, status_regex, boost::regex_constants::match_continuous)) + if (boost::regex_search(msg, servo_regex, boost::regex_constants::match_continuous)) { msgs["SERVO"] = msg; } @@ -127,62 +175,63 @@ private: } else { - UHD_LOGV(regularly) << __FUNCTION__ << ": Malformed NMEA string: " << msg << std::endl; + UHD_LOGV(regularly) << __FUNCTION__ << ": Malformed GPSDO string: " << msg << std::endl; } } boost::system_time time = boost::get_system_time(); - // Update sensors with newly read data - BOOST_FOREACH(std::string key, list) { - if (msgs[key].length()) - sensors[key] = boost::make_tuple(msgs[key], time, !sensor.compare(key)); + // Update sentences with newly read data + BOOST_FOREACH(std::string key, keys) + { + if (not msgs[key].empty()) + { + sentences[key] = boost::make_tuple(msgs[key], time, false); + } } - // Return requested sensor if it was updated - if (msgs[sensor].length()) - return msgs[sensor]; - - return std::string(); + _last_cache_update = time; } public: - gps_ctrl_impl(uart_iface::sptr uart){ - _uart = uart; - + gps_ctrl_impl(uart_iface::sptr uart) : + _uart(uart), + _gps_type(GPS_TYPE_NONE) + { std::string reply; bool i_heard_some_nmea = false, i_heard_something_weird = false; - gps_type = GPS_TYPE_NONE; //first we look for an internal GPSDO _flush(); //get whatever junk is in the rx buffer right now, and throw it away - _send("HAAAY GUYYYYS\n"); //to elicit a response from the GPSDO - - //wait for _send(...) to return - sleep(milliseconds(GPSDO_COMMAND_DELAY_MS)); + _send("*IDN?\r\n"); //request identity from the GPSDO //then we loop until we either timeout, or until we get a response that indicates we're a JL device const boost::system_time comm_timeout = boost::get_system_time() + milliseconds(GPS_COMM_TIMEOUT_MS); while(boost::get_system_time() < comm_timeout) { reply = _recv(); - if(reply.find("Command Error") != std::string::npos) { - gps_type = GPS_TYPE_INTERNAL_GPSDO; + //known devices are JL "FireFly" and "LC_XO" + if(reply.find("FireFly") != std::string::npos or reply.find("LC_XO") != std::string::npos) { + _gps_type = GPS_TYPE_INTERNAL_GPSDO; break; + } else if(reply.substr(0, 3) == "$GP") { + i_heard_some_nmea = true; //but keep looking + } else if(not reply.empty()) { + i_heard_something_weird = true; //probably wrong baud rate } - 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 } - if((i_heard_some_nmea) && (gps_type != GPS_TYPE_INTERNAL_GPSDO)) gps_type = GPS_TYPE_GENERIC_NMEA; + if((i_heard_some_nmea) && (_gps_type != GPS_TYPE_INTERNAL_GPSDO)) _gps_type = GPS_TYPE_GENERIC_NMEA; - if((gps_type == GPS_TYPE_NONE) && i_heard_something_weird) { + if((_gps_type == GPS_TYPE_NONE) && i_heard_something_weird) { UHD_MSG(error) << "GPS invalid reply \"" << reply << "\", assuming none available" << std::endl; } - switch(gps_type) { + switch(_gps_type) { case GPS_TYPE_INTERNAL_GPSDO: - UHD_MSG(status) << "Found an internal GPSDO" << std::endl; + erase_all(reply, "\r"); + erase_all(reply, "\n"); + UHD_MSG(status) << "Found an internal GPSDO: " << reply << std::endl; init_gpsdo(); break; @@ -196,6 +245,9 @@ public: break; } + + // initialize cache + update_cache(); } ~gps_ctrl_impl(void){ @@ -218,7 +270,7 @@ public: or key == "gps_gprmc") { return sensor_value_t( boost::to_upper_copy(key), - get_cached_sensor(boost::to_upper_copy(key.substr(4,8)), GPS_NMEA_NORMAL_FRESHNESS, false, false), + get_sentence(boost::to_upper_copy(key.substr(4,8)), GPS_NMEA_NORMAL_FRESHNESS, GPS_TIMEOUT_DELAY_MS), ""); } else if(key == "gps_time") { @@ -228,7 +280,10 @@ public: return sensor_value_t("GPS lock status", locked(), "locked", "unlocked"); } else if(key == "gps_servo") { - return sensor_value_t("GPS servo status", get_servo(), ""); + return sensor_value_t( + boost::to_upper_copy(key), + get_sentence(boost::to_upper_copy(key.substr(4,8)), GPS_SERVO_FRESHNESS, GPS_TIMEOUT_DELAY_MS), + ""); } else { throw uhd::value_error("gps ctrl get_sensor unknown key: " + key); @@ -241,40 +296,20 @@ private: //none of these should issue replies so we don't bother looking for them //we have to sleep between commands because the JL device, despite not acking, takes considerable time to process each command. sleep(milliseconds(GPSDO_COMMAND_DELAY_MS)); - _send("SYST:COMM:SER:ECHO OFF\n"); + _send("SYST:COMM:SER:ECHO OFF\r\n"); sleep(milliseconds(GPSDO_COMMAND_DELAY_MS)); - _send("SYST:COMM:SER:PRO OFF\n"); + _send("SYST:COMM:SER:PRO OFF\r\n"); sleep(milliseconds(GPSDO_COMMAND_DELAY_MS)); - _send("GPS:GPGGA 1\n"); + _send("GPS:GPGGA 1\r\n"); sleep(milliseconds(GPSDO_COMMAND_DELAY_MS)); - _send("GPS:GGAST 0\n"); + _send("GPS:GGAST 0\r\n"); sleep(milliseconds(GPSDO_COMMAND_DELAY_MS)); - _send("GPS:GPRMC 1\n"); + _send("GPS:GPRMC 1\r\n"); sleep(milliseconds(GPSDO_COMMAND_DELAY_MS)); - _send("SERV:TRAC 0\n"); + _send("SERV:TRAC 1\r\n"); sleep(milliseconds(GPSDO_COMMAND_DELAY_MS)); } - //retrieve a raw NMEA sentence - std::string get_nmea(std::string msgtype) { - std::string reply; - - const boost::system_time comm_timeout = boost::get_system_time() + milliseconds(GPS_COMM_TIMEOUT_MS); - while(boost::get_system_time() < comm_timeout) { - if(!msgtype.compare("GPRMC")) { - reply = get_cached_sensor(msgtype, GPS_NMEA_FRESHNESS, true); - } - else { - reply = get_cached_sensor(msgtype, GPS_NMEA_LOW_FRESHNESS, false); - } - if(reply.size()) { - if(reply.substr(1, 5) == msgtype) return reply; - } - boost::this_thread::sleep(milliseconds(GPS_TIMEOUT_DELAY_MS)); - } - throw uhd::value_error(str(boost::format("get_nmea(): no %s message found") % msgtype)); - } - //helper function to retrieve a field from an NMEA sentence std::string get_token(std::string sentence, size_t offset) { boost::tokenizer > tok(sentence); @@ -289,12 +324,12 @@ private: } ptime get_time(void) { - _flush(); int error_cnt = 0; ptime gps_time; while(error_cnt < 2) { try { - std::string reply = get_nmea("GPRMC"); + // wait for next GPRMC string + std::string reply = get_sentence("GPRMC", GPS_NMEA_NORMAL_FRESHNESS, GPS_COMM_TIMEOUT_MS, true); std::string datestr = get_token(reply, 9); std::string timestr = get_token(reply, 1); @@ -317,7 +352,6 @@ private: } catch(std::exception &e) { UHD_MSG(warning) << "get_time: " << e.what(); - _flush(); error_cnt++; } } @@ -331,46 +365,24 @@ private: } bool gps_detected(void) { - return (gps_type != GPS_TYPE_NONE); + return (_gps_type != GPS_TYPE_NONE); } bool locked(void) { int error_cnt = 0; while(error_cnt < 3) { try { - std::string reply = get_cached_sensor("GPGGA", GPS_LOCK_FRESHNESS, false, false); - if(reply.size() <= 1) return false; - - return (get_token(reply, 6) != "0"); + std::string reply = get_sentence("GPGGA", GPS_LOCK_FRESHNESS, GPS_COMM_TIMEOUT_MS); + if(reply.empty()) + error_cnt++; + else + return (get_token(reply, 6) != "0"); } catch(std::exception &e) { UHD_MSG(warning) << "locked: " << e.what(); error_cnt++; } } - throw uhd::value_error("Timeout after no valid message found"); - return false; - } - - std::string get_servo(void) { - - //enable servo reporting - _send("SERV:TRAC 1\n"); - sleep(milliseconds(GPSDO_COMMAND_DELAY_MS)); - - std::string reply; - - const boost::system_time comm_timeout = boost::get_system_time() + milliseconds(GPS_COMM_TIMEOUT_MS); - while(boost::get_system_time() < comm_timeout) { - reply = get_cached_sensor("SERVO", GPS_NMEA_LOW_FRESHNESS, false); - if(reply.size()) - { - //disable it before leaving function - _send("SERV:TRAC 0\n"); - return reply; - } - boost::this_thread::sleep(milliseconds(GPS_TIMEOUT_DELAY_MS)); - } - throw uhd::value_error("get_stat(): no servo message found"); + throw uhd::value_error("locked(): unable to determine GPS lock status"); } uart_iface::sptr _uart; @@ -393,13 +405,11 @@ private: GPS_TYPE_INTERNAL_GPSDO, GPS_TYPE_GENERIC_NMEA, GPS_TYPE_NONE - } gps_type; + } _gps_type; static const int GPS_COMM_TIMEOUT_MS = 1300; - static const int GPS_NMEA_FRESHNESS = 10; - static const int GPS_NMEA_LOW_FRESHNESS = 2500; static const int GPS_NMEA_NORMAL_FRESHNESS = 1000; - static const int GPS_SERVO_FRESHNESS = 2500; + static const int GPS_SERVO_FRESHNESS = 1000; static const int GPS_LOCK_FRESHNESS = 2500; static const int GPS_TIMEOUT_DELAY_MS = 200; static const int GPSDO_COMMAND_DELAY_MS = 200; -- cgit v1.2.3 From b229a1972c421c90420363ce1f93be91cc9bd2aa Mon Sep 17 00:00:00 2001 From: michael-west Date: Mon, 15 Aug 2016 11:18:37 -0700 Subject: B200: GPSDO fixes - Fix initialization order - Initialize to proper baud rate divisor - Remove unused function to change baud rate divisor - Simplify UART code so it does not strip or add characters --- host/lib/usrp/b200/b200_impl.cpp | 8 ++++---- host/lib/usrp/b200/b200_uart.cpp | 23 ++++++++--------------- host/lib/usrp/b200/b200_uart.hpp | 1 - 3 files changed, 12 insertions(+), 20 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index d7663c68e..5389e4773 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -460,6 +460,10 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s //////////////////////////////////////////////////////////////////// _async_task_data.reset(new AsyncTaskData()); _async_task_data->async_md.reset(new async_md_type(1000/*messages deep*/)); + if (_gpsdo_capable) + { + _async_task_data->gpsdo_uart = b200_uart::make(_ctrl_transport, B200_TX_GPS_UART_SID); + } _async_task = uhd::msg_task::make(boost::bind(&b200_impl::handle_async_task, this, _ctrl_transport, _async_task_data)); //////////////////////////////////////////////////////////////////// @@ -480,10 +484,6 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s //////////////////////////////////////////////////////////////////// if (_gpsdo_capable) { - _async_task_data->gpsdo_uart = b200_uart::make(_ctrl_transport, B200_TX_GPS_UART_SID); - _async_task_data->gpsdo_uart->set_baud_divider(B200_BUS_CLOCK_RATE/115200); - _async_task_data->gpsdo_uart->write_uart("\n"); //cause the baud and response to be setup - boost::this_thread::sleep(boost::posix_time::seconds(1)); //allow for a little propagation if ((_local_ctrl->peek32(RB32_CORE_STATUS) & 0xff) != B200_GPSDO_ST_NONE) { diff --git a/host/lib/usrp/b200/b200_uart.cpp b/host/lib/usrp/b200/b200_uart.cpp index f86b41609..065aa49ce 100644 --- a/host/lib/usrp/b200/b200_uart.cpp +++ b/host/lib/usrp/b200/b200_uart.cpp @@ -16,12 +16,14 @@ // #include "b200_uart.hpp" +#include "b200_impl.hpp" #include #include #include #include #include #include +#include using namespace uhd; using namespace uhd::transport; @@ -32,10 +34,10 @@ struct b200_uart_impl : b200_uart _xport(xport), _sid(sid), _count(0), + _baud_div(std::floor(B200_BUS_CLOCK_RATE/115200 + 0.5)), _line_queue(4096) { - //this default baud divider is over 9000 - this->set_baud_divider(9001); + /*NOP*/ } void send_char(const char ch) @@ -67,10 +69,9 @@ struct b200_uart_impl : b200_uart void write_uart(const std::string &buff) { - for (size_t i = 0; i < buff.size(); i++) + BOOST_FOREACH(const char ch, buff) { - if (buff[i] == '\n') this->send_char('\r'); - this->send_char(buff[i]); + this->send_char(ch); } } @@ -89,22 +90,14 @@ struct b200_uart_impl : b200_uart packet_info.num_packet_words32 = buff->size()/sizeof(boost::uint32_t); vrt::if_hdr_unpack_le(packet_buff, packet_info); const char ch = char(uhd::wtohx(packet_buff[packet_info.num_header_words32+1])); - if (ch != '\r') - _line += ch; + _line += ch; if (ch == '\n') { - // Don't store empty strings - if (_line.length() > 1) - _line_queue.push_with_pop_on_full(_line); + _line_queue.push_with_pop_on_full(_line); _line.clear(); } } - void set_baud_divider(const double baud_div) - { - _baud_div = size_t(baud_div + 0.5); - } - const zero_copy_if::sptr _xport; const boost::uint32_t _sid; size_t _count; diff --git a/host/lib/usrp/b200/b200_uart.hpp b/host/lib/usrp/b200/b200_uart.hpp index 1c8e44ddc..f58479888 100644 --- a/host/lib/usrp/b200/b200_uart.hpp +++ b/host/lib/usrp/b200/b200_uart.hpp @@ -29,7 +29,6 @@ public: typedef boost::shared_ptr sptr; static sptr make(uhd::transport::zero_copy_if::sptr, const boost::uint32_t sid); virtual void handle_uart_packet(uhd::transport::managed_recv_buffer::sptr buff) = 0; - virtual void set_baud_divider(const double baud_div) = 0; }; -- cgit v1.2.3 From 7ea624b179cfb2cd6204be4dc128ba7ef07f4546 Mon Sep 17 00:00:00 2001 From: michael-west Date: Mon, 15 Aug 2016 11:21:57 -0700 Subject: X300: GPSDO fixes - Optimize writes so full 32-bit words are written at a time - Simplify UART so it does not strip or add characters --- firmware/usrp3/x300/x300_main.c | 2 +- host/lib/usrp/x300/x300_fw_uart.cpp | 36 +++++++++++++++++------------------- 2 files changed, 18 insertions(+), 20 deletions(-) (limited to 'host/lib/usrp') diff --git a/firmware/usrp3/x300/x300_main.c b/firmware/usrp3/x300/x300_main.c index 3b812a2c4..125459583 100644 --- a/firmware/usrp3/x300/x300_main.c +++ b/firmware/usrp3/x300/x300_main.c @@ -345,12 +345,12 @@ static void handle_uarts(void) static uint32_t rxoffset = 0; for (int rxch = wb_uart_getc(UART0_BASE); rxch != -1; rxch = wb_uart_getc(UART0_BASE)) { - rxoffset++; const int shift = ((rxoffset%4) * 8); static uint32_t rxword32 = 0; if (shift == 0) rxword32 = 0; rxword32 |= ((uint32_t) rxch & 0xFF) << shift; rxpool[(rxoffset/4) % NUM_POOL_WORDS32] = rxword32; + rxoffset++; shmem[X300_FW_SHMEM_UART_RX_INDEX] = rxoffset; } diff --git a/host/lib/usrp/x300/x300_fw_uart.cpp b/host/lib/usrp/x300/x300_fw_uart.cpp index 86141ca9a..7f60e26fc 100644 --- a/host/lib/usrp/x300/x300_fw_uart.cpp +++ b/host/lib/usrp/x300/x300_fw_uart.cpp @@ -30,28 +30,36 @@ using namespace uhd; struct x300_uart_iface : uart_iface { x300_uart_iface(wb_iface::sptr iface): - rxoffset(0), txoffset(0), txword32(0), rxpool(0), txpool(0), poolsize(0) + _iface(iface), + rxoffset(0), + txword32(0), + _last_device_rxoffset(0) { - _iface = iface; - rxoffset = _iface->peek32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_UART_RX_INDEX)); txoffset = _iface->peek32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_UART_TX_INDEX)); 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); } void putchar(const char ch) { - txoffset = (txoffset + 1) % (poolsize*4); const int shift = ((txoffset%4) * 8); if (shift == 0) txword32 = 0; txword32 |= boost::uint32_t(ch) << shift; - _iface->poke32(SR_ADDR(txpool, txoffset/4), txword32); - _iface->poke32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_UART_TX_INDEX), txoffset); + // Write out full 32 bit words or whatever we have if end of string + if (txoffset % 4 == 3 or ch == '\n') + { + _iface->poke32(SR_ADDR(txpool, txoffset/4), txword32); + } + txoffset = (txoffset + 1) % (poolsize*4); + if (ch == '\n') + { + // Tell the X300 to write the string + _iface->poke32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_UART_TX_INDEX), txoffset); + } } void write_uart(const std::string &buff) @@ -59,7 +67,6 @@ struct x300_uart_iface : uart_iface boost::mutex::scoped_lock(_write_mutex); BOOST_FOREACH(const char ch, buff) { - if (ch == '\n') this->putchar('\r'); this->putchar(ch); } } @@ -128,22 +135,13 @@ struct x300_uart_iface : uart_iface // Get available characters for (int ch = this->getchar(); ch != -1; ch = this->getchar()) { - // skip carriage returns - if (ch == '\r') - continue; - - // avoid returning empty strings - if (ch == '\n' and _rxbuff.empty()) - continue; - // store character to buffer - _rxbuff += std::string(1, (char)ch); + _rxbuff.append(1, ch); // newline found - return string if (ch == '\n') { - buff = _rxbuff; - _rxbuff.clear(); + buff.swap(_rxbuff); return buff; } } -- cgit v1.2.3 From 8401e84d68f2061bc651d4c89a40c31009909889 Mon Sep 17 00:00:00 2001 From: michael-west Date: Mon, 15 Aug 2016 15:08:25 -0700 Subject: E100: Simplify GPSDO UART so it does not strip characters. --- host/lib/usrp/e100/e100_ctrl.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/e100/e100_ctrl.cpp b/host/lib/usrp/e100/e100_ctrl.cpp index 3b59a93e1..c164a6fb0 100644 --- a/host/lib/usrp/e100/e100_ctrl.cpp +++ b/host/lib/usrp/e100/e100_ctrl.cpp @@ -232,8 +232,6 @@ public: //got a character -> process it if (ret == 1){ - if (ch == '\r') continue; - if (ch == '\n' and _line.empty()) continue; _line += ch; if (ch == '\n') { -- cgit v1.2.3