diff options
Diffstat (limited to 'host')
| -rw-r--r-- | host/examples/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | host/examples/sync_to_gps.cpp | 191 | ||||
| -rw-r--r-- | host/include/uhd/types/serial.hpp | 13 | ||||
| -rw-r--r-- | host/lib/transport/udp_simple.cpp | 11 | ||||
| -rw-r--r-- | host/lib/usrp/b200/b200_impl.cpp | 8 | ||||
| -rw-r--r-- | host/lib/usrp/b200/b200_uart.cpp | 36 | ||||
| -rw-r--r-- | host/lib/usrp/b200/b200_uart.hpp | 1 | ||||
| -rw-r--r-- | host/lib/usrp/e100/e100_ctrl.cpp | 15 | ||||
| -rw-r--r-- | host/lib/usrp/gps_ctrl.cpp | 241 | ||||
| -rw-r--r-- | host/lib/usrp/x300/x300_fw_uart.cpp | 32 | ||||
| -rw-r--r-- | host/lib/usrp_clock/octoclock/octoclock_uart.cpp | 23 | 
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; | 
