aboutsummaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
authorMartin Braun <martin.braun@ettus.com>2016-09-02 11:27:37 -0700
committerMartin Braun <martin.braun@ettus.com>2016-09-02 11:27:37 -0700
commit83912104a9c1ab3631f755a4d98ee86e195db690 (patch)
tree4c7ba7da761b1b9b5508bffdb77b9e0696ff46ae /host
parent670eeda6e4c9ff2ab81f4e387bce49ea4dc79dcc (diff)
parent065065e90ce970f8eed0941ded6ae4377e649c2b (diff)
downloaduhd-83912104a9c1ab3631f755a4d98ee86e195db690.tar.gz
uhd-83912104a9c1ab3631f755a4d98ee86e195db690.tar.bz2
uhd-83912104a9c1ab3631f755a4d98ee86e195db690.zip
Merge branch 'UHD-3.9.LTS' into maint
This provides the GPS fixes. Conflicts: host/CMakeLists.txt tools/debs/upload_debs.sh
Diffstat (limited to 'host')
-rw-r--r--host/examples/CMakeLists.txt1
-rw-r--r--host/examples/sync_to_gps.cpp191
-rw-r--r--host/include/uhd/types/serial.hpp13
-rw-r--r--host/lib/transport/udp_simple.cpp11
-rw-r--r--host/lib/usrp/b200/b200_impl.cpp8
-rw-r--r--host/lib/usrp/b200/b200_uart.cpp36
-rw-r--r--host/lib/usrp/b200/b200_uart.hpp1
-rw-r--r--host/lib/usrp/e100/e100_ctrl.cpp15
-rw-r--r--host/lib/usrp/gps_ctrl.cpp241
-rw-r--r--host/lib/usrp/x300/x300_fw_uart.cpp32
-rw-r--r--host/lib/usrp_clock/octoclock/octoclock_uart.cpp23
11 files changed, 390 insertions, 182 deletions
diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt
index 43e0db9c0..e61fd897f 100644
--- a/host/examples/CMakeLists.txt
+++ b/host/examples/CMakeLists.txt
@@ -36,6 +36,7 @@ SET(example_sources
txrx_loopback_to_file.cpp
latency_test.cpp
gpio.cpp
+ sync_to_gps.cpp
)
IF(ENABLE_OCTOCLOCK)
diff --git a/host/examples/sync_to_gps.cpp b/host/examples/sync_to_gps.cpp
new file mode 100644
index 000000000..f27c3eff5
--- /dev/null
+++ b/host/examples/sync_to_gps.cpp
@@ -0,0 +1,191 @@
+//
+// Copyright 2016 Ettus Research
+//
+// 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
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/utils/thread_priority.hpp>
+#include <uhd/utils/safe_main.hpp>
+#include <uhd/usrp/multi_usrp.hpp>
+#include <boost/format.hpp>
+#include <boost/program_options.hpp>
+#include <boost/thread.hpp>
+#include <iostream>
+
+namespace po = boost::program_options;
+
+void print_notes(void)
+{
+ // Helpful notes
+ std::cout << boost::format("**************************************Helpful Notes on Clock/PPS Selection**************************************\n");
+ std::cout << boost::format("As you can see, the default 10 MHz Reference and 1 PPS signals are now from the GPSDO.\n");
+ std::cout << boost::format("If you would like to use the internal reference(TCXO) in other applications, you must configure that explicitly.\n");
+ std::cout << boost::format("You can no longer select the external SMAs for 10 MHz or 1 PPS signaling.\n");
+ std::cout << boost::format("****************************************************************************************************************\n");
+}
+
+int UHD_SAFE_MAIN(int argc, char *argv[])
+{
+ uhd::set_thread_priority_safe();
+
+ std::string args;
+
+ //Set up program options
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("args", po::value<std::string>(&args)->default_value(""), "USRP device arguments")
+ ;
+ po::variables_map vm;
+ po::store(po::parse_command_line(argc, argv, desc), vm);
+ po::notify(vm);
+
+ //Print the help message
+ if (vm.count("help"))
+ {
+ std::cout << boost::format("Synchronize USRP to GPS %s") % desc << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ //Create a USRP device
+ std::cout << boost::format("\nCreating the USRP device with: %s...\n") % args;
+ uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
+ std::cout << boost::format("Using Device: %s\n") % usrp->get_pp_string();
+
+ try
+ {
+ size_t num_mboards = usrp->get_num_mboards();
+ size_t num_gps_locked = 0;
+ for (size_t mboard = 0; mboard < num_mboards; mboard++)
+ {
+ std::cout << "Synchronizing mboard " << mboard << ": " << usrp->get_mboard_name(mboard) << std::endl;
+
+ //Set references to GPSDO
+ usrp->set_clock_source("gpsdo", mboard);
+ usrp->set_time_source("gpsdo", mboard);
+
+ std::cout << std::endl;
+ print_notes();
+ std::cout << std::endl;
+
+ //Check for 10 MHz lock
+ std::vector<std::string> sensor_names = usrp->get_mboard_sensor_names(mboard);
+ if(std::find(sensor_names.begin(), sensor_names.end(), "ref_locked") != sensor_names.end())
+ {
+ std::cout << "Waiting for reference lock..." << std::flush;
+ bool ref_locked = false;
+ for (int i = 0; i < 30 and not ref_locked; i++)
+ {
+ ref_locked = usrp->get_mboard_sensor("ref_locked", mboard).to_bool();
+ if (not ref_locked)
+ {
+ std::cout << "." << std::flush;
+ boost::this_thread::sleep(boost::posix_time::seconds(1));
+ }
+ }
+ if(ref_locked)
+ {
+ std::cout << "LOCKED" << std::endl;
+ } else {
+ std::cout << "FAILED" << std::endl;
+ throw uhd::runtime_error("Failed to lock to GPSDO 10 MHz Reference");
+ }
+ }
+ else
+ {
+ std::cout << boost::format("ref_locked sensor not present on this board.\n");
+ }
+
+ //Wait for GPS lock
+ bool gps_locked = usrp->get_mboard_sensor("gps_locked", mboard).to_bool();
+ if(gps_locked)
+ {
+ num_gps_locked++;
+ std::cout << boost::format("GPS Locked\n");
+ }
+ else
+ {
+ std::cerr << "WARNING: GPS not locked - time will not be accurate until locked" << std::endl;
+ }
+
+ //Set to GPS time
+ uhd::time_spec_t gps_time = uhd::time_spec_t(time_t(usrp->get_mboard_sensor("gps_time", mboard).to_int()));
+ usrp->set_time_next_pps(gps_time+1.0, mboard);
+
+ //Wait for it to apply
+ //The wait is 2 seconds because N-Series has a known issue where
+ //the time at the last PPS does not properly update at the PPS edge
+ //when the time is actually set.
+ boost::this_thread::sleep(boost::posix_time::seconds(2));
+
+ //Check times
+ gps_time = uhd::time_spec_t(time_t(usrp->get_mboard_sensor("gps_time", mboard).to_int()));
+ uhd::time_spec_t time_last_pps = usrp->get_time_last_pps(mboard);
+ std::cout << "USRP time: " << (boost::format("%0.9f") % time_last_pps.get_real_secs()) << std::endl;
+ std::cout << "GPSDO time: " << (boost::format("%0.9f") % gps_time.get_real_secs()) << std::endl;
+ if (gps_time.get_real_secs() == time_last_pps.get_real_secs())
+ std::cout << std::endl << "SUCCESS: USRP time synchronized to GPS time" << std::endl << std::endl;
+ else
+ std::cerr << std::endl << "ERROR: Failed to synchronize USRP time to GPS time" << std::endl << std::endl;
+ }
+
+ if (num_gps_locked == num_mboards and num_mboards > 1)
+ {
+ //Check to see if all USRP times are aligned
+ //First, wait for PPS.
+ uhd::time_spec_t time_last_pps = usrp->get_time_last_pps();
+ while (time_last_pps == usrp->get_time_last_pps())
+ {
+ boost::this_thread::sleep(boost::posix_time::milliseconds(1));
+ }
+
+ //Sleep a little to make sure all devices have seen a PPS edge
+ boost::this_thread::sleep(boost::posix_time::milliseconds(200));
+
+ //Compare times across all mboards
+ bool all_matched = true;
+ uhd::time_spec_t mboard0_time = usrp->get_time_last_pps(0);
+ for (size_t mboard = 1; mboard < num_mboards; mboard++)
+ {
+ uhd::time_spec_t mboard_time = usrp->get_time_last_pps(mboard);
+ if (mboard_time != mboard0_time)
+ {
+ all_matched = false;
+ std::cerr << (boost::format("ERROR: Times are not aligned: USRP 0=%0.9f, USRP %d=%0.9f")
+ % mboard0_time.get_real_secs()
+ % mboard
+ % mboard_time.get_real_secs()) << std::endl;
+ }
+ }
+ if (all_matched)
+ {
+ std::cout << "SUCCESS: USRP times aligned" << std::endl << std::endl;
+ } else {
+ std::cout << "ERROR: USRP times are not aligned" << std::endl << std::endl;
+ }
+ }
+ }
+ catch (std::exception& e)
+ {
+ std::cout << boost::format("\nError: %s") % e.what();
+ std::cout << boost::format("This could mean that you have not installed the GPSDO correctly.\n\n");
+ std::cout << boost::format("Visit one of these pages if the problem persists:\n");
+ std::cout << boost::format(" * N2X0/E1X0: http://files.ettus.com/manual/page_gpsdo.html");
+ std::cout << boost::format(" * X3X0: http://files.ettus.com/manual/page_gpsdo_x3x0.html\n\n");
+ std::cout << boost::format(" * E3X0: http://files.ettus.com/manual/page_usrp_e3x0.html#e3x0_hw_gps\n\n");
+ exit(EXIT_FAILURE);
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/host/include/uhd/types/serial.hpp b/host/include/uhd/types/serial.hpp
index 5b7f34fbd..cb90d7c71 100644
--- a/host/include/uhd/types/serial.hpp
+++ b/host/include/uhd/types/serial.hpp
@@ -157,12 +157,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
*/
@@ -172,7 +172,7 @@ namespace uhd{
boost::uint32_t data,
size_t num_bits
);
-
+
/*!
* Write to the SPI bus.
* \param which_slave the slave device number
@@ -189,7 +189,7 @@ namespace uhd{
};
/*!
- * UART interface to write and read bytes.
+ * UART interface to write and read strings.
*/
class UHD_API uart_iface{
public:
@@ -204,10 +204,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..43414feaa 100644
--- a/host/lib/transport/udp_simple.cpp
+++ b/host/lib/transport/udp_simple.cpp
@@ -114,9 +114,13 @@ 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++];
+ _line += ch;
+ if (ch == '\n')
+ {
+ line.swap(_line);
+ return line;
+ }
}
//recv a new packet into the buffer
@@ -131,6 +135,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_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp
index aed1204d3..33f0850eb 100644
--- a/host/lib/usrp/b200/b200_impl.cpp
+++ b/host/lib/usrp/b200/b200_impl.cpp
@@ -461,6 +461,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));
////////////////////////////////////////////////////////////////////
@@ -481,10 +485,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 4682a79b9..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 <uhd/transport/bounded_buffer.hpp>
#include <uhd/transport/vrt_if_packet.hpp>
#include <uhd/utils/byteswap.hpp>
#include <uhd/utils/msg.hpp>
#include <uhd/types/time_spec.hpp>
#include <uhd/exception.hpp>
+#include <boost/foreach.hpp>
using namespace uhd;
using namespace uhd::transport;
@@ -32,10 +34,10 @@ struct b200_uart_impl : b200_uart
_xport(xport),
_sid(sid),
_count(0),
- _char_queue(4096)
+ _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,23 +69,16 @@ 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);
}
}
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,19 +90,20 @@ 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);
- }
-
- void set_baud_divider(const double baud_div)
- {
- _baud_div = size_t(baud_div + 0.5);
+ _line += ch;
+ if (ch == '\n')
+ {
+ _line_queue.push_with_pop_on_full(_line);
+ _line.clear();
+ }
}
const zero_copy_if::sptr _xport;
const boost::uint32_t _sid;
size_t _count;
size_t _baud_div;
- bounded_buffer<char> _char_queue;
+ bounded_buffer<std::string> _line_queue;
+ std::string _line;
};
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<b200_uart> 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;
};
diff --git a/host/lib/usrp/e100/e100_ctrl.cpp b/host/lib/usrp/e100/e100_ctrl.cpp
index cdbbff6dd..c164a6fb0 100644
--- a/host/lib/usrp/e100/e100_ctrl.cpp
+++ b/host/lib/usrp/e100/e100_ctrl.cpp
@@ -232,10 +232,13 @@ 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;
+ _line += ch;
+ if (ch == '\n')
+ {
+ line = _line;
+ _line.clear();
+ break;
+ }
}
//didnt get a character, check the timeout
@@ -251,7 +254,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/gps_ctrl.cpp b/host/lib/usrp/gps_ctrl.cpp
index 207ef10ab..908f84a00 100644
--- a/host/lib/usrp/gps_ctrl.cpp
+++ b/host/lib/usrp/gps_ctrl.cpp
@@ -28,6 +28,7 @@
#include <boost/tokenizer.hpp>
#include <boost/format.hpp>
#include <boost/regex.hpp>
+#include <boost/thread/mutex.hpp>
#include "boost/tuple/tuple.hpp"
#include "boost/foreach.hpp"
@@ -48,24 +49,68 @@ gps_ctrl::~gps_ctrl(void){
class gps_ctrl_impl : public gps_ctrl{
private:
- std::map<std::string, boost::tuple<std::string, boost::system_time, bool> > sensors;
+ std::map<std::string, boost::tuple<std::string, boost::system_time, bool> > 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::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<boost::mutex> 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<boost::mutex> 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)
{
@@ -88,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<std::string> list = boost::assign::list_of("GPGGA")("GPRMC")("SERVO");
- static const boost::regex status_regex("\\d\\d-\\d\\d-\\d\\d");
+ const std::list<std::string> 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<std::string,std::string> msgs;
// Get all GPSDO messages available
// Creating a map here because we only want the latest of each message type
- for (std::string msg = _recv(); 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;
}
@@ -124,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;
@@ -193,6 +245,9 @@ public:
break;
}
+
+ // initialize cache
+ update_cache();
}
~gps_ctrl_impl(void){
@@ -215,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") {
@@ -225,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);
@@ -238,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<boost::escaped_list_separator<char> > tok(sentence);
@@ -286,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);
@@ -314,7 +352,6 @@ private:
} catch(std::exception &e) {
UHD_MSG(warning) << "get_time: " << e.what();
- _flush();
error_cnt++;
}
}
@@ -328,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;
@@ -390,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;
diff --git a/host/lib/usrp/x300/x300_fw_uart.cpp b/host/lib/usrp/x300/x300_fw_uart.cpp
index b0fae124d..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,18 +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;
-
// 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;
}
}
diff --git a/host/lib/usrp_clock/octoclock/octoclock_uart.cpp b/host/lib/usrp_clock/octoclock/octoclock_uart.cpp
index 221a7e471..0b5b840d3 100644
--- a/host/lib/usrp_clock/octoclock/octoclock_uart.cpp
+++ b/host/lib/usrp_clock/octoclock/octoclock_uart.cpp
@@ -68,13 +68,12 @@ namespace uhd{
}
void octoclock_uart_iface::write_uart(const std::string &buf){
- std::string to_send = boost::algorithm::replace_all_copy(buf, "\n", "\r\n");
size_t len = 0;
octoclock_packet_t pkt_out;
pkt_out.sequence = uhd::htonx<boost::uint32_t>(++_sequence);
- pkt_out.len = to_send.size();
- memcpy(pkt_out.data, to_send.c_str(), to_send.size());
+ pkt_out.len = buf.size();
+ memcpy(pkt_out.data, buf.c_str(), buf.size());
boost::uint8_t octoclock_data[udp_simple::mtu];
const octoclock_packet_t *pkt_in = reinterpret_cast<octoclock_packet_t*>(octoclock_data);
@@ -87,28 +86,26 @@ namespace uhd{
std::string octoclock_uart_iface::read_uart(double timeout){
std::string result;
- bool first_time = true;
boost::system_time exit_time = boost::get_system_time() + boost::posix_time::milliseconds(long(timeout*1e3));
- while(boost::get_system_time() < exit_time){
- if (first_time)
- first_time = false;
- else
- boost::this_thread::sleep(boost::posix_time::milliseconds(1));
-
+ while(true)
+ {
_update_cache();
for(char ch = _getchar(); ch != 0; ch = _getchar()){
- if(ch == '\r') continue; //Skip carriage returns
_rxbuff += ch;
//If newline found, return string
if(ch == '\n'){
- result = _rxbuff;
- _rxbuff.clear();
+ result.swap(_rxbuff);
return result;
}
}
+ if (boost::get_system_time() > exit_time)
+ {
+ break;
+ }
+ boost::this_thread::sleep(boost::posix_time::milliseconds(1));
}
return result;