summaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
Diffstat (limited to 'host')
-rw-r--r--host/docs/CMakeLists.txt1
-rw-r--r--host/docs/gpsdo.rst66
-rw-r--r--host/docs/sync.rst19
-rw-r--r--host/docs/usrp2.rst8
-rw-r--r--host/examples/benchmark_rate.cpp36
-rw-r--r--host/include/uhd/transport/bounded_buffer.ipp14
-rw-r--r--host/include/uhd/usrp/gps_ctrl.hpp14
-rw-r--r--host/include/uhd/utils/byteswap.hpp8
-rw-r--r--host/include/uhd/utils/byteswap.ipp16
-rw-r--r--host/lib/usrp/gps_ctrl.cpp210
-rw-r--r--host/lib/usrp/usrp2/mboard_impl.cpp24
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp2
-rw-r--r--host/lib/usrp/usrp_e100/io_impl.cpp2
-rw-r--r--host/tests/sph_recv_test.cpp18
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));
}
}