diff options
Diffstat (limited to 'host')
| -rw-r--r-- | host/docs/usrp1.rst | 8 | ||||
| -rw-r--r-- | host/lib/transport/libusb1_control.cpp | 3 | ||||
| -rw-r--r-- | host/lib/usrp/e100/io_impl.cpp | 5 | ||||
| -rw-r--r-- | host/lib/usrp/usrp1/io_impl.cpp | 155 | ||||
| -rw-r--r-- | host/lib/usrp/usrp1/soft_time_ctrl.cpp | 48 | ||||
| -rw-r--r-- | host/lib/usrp/usrp1/soft_time_ctrl.hpp | 9 | ||||
| -rw-r--r-- | host/lib/usrp/usrp1/usrp1_impl.cpp | 4 | ||||
| -rw-r--r-- | host/lib/usrp/usrp1/usrp1_impl.hpp | 4 | 
8 files changed, 171 insertions, 65 deletions
| diff --git a/host/docs/usrp1.rst b/host/docs/usrp1.rst index cf344d7e4..71b4f6779 100644 --- a/host/docs/usrp1.rst +++ b/host/docs/usrp1.rst @@ -74,6 +74,10 @@ List of emulated features  * Receiving at a specific time  * Receiving a specific number of samples  * End of burst flags for transmit/receive +* Notification on late stream command +* Notification on late transmit packet +* Notification on underflow or overflow +* Notification on broken chain error  **Note:**  These emulated features rely on the host system's clock for timed operations, @@ -82,10 +86,6 @@ and therefore may not have sufficient precision for the application.  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  List of missing features  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -* Notification on late stream command -* Notification on late transmit packet -* Notification on broken chain error -* Notification on underflow or overflow  * Start of burst flags for transmit/receive  ------------------------------------------------------------------------ diff --git a/host/lib/transport/libusb1_control.cpp b/host/lib/transport/libusb1_control.cpp index f903907d0..bce3d4b0b 100644 --- a/host/lib/transport/libusb1_control.cpp +++ b/host/lib/transport/libusb1_control.cpp @@ -17,6 +17,7 @@  #include "libusb1_base.hpp"  #include <uhd/transport/usb_control.hpp> +#include <boost/thread/mutex.hpp>  using namespace uhd::transport; @@ -40,6 +41,7 @@ public:                    unsigned char *buff,                    boost::uint16_t length      ){ +        boost::mutex::scoped_lock lock(_mutex);          return libusb_control_transfer(_handle->get(),                                         request_type,                                         request, @@ -52,6 +54,7 @@ public:  private:      libusb::device_handle::sptr _handle; +    boost::mutex _mutex;  };  /*********************************************************************** diff --git a/host/lib/usrp/e100/io_impl.cpp b/host/lib/usrp/e100/io_impl.cpp index 14b348f96..6e1bc3245 100644 --- a/host/lib/usrp/e100/io_impl.cpp +++ b/host/lib/usrp/e100/io_impl.cpp @@ -51,6 +51,11 @@ struct e100_impl::io_impl{          false_alarm(0), async_msg_fifo(100/*messages deep*/)      { /* NOP */ } +    ~io_impl(void){ +        recv_pirate_crew.interrupt_all(); +        recv_pirate_crew.join_all(); +    } +      double tick_rate; //set by update tick rate method      e100_ctrl::sptr iface; //so handle irq can peek and poke      void handle_irq(void); diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index 8e75f2025..461529ae2 100644 --- a/host/lib/usrp/usrp1/io_impl.cpp +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -28,6 +28,7 @@  #include <uhd/transport/bounded_buffer.hpp>  #include <boost/math/special_functions/sign.hpp>  #include <boost/math/special_functions/round.hpp> +#include <boost/thread/thread.hpp>  #include <boost/bind.hpp>  #include <boost/format.hpp> @@ -123,8 +124,6 @@ static void usrp1_bs_vrt_unpacker(  struct usrp1_impl::io_impl{      io_impl(zero_copy_if::sptr data_transport):          data_transport(data_transport), -        underflow_poll_samp_count(0), -        overflow_poll_samp_count(0),          curr_buff(offset_send_buffer(data_transport->get_send_buff())),          omsb(boost::bind(&usrp1_impl::io_impl::commit_send_buff, this, _1, _2, _3))      { @@ -132,6 +131,8 @@ struct usrp1_impl::io_impl{      }      ~io_impl(void){ +        vandal_tribe.interrupt_all(); +        vandal_tribe.join_all();          UHD_SAFE_CALL(flush_send_buff();)      } @@ -141,12 +142,6 @@ struct usrp1_impl::io_impl{      sph::recv_packet_handler recv_handler;      sph::send_packet_handler send_handler; -    //state management for overflow and underflow -    size_t underflow_poll_samp_count; -    size_t overflow_poll_samp_count; -    size_t rx_samps_per_poll_interval; -    size_t tx_samps_per_poll_interval; -      //wrapper around the actual send buffer interface      //all of this to ensure only aligned lengths are committed      //NOTE: you must commit before getting a new buffer @@ -163,6 +158,9 @@ struct usrp1_impl::io_impl{          //make a new managed buffer with the offset buffs          return omsb.get_new(curr_buff, next_buff);      } + +    boost::thread_group vandal_tribe; +    boost::system_time last_send_time;  };  /*! @@ -231,6 +229,14 @@ void usrp1_impl::io_init(void){      _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transport)); +    //create a new vandal thread to poll xerflow conditions +    boost::barrier spawn_barrier(2); +    _io_impl->vandal_tribe.create_thread(boost::bind( +        &usrp1_impl::vandal_conquest_loop, +        this, boost::ref(spawn_barrier) +    )); +    spawn_barrier.wait(); +      //init some handler stuff      _io_impl->recv_handler.set_tick_rate(_master_clock_rate);      _io_impl->recv_handler.set_vrt_unpacker(&usrp1_bs_vrt_unpacker); @@ -243,23 +249,91 @@ void usrp1_impl::io_init(void){          &usrp1_impl::io_impl::get_send_buff, _io_impl.get(), _1      )); -    this->enable_tx(true); //always enabled +    //init as disabled, then call the real function (uses restore) +    this->enable_rx(false); +    this->enable_tx(false);      rx_stream_on_off(false); +    tx_stream_on_off(false);      _io_impl->flush_send_buff();  }  void usrp1_impl::rx_stream_on_off(bool enb){ -    this->enable_rx(enb); +    this->restore_rx(enb);      //drain any junk in the receive transport after stop streaming command      while(not enb and _data_transport->get_recv_buff().get() != NULL){          /* NOP */      }  } +void usrp1_impl::tx_stream_on_off(bool enb){ +    _io_impl->last_send_time = boost::get_system_time(); +    if (_tx_enabled and not enb) _io_impl->flush_send_buff(); +    this->restore_tx(enb); +} + +/*! + * Casually poll the overflow and underflow registers. + * On an underflow, push an async message into the queue and print. + * On an overflow, interleave an inline message into recv and print. + * This procedure creates "soft" inline and async user messages. + */ +void usrp1_impl::vandal_conquest_loop(boost::barrier &spawn_barrier){ +    spawn_barrier.wait(); + +    //initialize the async metadata +    async_metadata_t async_metadata; +    async_metadata.channel = 0; +    async_metadata.has_time_spec = true; +    async_metadata.event_code = async_metadata_t::EVENT_CODE_UNDERFLOW; + +    //initialize the inline metadata +    rx_metadata_t inline_metadata; +    inline_metadata.has_time_spec = true; +    inline_metadata.error_code = rx_metadata_t::ERROR_CODE_OVERFLOW; + +    //start the polling loop... +    try{ while (not boost::this_thread::interruption_requested()){ +        boost::uint8_t underflow = 0, overflow = 0; + +        //shutoff transmit if it has been too long since send() was called +        if (_tx_enabled and (boost::get_system_time() - _io_impl->last_send_time) > boost::posix_time::milliseconds(100)){ +            this->tx_stream_on_off(false); +        } + +        //always poll regardless of enabled so we can clear the conditions +        _fx2_ctrl->usrp_control_read( +            VRQ_GET_STATUS, 0, GS_TX_UNDERRUN, &underflow, sizeof(underflow) +        ); +        _fx2_ctrl->usrp_control_read( +            VRQ_GET_STATUS, 0, GS_RX_OVERRUN, &overflow, sizeof(overflow) +        ); + +        //handle message generation for xerflow conditions +        if (_tx_enabled and underflow){ +            async_metadata.time_spec = _soft_time_ctrl->get_time(); +            _soft_time_ctrl->get_async_queue().push_with_pop_on_full(async_metadata); +            UHD_MSG(fastpath) << "U"; +        } +        if (_rx_enabled and overflow){ +            inline_metadata.time_spec = _soft_time_ctrl->get_time(); +            _soft_time_ctrl->get_inline_queue().push_with_pop_on_full(inline_metadata); +            UHD_MSG(fastpath) << "O"; +        } + +        boost::this_thread::sleep(boost::posix_time::milliseconds(50)); +    }} +    catch(const boost::thread_interrupted &){} //normal exit condition +    catch(const std::exception &e){ +        UHD_MSG(error) << "The vandal caught an unexpected exception " << e.what() << std::endl; +    } +} +  /***********************************************************************   * Properties callback methods below   **********************************************************************/  void usrp1_impl::update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){ +    boost::mutex::scoped_lock lock = _io_impl->recv_handler.get_scoped_lock(); +      //sanity checking      validate_subdev_spec(_tree, spec, "rx"); @@ -281,6 +355,8 @@ void usrp1_impl::update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){  }  void usrp1_impl::update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){ +    boost::mutex::scoped_lock lock = _io_impl->send_handler.get_scoped_lock(); +      //sanity checking      validate_subdev_spec(_tree, spec, "tx"); @@ -305,14 +381,13 @@ void usrp1_impl::update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){  }  double usrp1_impl::update_rx_samp_rate(const double samp_rate){ +    boost::mutex::scoped_lock lock = _io_impl->recv_handler.get_scoped_lock(); +      size_t rate = boost::math::iround(_master_clock_rate / samp_rate);      //clip the rate to something in range:      rate = std::min<size_t>(std::max<size_t>(rate, 4), 256); -    //TODO Poll every 100ms. Make it selectable? -    _io_impl->rx_samps_per_poll_interval = size_t(0.1 * _master_clock_rate / rate); -      bool s = this->disable_rx();      _iface->poke32(FR_DECIM_RATE, rate/2 - 1);      this->restore_rx(s); @@ -322,14 +397,13 @@ double usrp1_impl::update_rx_samp_rate(const double samp_rate){  }  double usrp1_impl::update_tx_samp_rate(const double samp_rate){ +    boost::mutex::scoped_lock lock = _io_impl->send_handler.get_scoped_lock(); +      size_t rate = boost::math::iround(_master_clock_rate / samp_rate);      //clip the rate to something in range:      rate = std::min<size_t>(std::max<size_t>(rate, 4), 256); -    //TODO Poll every 100ms. Make it selectable?  -    _io_impl->tx_samps_per_poll_interval = size_t(0.1 * _master_clock_rate / rate); -      bool s = this->disable_tx();      _iface->poke32(FR_INTERP_RATE, rate/2 - 1);      this->restore_tx(s); @@ -367,10 +441,11 @@ double usrp1_impl::update_tx_dsp_freq(const size_t dspno, const double freq){  /***********************************************************************   * Async Data   **********************************************************************/ -bool usrp1_impl::recv_async_msg(uhd::async_metadata_t &, double timeout){ -    //dummy fill-in for the recv_async_msg -    boost::this_thread::sleep(boost::posix_time::microseconds(long(timeout*1e6))); -    return false; +bool usrp1_impl::recv_async_msg( +    async_metadata_t &async_metadata, double timeout +){ +    boost::this_thread::disable_interruption di; //disable because the wait can throw +    return _soft_time_ctrl->get_async_queue().pop_with_timed_wait(async_metadata, timeout);  }  /*********************************************************************** @@ -390,29 +465,23 @@ size_t usrp1_impl::send(  ){      if (_soft_time_ctrl->send_pre(metadata, timeout)) return 0; +    this->tx_stream_on_off(true); //always enable (it will do the right thing)      size_t num_samps_sent = _io_impl->send_handler.send(          buffs, nsamps_per_buff,          metadata, io_type,          send_mode, timeout      ); -    //handle eob flag (commit the buffer, disable the DACs) +    //handle eob flag (commit the buffer, /*disable the DACs*/)      //check num samps sent to avoid flush on incomplete/timeout      if (metadata.end_of_burst and num_samps_sent == nsamps_per_buff){ -        _io_impl->flush_send_buff(); -    } - -    //handle the polling for underflow conditions -    _io_impl->underflow_poll_samp_count += num_samps_sent; -    if (_io_impl->underflow_poll_samp_count >= _io_impl->tx_samps_per_poll_interval){ -        _io_impl->underflow_poll_samp_count = 0; //reset count -        boost::uint8_t underflow = 0; -        int ret = _fx2_ctrl->usrp_control_read( -            VRQ_GET_STATUS, 0, GS_TX_UNDERRUN, -            &underflow, sizeof(underflow) -        ); -        if (ret < 0)        UHD_MSG(error) << "USRP: underflow check failed" << std::endl; -        else if (underflow) UHD_MSG(fastpath) << "U"; +        async_metadata_t metadata; +        metadata.channel = 0; +        metadata.has_time_spec = true; +        metadata.time_spec = _soft_time_ctrl->get_time(); +        metadata.event_code = async_metadata_t::EVENT_CODE_BURST_ACK; +        _soft_time_ctrl->get_async_queue().push_with_pop_on_full(metadata); +        this->tx_stream_on_off(false);      }      return num_samps_sent; @@ -433,6 +502,9 @@ size_t usrp1_impl::recv(      rx_metadata_t &metadata, const io_type_t &io_type,      recv_mode_t recv_mode, double timeout  ){ +    //interleave a "soft" inline message into the receive stream: +    if (_soft_time_ctrl->get_inline_queue().pop_with_haste(metadata)) return 0; +      size_t num_samps_recvd = _io_impl->recv_handler.recv(          buffs, nsamps_per_buff,          metadata, io_type, @@ -441,18 +513,5 @@ size_t usrp1_impl::recv(      _soft_time_ctrl->recv_post(metadata, num_samps_recvd); -    //handle the polling for overflow conditions -    _io_impl->overflow_poll_samp_count += num_samps_recvd; -    if (_io_impl->overflow_poll_samp_count >= _io_impl->rx_samps_per_poll_interval){ -        _io_impl->overflow_poll_samp_count = 0; //reset count -        boost::uint8_t overflow = 0; -        int ret = _fx2_ctrl->usrp_control_read( -            VRQ_GET_STATUS, 0, GS_RX_OVERRUN, -            &overflow, sizeof(overflow) -        ); -        if (ret < 0)       UHD_MSG(error) << "USRP: overflow check failed" << std::endl; -        else if (overflow) UHD_MSG(fastpath) << "O"; -    } -      return num_samps_recvd;  } diff --git a/host/lib/usrp/usrp1/soft_time_ctrl.cpp b/host/lib/usrp/usrp1/soft_time_ctrl.cpp index 1bab34e7b..cf602185d 100644 --- a/host/lib/usrp/usrp1/soft_time_ctrl.cpp +++ b/host/lib/usrp/usrp1/soft_time_ctrl.cpp @@ -16,8 +16,7 @@  //  #include "soft_time_ctrl.hpp" -#include <uhd/transport/bounded_buffer.hpp> -#include <boost/any.hpp> +#include <boost/make_shared.hpp>  #include <boost/thread/thread.hpp>  #include <boost/thread/barrier.hpp>  #include <boost/thread/condition_variable.hpp> @@ -41,6 +40,8 @@ public:          _nsamps_remaining(0),          _stream_mode(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS),          _cmd_queue(2), +        _async_msg_queue(100), +        _inline_msg_queue(100),          _stream_on_off(stream_on_off)      {          //synchronously spawn a new thread @@ -102,11 +103,20 @@ public:          //When to stop streaming:          //The samples have been received and the stream mode is non-continuous.          //Rewrite the sample count to clip to the requested number of samples. -        if (_nsamps_remaining <= nsamps){ +        if (_nsamps_remaining <= nsamps) switch(_stream_mode){ +        case stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE:{ +            rx_metadata_t metadata; +            metadata.has_time_spec = true; +            metadata.time_spec = this->time_now(); +            metadata.error_code = rx_metadata_t::ERROR_CODE_BROKEN_CHAIN; +            _inline_msg_queue.push_with_pop_on_full(metadata); +        } //continue to next case... +        case stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE:              nsamps = _nsamps_remaining; //set nsamps, then stop              md.end_of_burst = true;              stream_on_off(false);              return; +        default: break;          }          //update the consumed samples @@ -114,7 +124,7 @@ public:      }      void issue_stream_cmd(const stream_cmd_t &cmd){ -        _cmd_queue.push_with_wait(cmd); +        _cmd_queue.push_with_wait(boost::make_shared<stream_cmd_t>(cmd));      }      void stream_on_off(bool enb){ @@ -134,7 +144,12 @@ public:          //handle late packets          if (time_at < time_now()){ -            //TODO post async message +            async_metadata_t metadata; +            metadata.channel = 0; +            metadata.has_time_spec = true; +            metadata.time_spec = this->time_now(); +            metadata.event_code = async_metadata_t::EVENT_CODE_TIME_ERROR; +            _async_msg_queue.push_with_pop_on_full(metadata);              return true;          } @@ -153,7 +168,12 @@ public:          if (not cmd.stream_now){              time_spec_t time_at(cmd.time_spec - TWIDDLE);              if (time_at < time_now()){ -                //TODO inject late cmd inline error +                rx_metadata_t metadata; +                metadata.has_time_spec = true; +                metadata.time_spec = this->time_now(); +                metadata.error_code = rx_metadata_t::ERROR_CODE_LATE_COMMAND; +                _inline_msg_queue.push_with_pop_on_full(metadata); +                _stream_mode = stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS;              }              else{                  sleep_until_time(lock, time_at); @@ -180,20 +200,30 @@ public:      void recv_cmd_dispatcher(boost::barrier &spawn_barrier){          spawn_barrier.wait();          try{ -            boost::any cmd; +            boost::shared_ptr<stream_cmd_t> cmd;              while (true){                  _cmd_queue.pop_with_wait(cmd); -                recv_cmd_handle_cmd(boost::any_cast<stream_cmd_t>(cmd)); +                recv_cmd_handle_cmd(*cmd);              }          } catch(const boost::thread_interrupted &){}      } +    bounded_buffer<async_metadata_t> &get_async_queue(void){ +        return _async_msg_queue; +    } + +    bounded_buffer<rx_metadata_t> &get_inline_queue(void){ +        return _inline_msg_queue; +    } +  private:      boost::mutex _update_mutex;      size_t _nsamps_remaining;      stream_cmd_t::stream_mode_t _stream_mode;      time_spec_t _time_offset; -    bounded_buffer<boost::any> _cmd_queue; +    bounded_buffer<boost::shared_ptr<stream_cmd_t> > _cmd_queue; +    bounded_buffer<async_metadata_t> _async_msg_queue; +    bounded_buffer<rx_metadata_t> _inline_msg_queue;      const cb_fcn_type _stream_on_off;      boost::thread_group _thread_group;  }; diff --git a/host/lib/usrp/usrp1/soft_time_ctrl.hpp b/host/lib/usrp/usrp1/soft_time_ctrl.hpp index 7fdac7fc8..b2bf6c6f9 100644 --- a/host/lib/usrp/usrp1/soft_time_ctrl.hpp +++ b/host/lib/usrp/usrp1/soft_time_ctrl.hpp @@ -21,6 +21,7 @@  #include <uhd/types/stream_cmd.hpp>  #include <uhd/types/time_spec.hpp>  #include <uhd/types/metadata.hpp> +#include <uhd/transport/bounded_buffer.hpp>  #include <boost/utility.hpp>  #include <boost/shared_ptr.hpp>  #include <boost/function.hpp> @@ -45,8 +46,6 @@ public:       * \return a new soft time control object       */      static sptr make(const cb_fcn_type &stream_on_off); -        //TODO pass in the error queue for async msgs -        //TODO pass in the queue for inline msgs      //! Set the current time      virtual void set_time(const time_spec_t &time) = 0; @@ -62,6 +61,12 @@ public:      //! Issue a stream command to receive      virtual void issue_stream_cmd(const stream_cmd_t &cmd) = 0; + +    //! Get access to a buffer of async metadata +    virtual transport::bounded_buffer<async_metadata_t> &get_async_queue(void) = 0; + +    //! Get access to a buffer of inline metadata +    virtual transport::bounded_buffer<rx_metadata_t> &get_inline_queue(void) = 0;  };  }} //namespace diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index deb257a83..78137178b 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -294,8 +294,8 @@ usrp1_impl::usrp1_impl(const device_addr_t &device_addr){              .coerce(boost::bind(&usrp1_impl::update_tx_samp_rate, this, _1));          _tree->create<double>(tx_dsp_path / "freq/value")              .coerce(boost::bind(&usrp1_impl::update_tx_dsp_freq, this, dspno, _1)); -        _tree->create<meta_range_t>(tx_dsp_path / "freq/range") -            .set(meta_range_t(-_master_clock_rate/2, +_master_clock_rate/2)); +        _tree->create<meta_range_t>(tx_dsp_path / "freq/range") //magic scalar comes from codec control: +            .set(meta_range_t(-_master_clock_rate*0.6875, +_master_clock_rate*0.6875));      }      //////////////////////////////////////////////////////////////////// diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp index f156d0bc4..cb1497253 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.hpp +++ b/host/lib/usrp/usrp1/usrp1_impl.hpp @@ -30,6 +30,7 @@  #include <uhd/usrp/subdev_spec.hpp>  #include <uhd/usrp/dboard_eeprom.hpp>  #include <uhd/usrp/dboard_manager.hpp> +#include <boost/thread/barrier.hpp>  #include <uhd/transport/usb_zero_copy.hpp>  #ifndef INCLUDED_USRP1_IMPL_HPP @@ -116,6 +117,7 @@ private:      UHD_PIMPL_DECL(io_impl) _io_impl;      void io_init(void);      void rx_stream_on_off(bool); +    void tx_stream_on_off(bool);      void handle_overrun(size_t);      //otw types @@ -128,6 +130,8 @@ private:      bool has_rx_halfband(void);      bool has_tx_halfband(void); +    void vandal_conquest_loop(boost::barrier &); +      //handle the enables      bool _rx_enabled, _tx_enabled;      void enable_rx(bool enb){ | 
