diff options
-rw-r--r-- | host/docs/CMakeLists.txt | 1 | ||||
-rw-r--r-- | host/docs/gpsdo.rst | 66 | ||||
-rw-r--r-- | host/docs/sync.rst | 19 | ||||
-rw-r--r-- | host/docs/usrp2.rst | 8 | ||||
-rw-r--r-- | host/examples/benchmark_rate.cpp | 36 | ||||
-rw-r--r-- | host/include/uhd/transport/bounded_buffer.ipp | 14 | ||||
-rw-r--r-- | host/include/uhd/usrp/gps_ctrl.hpp | 14 | ||||
-rw-r--r-- | host/include/uhd/utils/byteswap.hpp | 8 | ||||
-rw-r--r-- | host/include/uhd/utils/byteswap.ipp | 16 | ||||
-rw-r--r-- | host/lib/usrp/gps_ctrl.cpp | 210 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/mboard_impl.cpp | 24 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.cpp | 2 | ||||
-rw-r--r-- | host/lib/usrp/usrp_e100/io_impl.cpp | 2 | ||||
-rw-r--r-- | host/tests/sph_recv_test.cpp | 18 |
14 files changed, 293 insertions, 145 deletions
diff --git a/host/docs/CMakeLists.txt b/host/docs/CMakeLists.txt index 88afb9c98..be00a6655 100644 --- a/host/docs/CMakeLists.txt +++ b/host/docs/CMakeLists.txt @@ -24,6 +24,7 @@ SET(manual_sources build.rst coding.rst dboards.rst + gpsdo.rst general.rst images.rst sync.rst diff --git a/host/docs/gpsdo.rst b/host/docs/gpsdo.rst new file mode 100644 index 000000000..a0f2d67da --- /dev/null +++ b/host/docs/gpsdo.rst @@ -0,0 +1,66 @@ +======================================================================== +UHD - Internal GPSDO Application Notes +======================================================================== + +.. contents:: Table of Contents + +This application note describes the use of integrated GPS-disciplined +oscillators with Ettus Research USRP devices. It pertains specifically +to the Jackson Labs Firefly-1A device unless noted otherwise. + +------------------------------------------------------------------------ +Specifications +------------------------------------------------------------------------ +Receiver type: 50 channel with WAAS, EGNOS, MSAS +10MHz ADEV: 1e-11 over >24h +1PPS RMS jitter: <50ns 1-sigma +Holdover: <11us over 3h +Phase noise: 1Hz: -80dBc/Hz, 10Hz: -110dBc/Hz, 100Hz: -135dBc/Hz, 1kHz: -145dBc/Hz, 10kHz: <-145dBc/Hz + +------------------------------------------------------------------------ +Installation +------------------------------------------------------------------------ +See the documentation for your device for specifics on installing the GPSDO. + +------------------------------------------------------------------------ +Configuring the USRP to use the GPSDO +------------------------------------------------------------------------ +This is necessary if you require absolute GPS time in your application, +or need to communicate with the GPSDO to obtain location, satellite info, etc. +If you only require 10MHz and PPS signals for reference or MIMO use, +(see the Synchronization application note), it is not necessary to perform +this step. + +To configure the USRP to communicate with the GPSDO, use the +usrp_burn_mb_eeprom utility: + +:: + $ cd <install-path>/share/uhd/utils + $ ./usrp_burn_mb_eeprom --key=gpsdo --val=internal + +This will configure the driver to communicate with the GPSDO on startup. + +------------------------------------------------------------------------ +Using the GPSDO in your application +------------------------------------------------------------------------ +By default, if a GPSDO is detected at startup, the USRP will be configured +to use it as a frequency and time reference. The internal VITA timestamp +will be initialized to the GPS time, and the internal oscillator will be +phase-locked to the 10MHz GPSDO reference. If the GPSDO is not locked to +satellites, the VITA time will not be initialized. + +GPS data is obtained through the mboard_sensors interface. To retrieve +the current GPS time, use the "gps_time" sensor: + +:: + usrp->get_mboard_sensor("gps_time"); + +The returned value will be the current epoch time, in seconds since +January 1, 1970. This value is readily converted into human-readable +format using the time.h library in C, boost::posix_time in C++, etc. + +Other information can be fetched as well. You can query the lock status +with the "gps_locked" sensor, as well as obtain raw NMEA sentences using +the "gps_gpgsa", "gps_gprmc", and "gps_gpgga" sensors. Location +information can be parsed out of the "gps_gpgga" sensor by using gpsd or +another NMEA parser. diff --git a/host/docs/sync.rst b/host/docs/sync.rst index 9284d8e33..3cb13fbf3 100644 --- a/host/docs/sync.rst +++ b/host/docs/sync.rst @@ -102,22 +102,11 @@ and the user can also parse this string to determine GPS time: usrp->set_time_next_pps(uhd::time_spec_t(gps_time+1)); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Method 3 - query the gps_time sensor +Method 3 - internal GPSDO ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -This is a variant of method 2 for USRPs with internal GPSDOs. -The user can query the gps_time sensor to wait for the NMEA string. - -:: - - //wait for NMEA string from internal GPSDO - usrp->get_mboard_sensor("gps_time"); - usrp->set_time_next_pps(uhd::time_spec_t(0.0)); - - -- OR -- - - //wait for the NMEA string and set GPS time - const time_t gps_time = usrp->get_mboard_sensor("gps_time").to_int(); - usrp->set_time_next_pps(uhd::time_spec_t(gps_time+1)); +USRPs with internal GPSDOs properly configured will automatically +configure themselves to set the VITA time to current UTC time. See the +GPSDO application note for more details. ------------------------------------------------------------------------ Synchronizing channel phase diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst index 88b217f1b..1b07834fb 100644 --- a/host/docs/usrp2.rst +++ b/host/docs/usrp2.rst @@ -349,9 +349,8 @@ Test the PPS input with the following app: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Internal GPSDO ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -USRP-N2XX models can have an optional internal GPSDO. -To use the GPSDO with UHD, you must burn an EEPROM setting -so that UHD knows that the internal GPSDO was installed. +Please see the GPSDO application note for information on configuring and +using the internal GPSDO. **Installation instructions:** @@ -396,7 +395,8 @@ they can be queried through the API. * mimo_locked - clock reference locked over the MIMO cable * ref_locked - clock reference locked (internal/external) -* gps_time - GPS seconds (available when GPSDO installed) +* gps_time - GPS epoch seconds (available when GPSDO installed) +* gps_locked - GPS lock status ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Multiple RX channels diff --git a/host/examples/benchmark_rate.cpp b/host/examples/benchmark_rate.cpp index 6927b512b..688cd797a 100644 --- a/host/examples/benchmark_rate.cpp +++ b/host/examples/benchmark_rate.cpp @@ -27,11 +27,15 @@ namespace po = boost::program_options; +/*********************************************************************** + * Test result variables + **********************************************************************/ unsigned long long num_overflows = 0; unsigned long long num_underflows = 0; unsigned long long num_rx_samps = 0; unsigned long long num_tx_samps = 0; unsigned long long num_dropped_samps = 0; +unsigned long long num_seq_errors = 0; /*********************************************************************** * Benchmark RX Rate @@ -77,11 +81,11 @@ void benchmark_rx_rate(uhd::usrp::multi_usrp::sptr usrp){ default: std::cerr << "Error code: " << md.error_code << std::endl; - std::cerr << "Unexpected error on recv, exit test..." << std::endl; - goto loop_done; + std::cerr << "Unexpected error on recv, continuing..." << std::endl; + break; } - } loop_done: + } usrp->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); } @@ -122,11 +126,9 @@ void benchmark_tx_rate_async_helper(uhd::usrp::multi_usrp::sptr usrp){ //setup variables and allocate buffer uhd::async_metadata_t async_md; - while (true){ + while (not boost::this_thread::interruption_requested()){ - if (not usrp->get_device()->recv_async_msg(async_md)){ - if (boost::this_thread::interruption_requested()) return; - } + if (not usrp->get_device()->recv_async_msg(async_md)) continue; //handle the error codes switch(async_md.event_code){ @@ -138,10 +140,15 @@ void benchmark_tx_rate_async_helper(uhd::usrp::multi_usrp::sptr usrp){ num_underflows++; break; + case uhd::async_metadata_t::EVENT_CODE_SEQ_ERROR: + case uhd::async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST: + num_seq_errors++; + break; + default: std::cerr << "Event code: " << async_md.event_code << std::endl; - std::cerr << "Unexpected event on async recv, exit test..." << std::endl; - return; + std::cerr << "Unexpected event on async recv, continuing..." << std::endl; + break; } } } @@ -183,16 +190,12 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ //create a usrp device std::cout << std::endl; uhd::device_addrs_t device_addrs = uhd::device::find(args); - if (device_addrs.empty()){ - std::cerr << "Could not find any devices for: " << args << std::endl; - return ~0; - } - if (device_addrs.at(0).get("type", "") == "usrp1"){ + if (not device_addrs.empty() and device_addrs.at(0).get("type", "") == "usrp1"){ std::cerr << "*** Warning! ***" << std::endl; std::cerr << "Benchmark results will be inaccurate on USRP1 due to insufficient features.\n" << std::endl; } std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; - uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(device_addrs.at(0)); + uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args); std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl; boost::thread_group thread_group; @@ -226,8 +229,9 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ " Num dropped samples: %u\n" " Num overflows detected: %u\n" " Num transmitted samples: %u\n" + " Num sequence errors: %u\n" " Num underflows detected: %u\n" - ) % num_rx_samps % num_dropped_samps % num_overflows % num_tx_samps % num_underflows << std::endl; + ) % num_rx_samps % num_dropped_samps % num_overflows % num_tx_samps % num_seq_errors % num_underflows << std::endl; //finished std::cout << std::endl << "Done!" << std::endl << std::endl; diff --git a/host/include/uhd/transport/bounded_buffer.ipp b/host/include/uhd/transport/bounded_buffer.ipp index 0d393ad64..9c24005b7 100644 --- a/host/include/uhd/transport/bounded_buffer.ipp +++ b/host/include/uhd/transport/bounded_buffer.ipp @@ -20,6 +20,7 @@ #include <uhd/config.hpp> #include <boost/bind.hpp> +#include <boost/utility.hpp> #include <boost/function.hpp> #include <boost/circular_buffer.hpp> #include <boost/thread/condition.hpp> @@ -27,7 +28,7 @@ namespace uhd{ namespace transport{ namespace{ /*anon*/ - template <typename elem_type> class bounded_buffer_detail{ + template <typename elem_type> class bounded_buffer_detail : boost::noncopyable{ public: bounded_buffer_detail(size_t capacity): @@ -87,7 +88,7 @@ namespace uhd{ namespace transport{ namespace{ /*anon*/ UHD_INLINE bool pop_with_haste(elem_type &elem){ boost::mutex::scoped_lock lock(_mutex); if (_buffer.empty()) return false; - elem = this->pop_back(); + this->pop_back(elem); lock.unlock(); _full_cond.notify_one(); return true; @@ -97,7 +98,7 @@ namespace uhd{ namespace transport{ namespace{ /*anon*/ if (this->pop_with_haste(elem)) return; boost::mutex::scoped_lock lock(_mutex); _empty_cond.wait(lock, _not_empty_fcn); - elem = this->pop_back(); + this->pop_back(elem); lock.unlock(); _full_cond.notify_one(); } @@ -108,7 +109,7 @@ namespace uhd{ namespace transport{ namespace{ /*anon*/ if (not _empty_cond.timed_wait( lock, to_time_dur(timeout), _not_empty_fcn )) return false; - elem = this->pop_back(); + this->pop_back(elem); lock.unlock(); _full_cond.notify_one(); return true; @@ -130,11 +131,10 @@ namespace uhd{ namespace transport{ namespace{ /*anon*/ * 2) assign the back element to empty * 3) pop the back to move the counter */ - UHD_INLINE elem_type pop_back(void){ - elem_type elem = _buffer.back(); + UHD_INLINE void pop_back(elem_type &elem){ + elem = _buffer.back(); _buffer.back() = elem_type(); _buffer.pop_back(); - return elem; } static UHD_INLINE boost::posix_time::time_duration to_time_dur(double timeout){ diff --git a/host/include/uhd/usrp/gps_ctrl.hpp b/host/include/uhd/usrp/gps_ctrl.hpp index bd679b165..6ff00e03c 100644 --- a/host/include/uhd/usrp/gps_ctrl.hpp +++ b/host/include/uhd/usrp/gps_ctrl.hpp @@ -22,6 +22,8 @@ #include <boost/utility.hpp> #include <boost/function.hpp> #include <boost/date_time/posix_time/posix_time_types.hpp> +#include <vector> +#include <uhd/types/sensors.hpp> using namespace boost::posix_time; @@ -38,16 +40,14 @@ public: static sptr make(gps_send_fn_t, gps_recv_fn_t); /*! - * Get the current GPS time and date - * \return current GPS time and date as boost::posix_time::ptime object + * Retrieve the list of sensors this GPS object provides */ - virtual ptime get_time(void) = 0; - + virtual std::vector<std::string> get_sensors(void) = 0; + /*! - * Get the epoch time (as time_t, which is int) - * \return current GPS time and date as time_t + * Retrieve the named sensor */ - virtual time_t get_epoch_time(void) = 0; + virtual uhd::sensor_value_t get_sensor(std::string key) = 0; /*! * Tell you if there's a supported GPS connected or not diff --git a/host/include/uhd/utils/byteswap.hpp b/host/include/uhd/utils/byteswap.hpp index 9a1871210..2b5a46c66 100644 --- a/host/include/uhd/utils/byteswap.hpp +++ b/host/include/uhd/utils/byteswap.hpp @@ -1,5 +1,5 @@ // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-2011 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 @@ -43,6 +43,12 @@ namespace uhd{ //! host to network: short, long, or long-long template<typename T> T htonx(T); + //! worknet to host: short, long, or long-long + template<typename T> T wtohx(T); + + //! host to worknet: short, long, or long-long + template<typename T> T htowx(T); + } //namespace uhd #include <uhd/utils/byteswap.ipp> diff --git a/host/include/uhd/utils/byteswap.ipp b/host/include/uhd/utils/byteswap.ipp index c090dee55..51e9c28a0 100644 --- a/host/include/uhd/utils/byteswap.ipp +++ b/host/include/uhd/utils/byteswap.ipp @@ -117,4 +117,20 @@ template<typename T> UHD_INLINE T uhd::htonx(T num){ #endif } +template<typename T> UHD_INLINE T uhd::wtohx(T num){ + #ifdef BOOST_BIG_ENDIAN + return uhd::byteswap(num); + #else + return num; + #endif +} + +template<typename T> UHD_INLINE T uhd::htowx(T num){ + #ifdef BOOST_BIG_ENDIAN + return uhd::byteswap(num); + #else + return num; + #endif +} + #endif /* INCLUDED_UHD_UTILS_BYTESWAP_IPP */ diff --git a/host/lib/usrp/gps_ctrl.cpp b/host/lib/usrp/gps_ctrl.cpp index 3bee26340..3cef1ef19 100644 --- a/host/lib/usrp/gps_ctrl.cpp +++ b/host/lib/usrp/gps_ctrl.cpp @@ -17,23 +17,26 @@ #include <uhd/usrp/gps_ctrl.hpp> #include <uhd/utils/msg.hpp> +#include <uhd/utils/props.hpp> #include <uhd/exception.hpp> +#include <uhd/types/sensors.hpp> +#include <boost/algorithm/string.hpp> +#include <boost/assign/list_of.hpp> #include <boost/cstdint.hpp> #include <boost/date_time/posix_time/posix_time.hpp> #include <boost/thread/thread.hpp> -#include <boost/algorithm/string/trim.hpp> #include <boost/tokenizer.hpp> using namespace uhd; using namespace boost::gregorian; using namespace boost::posix_time; using namespace boost::algorithm; +using namespace boost::this_thread; /*! * A GPS control for Jackson Labs devices (and other NMEA compatible GPS's) */ -//TODO: multiple baud rate support (requires mboard_impl changes for poking UART registers) class gps_ctrl_impl : public gps_ctrl{ public: gps_ctrl_impl(gps_send_fn_t send, gps_recv_fn_t recv){ @@ -42,74 +45,41 @@ public: std::string reply; bool i_heard_some_nmea = false, i_heard_something_weird = false; - gps_type = GPS_TYPE_NONE; - -// set_uart_baud_rate(GPS_UART, 115200); - //first we look for a Jackson Labs Firefly (since that's what we sell with the USRP2+...) - + + //first we look for a Jackson Labs Firefly (since that's what we provide...) _recv(); //get whatever junk is in the rx buffer right now, and throw it away _send("HAAAY GUYYYYS\n"); //to elicit a response from the Firefly //then we loop until we either timeout, or until we get a response that indicates we're a JL device int timeout = GPS_TIMEOUT_TRIES; while(timeout--) { - reply = safe_gps_read(); - if(trim_right_copy(reply) == "Command Error") { + reply = _recv(); + if(reply.find("Command Error") != std::string::npos) { gps_type = GPS_TYPE_JACKSON_LABS; break; } 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 - boost::this_thread::sleep(boost::posix_time::milliseconds(200)); + sleep(milliseconds(200)); } if((i_heard_some_nmea) && (gps_type != GPS_TYPE_JACKSON_LABS)) gps_type = GPS_TYPE_GENERIC_NMEA; - //otherwise, we can try some other common baud rates looking to see if a GPS is connected (todo, later) if((gps_type == GPS_TYPE_NONE) && i_heard_something_weird) { UHD_MSG(error) << "GPS invalid reply \"" << reply << "\", assuming none available" << std::endl; } - bool found_gprmc = false; - switch(gps_type) { case GPS_TYPE_JACKSON_LABS: UHD_MSG(status) << "Found a Jackson Labs GPS" << std::endl; - //issue some setup stuff so it spits out the appropriate data - //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. - boost::this_thread::sleep(boost::posix_time::milliseconds(FIREFLY_STUPID_DELAY_MS)); - _send("SYST:COMM:SER:ECHO OFF\n"); - boost::this_thread::sleep(boost::posix_time::milliseconds(FIREFLY_STUPID_DELAY_MS)); - _send("SYST:COMM:SER:PRO OFF\n"); - boost::this_thread::sleep(boost::posix_time::milliseconds(FIREFLY_STUPID_DELAY_MS)); - _send("GPS:GPGGA 0\n"); - boost::this_thread::sleep(boost::posix_time::milliseconds(FIREFLY_STUPID_DELAY_MS)); - _send("GPS:GGAST 0\n"); - boost::this_thread::sleep(boost::posix_time::milliseconds(FIREFLY_STUPID_DELAY_MS)); - _send("GPS:GPRMC 1\n"); - boost::this_thread::sleep(boost::posix_time::milliseconds(FIREFLY_STUPID_DELAY_MS)); - -// break; + init_firefly(); case GPS_TYPE_GENERIC_NMEA: if(gps_type == GPS_TYPE_GENERIC_NMEA) UHD_MSG(status) << "Found a generic NMEA GPS device" << std::endl; - found_gprmc = false; - //here we loop around looking for a GPRMC packet. if we don't get one, we don't have a usable GPS. - timeout = GPS_TIMEOUT_TRIES; - while(timeout--) { - reply = safe_gps_read(); - if(reply.substr(0, 6) == "$GPRMC") { - found_gprmc = true; - break; - } - boost::this_thread::sleep(boost::posix_time::milliseconds(200)); - } - if(!found_gprmc) { - if(gps_type == GPS_TYPE_JACKSON_LABS) UHD_MSG(error) << "Firefly GPS not locked or warming up." << std::endl; - else UHD_MSG(error) << "GPS does not output GPRMC packets. Cannot retrieve time." << std::endl; - gps_type = GPS_TYPE_NONE; + if(get_time() == ptime()) { + UHD_MSG(status) << "No valid GPRMC packet found. Ignoring discovered GPS."; + gps_type = GPS_TYPE_NONE; } break; @@ -118,71 +88,134 @@ public: break; } - - } ~gps_ctrl_impl(void){ + /* NOP */ + } + //return a list of supported sensors + std::vector<std::string> get_sensors(void) { + std::vector<std::string> ret = boost::assign::list_of + ("gps_gpgga") + ("gps_gprmc") + ("gps_gpgsa") + ("gps_time") + ("gps_locked"); + return ret; } - std::string safe_gps_read() { - return _recv(); + uhd::sensor_value_t get_sensor(std::string key) { + if(key == "gps_gpgga" + or key == "gps_gprmc" + or key == "gps_gpgsa") { + return sensor_value_t( + boost::to_upper_copy(key), + get_nmea(boost::to_upper_copy(key.substr(4,8))), + ""); + } + else if(key == "gps_time") { + return sensor_value_t("GPS epoch time", int(get_epoch_time()), "seconds"); + } + else if(key == "gps_locked") { + return sensor_value_t("GPS lock status", locked(), "locked", "unlocked"); + } + else { + UHD_THROW_PROP_GET_ERROR(); + } } - ptime get_time(void) { +private: + void init_firefly(void) { + //issue some setup stuff so it spits out the appropriate data + //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(FIREFLY_STUPID_DELAY_MS)); + _send("SYST:COMM:SER:ECHO OFF\n"); + sleep(milliseconds(FIREFLY_STUPID_DELAY_MS)); + _send("SYST:COMM:SER:PRO OFF\n"); + sleep(milliseconds(FIREFLY_STUPID_DELAY_MS)); + _send("GPS:GPGGA 1\n"); + sleep(milliseconds(FIREFLY_STUPID_DELAY_MS)); + _send("GPS:GGAST 0\n"); + sleep(milliseconds(FIREFLY_STUPID_DELAY_MS)); + _send("GPS:GPRMC 1\n"); + sleep(milliseconds(FIREFLY_STUPID_DELAY_MS)); + _send("GPS:GPGSA 1\n"); + sleep(milliseconds(FIREFLY_STUPID_DELAY_MS)); + } + + //retrieve a raw NMEA sentence + std::string get_nmea(std::string msgtype) { + msgtype.insert(0, "$"); std::string reply; - ptime now; - boost::tokenizer<boost::escaped_list_separator<char> > tok(reply); - std::vector<std::string> toked; + if(not gps_detected()) { + UHD_MSG(error) << "get_nmea(): unsupported GPS or no GPS detected"; + return std::string(); + } int timeout = GPS_TIMEOUT_TRIES; - bool found_gprmc = false; - switch(gps_type) { - case GPS_TYPE_JACKSON_LABS: //deprecated in favor of a single NMEA parser - case GPS_TYPE_GENERIC_NMEA: + while(timeout--) { + reply = _recv(); + if(reply.substr(0, 6) == msgtype) + return reply; + boost::this_thread::sleep(milliseconds(GPS_TIMEOUT_DELAY_MS)); + } + UHD_MSG(error) << "get_nmea(): no " << msgtype << " message found"; + return std::string(); + } - while(timeout--) { - reply = safe_gps_read(); - if(reply.substr(0, 6) == "$GPRMC") { - found_gprmc = true; - break; - } - boost::this_thread::sleep(boost::posix_time::milliseconds(200)); - } - UHD_ASSERT_THROW(found_gprmc); - - tok.assign(reply); - toked.assign(tok.begin(), tok.end()); - - UHD_ASSERT_THROW(toked.size() == 12); //if it's not we got something weird in there - - now = ptime( date( - greg_year(boost::lexical_cast<int>(toked[9].substr(4, 2)) + 2000), //just trust me on this one - greg_month(boost::lexical_cast<int>(toked[9].substr(2, 2))), - greg_day(boost::lexical_cast<int>(toked[9].substr(0, 2))) - ), - hours( boost::lexical_cast<int>(toked[1].substr(0, 2))) - + minutes(boost::lexical_cast<int>(toked[1].substr(2, 2))) - + seconds(boost::lexical_cast<int>(toked[1].substr(4, 2))) - ); - break; - case GPS_TYPE_NONE: - default: - throw uhd::runtime_error("get_time(): Unsupported GPS or no GPS detected\n"); - break; + //helper function to retrieve a field from an NMEA sentence + std::string get_token(std::string sentence, size_t offset) { + boost::tokenizer<boost::escaped_list_separator<char> > tok(sentence); + std::vector<std::string> toked; + + tok.assign(sentence); + toked.assign(tok.begin(), tok.end()); + + if(toked.size() <= offset) { + UHD_MSG(error) << "get_token: too few tokens in reply " << sentence; + return std::string(); } - return now; + return toked[offset]; + } + + ptime get_time(void) { + std::string reply = get_nmea("GPRMC"); + + std::string datestr = get_token(reply, 9); + std::string timestr = get_token(reply, 1); + + if(datestr.size() == 0 or timestr.size() == 0) { + return ptime(); + } + + //just trust me on this one + return ptime( date( + greg_year(boost::lexical_cast<int>(datestr.substr(4, 2)) + 2000), + greg_month(boost::lexical_cast<int>(datestr.substr(2, 2))), + greg_day(boost::lexical_cast<int>(datestr.substr(0, 2))) + ), + hours( boost::lexical_cast<int>(timestr.substr(0, 2))) + + minutes(boost::lexical_cast<int>(timestr.substr(2, 2))) + + seconds(boost::lexical_cast<int>(timestr.substr(4, 2))) + ); } time_t get_epoch_time(void) { - return (get_time() - boost::posix_time::from_time_t(0)).total_seconds(); + return (get_time() - from_time_t(0)).total_seconds(); } bool gps_detected(void) { return (gps_type != GPS_TYPE_NONE); } -private: + bool locked(void) { + std::string reply = get_nmea("GPGGA"); + if(reply.size() <= 1) return false; + + return (get_token(reply, 6) != "0"); + } + gps_send_fn_t _send; gps_recv_fn_t _recv; @@ -195,7 +228,6 @@ private: static const int GPS_TIMEOUT_TRIES = 10; static const int GPS_TIMEOUT_DELAY_MS = 200; static const int FIREFLY_STUPID_DELAY_MS = 200; - }; /*********************************************************************** diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 6bf412a3e..61ceb95ca 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -149,7 +149,13 @@ usrp2_mboard_impl::usrp2_mboard_impl( (_mimo_clocking_mode_is_master?"master":"slave") << std::endl; //init the clock config - _clock_config = clock_config_t::internal(); + if(_iface->mb_eeprom["gpsdo"] == "internal" or + _iface->mb_eeprom["gpsdo"] == "external") { + _clock_config = clock_config_t::external(); + } + else { + _clock_config = clock_config_t::internal(); + } update_clock_config(); //init the codec before the dboard @@ -174,6 +180,13 @@ usrp2_mboard_impl::usrp2_mboard_impl( _iface->poke32(U2_REG_RX_CTRL_CLEAR(i), 1); //resets sequence } //------------------------------------------------------------------ + + //initialize VITA time to GPS time + if( _gps_ctrl.get() + and _gps_ctrl->gps_detected()) { + UHD_MSG(status) << "Setting device time to GPS time...\n"; + set_time_spec(time_spec_t(double(_gps_ctrl->get_sensor("gps_time").to_int()+1)), false); + } } usrp2_mboard_impl::~usrp2_mboard_impl(void){UHD_SAFE_CALL( @@ -375,7 +388,10 @@ void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){ case SUBDEV_PROP_SENSOR_NAMES:{ prop_names_t names = boost::assign::list_of("mimo_locked")("ref_locked"); - if (_gps_ctrl.get()) names.push_back("gps_time"); + if (_gps_ctrl.get()) { + std::vector<std::string> gs = _gps_ctrl->get_sensors(); + names.insert(names.end(), gs.begin(), gs.end()); + } val = names; } return; @@ -389,8 +405,8 @@ void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){ val = sensor_value_t("Ref", this->get_ref_locked(), "locked", "unlocked"); return; } - else if(key.name == "gps_time" and _gps_ctrl.get()) { - val = sensor_value_t("GPS time", int(_gps_ctrl->get_epoch_time()), "seconds"); + else if(uhd::has(_gps_ctrl->get_sensors(), key.name) and _gps_ctrl.get()) { + val = _gps_ctrl->get_sensor(key.name); } else { UHD_THROW_PROP_GET_ERROR(); diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 9947e71e7..b5e50507c 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -249,7 +249,7 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){ //extract the user's requested MTU size or default mtu_result_t user_mtu; user_mtu.recv_mtu = size_t(device_addr.cast<double>("recv_frame_size", udp_simple::mtu)); - user_mtu.send_mtu = size_t(device_addr.cast<double>("recv_frame_size", udp_simple::mtu)); + user_mtu.send_mtu = size_t(device_addr.cast<double>("send_frame_size", udp_simple::mtu)); try{ //calculate the minimum send and recv mtu of all devices diff --git a/host/lib/usrp/usrp_e100/io_impl.cpp b/host/lib/usrp/usrp_e100/io_impl.cpp index 91b129276..998a715fe 100644 --- a/host/lib/usrp/usrp_e100/io_impl.cpp +++ b/host/lib/usrp/usrp_e100/io_impl.cpp @@ -123,7 +123,7 @@ void usrp_e100_impl::io_impl::recv_pirate_loop( const boost::uint32_t *vrt_hdr = buff->cast<const boost::uint32_t *>(); //handle an rx data packet or inline message - if (uhd::ntohx(vrt_hdr[1]) == rx_data_inline_sid){ //ASSUME has_sid + if (uhd::wtohx(vrt_hdr[1]) == rx_data_inline_sid){ //ASSUME has_sid if (fp_recv_debug) UHD_LOGV(always) << "this is rx_data_inline_sid\n"; //same number of frames as the data transport -> always immediate recv_pirate_booty.push_with_wait(buff); diff --git a/host/tests/sph_recv_test.cpp b/host/tests/sph_recv_test.cpp index 6bb5d1175..cd33452c6 100644 --- a/host/tests/sph_recv_test.cpp +++ b/host/tests/sph_recv_test.cpp @@ -27,6 +27,19 @@ BOOST_CHECK_CLOSE((a).get_real_secs(), (b).get_real_secs(), 0.001) /*********************************************************************** + * A dummy overflow handler for testing + **********************************************************************/ +struct overflow_handler_type{ + overflow_handler_type(void){ + num_overflow = 0; + } + void handle(void){ + num_overflow++; + } + size_t num_overflow; +}; + +/*********************************************************************** * A dummy managed receive buffer for testing **********************************************************************/ class dummy_mrb : public uhd::transport::managed_recv_buffer{ @@ -300,6 +313,10 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_one_channel_inline_message){ handler.set_xport_chan_get_buff(0, boost::bind(&dummy_recv_xport_class::get_recv_buff, &dummy_recv_xport, _1)); handler.set_converter(otw_type); + //create an overflow handler + overflow_handler_type overflow_handler; + handler.set_overflow_handler(0, boost::bind(&overflow_handler_type::handle, &overflow_handler)); + //check the received packets size_t num_accum_samps = 0; std::vector<std::complex<float> > buff(20); @@ -326,6 +343,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_one_channel_inline_message){ std::cout << "metadata.error_code " << metadata.error_code << std::endl; BOOST_REQUIRE(metadata.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW); BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t(0, num_accum_samps, SAMP_RATE)); + BOOST_CHECK_EQUAL(overflow_handler.num_overflow, size_t(1)); } } |