diff options
| author | Josh Blum <josh@joshknows.com> | 2010-10-07 10:11:32 -0700 | 
|---|---|---|
| committer | Josh Blum <josh@joshknows.com> | 2010-10-07 10:11:32 -0700 | 
| commit | 86b021e48031f2bc6e99c7c5d2d626ea149dec70 (patch) | |
| tree | c107d3d7fb0f34da17085c06e81aa96258c38746 /host | |
| parent | d5a0960455560e9f6077aa45d52aa01c469769dd (diff) | |
| parent | b40ace72dd1b940fc0ce6e4a5e06346439dd5625 (diff) | |
| download | uhd-86b021e48031f2bc6e99c7c5d2d626ea149dec70.tar.gz uhd-86b021e48031f2bc6e99c7c5d2d626ea149dec70.tar.bz2 uhd-86b021e48031f2bc6e99c7c5d2d626ea149dec70.zip | |
Merge branch 'next' into usrp_e_mmap_b2
Diffstat (limited to 'host')
23 files changed, 424 insertions, 360 deletions
| diff --git a/host/docs/CMakeLists.txt b/host/docs/CMakeLists.txt index bbb8812b0..65db3befc 100644 --- a/host/docs/CMakeLists.txt +++ b/host/docs/CMakeLists.txt @@ -25,6 +25,7 @@ SET(manual_sources      dboards.rst      general.rst      images.rst +    transport.rst      usrp1.rst      usrp2.rst  ) diff --git a/host/docs/index.rst b/host/docs/index.rst index bd55edc0b..7f8129e2d 100644 --- a/host/docs/index.rst +++ b/host/docs/index.rst @@ -20,11 +20,12 @@ Building the UHD  ^^^^^^^^^^^^^^^^^^^^^  Application Notes  ^^^^^^^^^^^^^^^^^^^^^ -* `General App Notes <./general.html>`_ +* `General Application Notes <./general.html>`_  * `Firmware and FPGA Image Notes <./images.html>`_ -* `USRP1 App Notes <./usrp1.html>`_ -* `USRP2 App Notes <./usrp2.html>`_ -* `Daughterboard App Notes <./dboards.html>`_ +* `USRP1 Application Notes <./usrp1.html>`_ +* `USRP2 Application Notes <./usrp2.html>`_ +* `Daughterboard Application Notes <./dboards.html>`_ +* `Transport Application Notes <./transport.html>`_  ^^^^^^^^^^^^^^^^^^^^^  API Documentation diff --git a/host/docs/transport.rst b/host/docs/transport.rst new file mode 100644 index 000000000..30fc1d78f --- /dev/null +++ b/host/docs/transport.rst @@ -0,0 +1,82 @@ +======================================================================== +UHD - Transport Application Notes +======================================================================== + +.. contents:: Table of Contents + +The advanced user can pass optional parameters +into the underlying transport layer through the device address. +These optional parameters control how the transport object allocates memory, +resizes kernel buffers, spawns threads, etc. +When not spcified, the transport layer will use values for these parameters +that are known to perform well on a variety of systems. +The transport parameters are defined below for the various transports in the UHD: + +------------------------------------------------------------------------ +UDP transport (ASIO) +------------------------------------------------------------------------ +The UDP transport is implemented with Boost's ASIO library. +ASIO provides an asynchronous API for user-space sockets. +The transport implementation allocates a number of buffers +and submits asynchronous requests for send and receive. +IO service threads run in the background to process these requests. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Transport parameters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The following parameters can be used to alter the transport's default behavior: + +* **recv_frame_size:** The size of a single receive buffer in bytes +* **num_recv_frames:** The number of receive buffers to allocate +* **send_frame_size:** The size of a single send buffer in bytes +* **num_send_frames:** The number of send buffers to allocate +* **concurrency_hint:** The number of threads to run the IO service + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Resize socket buffers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +It may be useful increase the size of the socket buffers to +move the burden of buffering samples into the kernel, or to +buffer incoming samples faster than they can be processed. +However, if your application cannot process samples fast enough, +no amount of buffering can save you. +The following parameters can be used to alter socket's buffer sizes: + +* **recv_buff_size:** The desired size of the receive buffer in bytes +* **send_buff_size:** The desired size of the send buffer in bytes + +**Note:** Large send buffers tend to decrease transmit performance. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Linux specific notes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +On linux, the maximum buffer sizes are capped by the sysctl values +**net.core.rmem_max** and **net.core.wmem_max**. +To change the maximum values, run the following commands: +:: + +    sudo sysctl -w net.core.rmem_max=<new value> +    sudo sysctl -w net.core.wmem_max=<new value> + +Set the values permanently by editing */etc/sysctl.conf* + +------------------------------------------------------------------------ +USB transport (libusb) +------------------------------------------------------------------------ +The USB transport is implemented with libusb. +Libusb provides an asynchronous API for USB bulk transfers. +The transport implementation allocates a number of buffers +and submits asynchronous requests through libusb. +A single thread runs in the background +and executes the libusb event handler to process these requests. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Transport parameters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The following parameters can be used to alter the transport's default behavior: + +* **recv_frame_size:** The size of a single receive transfers in bytes +* **num_recv_frames:** The number of simultaneous receive transfers +* **send_frame_size:** The size of a single send transfers in bytes +* **num_send_frames:** The number of simultaneous send transfers +* **concurrency_hint:** The number of threads to run the event handler diff --git a/host/docs/usrp1.rst b/host/docs/usrp1.rst index 0baa93a45..3443fd871 100644 --- a/host/docs/usrp1.rst +++ b/host/docs/usrp1.rst @@ -60,29 +60,6 @@ Example device address string representations to specify non-standard firmware a      fpga=usrp1_fpga_4rx.rbf, fw=usrp1_fw_custom.ihx -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Change USB transfer parameters -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The advanced user may manipulate parameters of the usb bulk transfers -for various reasons, such as lowering latency or increasing buffer size. -By default, the UHD will use values for these parameters -that are known to perform well on a variety of systems. -The following device address parameters can be used to manipulate USB bulk transfers: - -* **recv_xfer_size:** the size of each receive bulk transfer in bytes -* **recv_num_xfers:** the number of simultaneous receive bulk transfers -* **send_xfer_size:** the size of each send bulk transfer in bytes -* **send_num_xfers:** the number of simultaneous send bulk transfers - -Example usage, set the device address markup string to the following: -:: - -    serial=12345678, recv_num_xfers=16 - -   -- OR -- - -    serial=12345678, recv_xfer_size=2048, recv_num_xfers=16 -  ------------------------------------------------------------------------  Specifying the subdevice to use  ------------------------------------------------------------------------ diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst index 70e5ea28b..1ebab388a 100644 --- a/host/docs/usrp2.rst +++ b/host/docs/usrp2.rst @@ -166,47 +166,6 @@ The device address string representation for 2 USRP2s with IPv4 addresses 192.16      addr=192.168.10.2 192.168.20.2  ------------------------------------------------------------------------ -Resize the send and receive buffers ------------------------------------------------------------------------- -It may be useful increase the size of the socket buffers to -move the burden of buffering samples into the kernel, or to -buffer incoming samples faster than they can be processed. -However, if you application cannot process samples fast enough, -no amount of buffering can save you. - -By default, the UHD will try to resize both the send and receive buffer for optimum performance. -A warning will be printed on instantiation if the actual buffer size is insufficient. -See the OS specific notes below: - -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -OS specific notes -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -On linux, the maximum buffer sizes are capped by the sysctl values -**net.core.rmem_max** and **net.core.wmem_max**. -To change the maximum values, run the following commands: -:: - -    sudo sysctl -w net.core.rmem_max=<new value> -    sudo sysctl -w net.core.wmem_max=<new value> - -Set the values permanently by editing */etc/sysctl.conf* - -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Device address params -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -To manually set the size of the buffers, -the usrp2 will accept two optional parameters in the device address. -Each parameter will accept a numeric value for the number of bytes. - -* recv_buff_size -* send_buff_size - -Example usage, set the device address markup string to the following: -:: - -    addr=192.168.10.2, recv_buff_size=100e6 - -------------------------------------------------------------------------  Hardware setup notes  ------------------------------------------------------------------------ diff --git a/host/examples/tx_timed_samples.cpp b/host/examples/tx_timed_samples.cpp index 2a15b2f66..863446682 100644 --- a/host/examples/tx_timed_samples.cpp +++ b/host/examples/tx_timed_samples.cpp @@ -99,7 +99,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){              //send will backup into the host this many seconds before sending:              seconds_in_future + 0.1 //timeout (delay before transmit + padding)          ); -        if (num_tx_samps == 0) std::cout << "Send timeout..." << std::endl; +        if (num_tx_samps < samps_to_send) std::cout << "Send timeout..." << std::endl;          if(verbose) std::cout << std::endl << boost::format("Sent %d samples") % num_tx_samps << std::endl;      } diff --git a/host/include/uhd/transport/udp_zero_copy.hpp b/host/include/uhd/transport/udp_zero_copy.hpp index 818709973..bbba97b21 100644 --- a/host/include/uhd/transport/udp_zero_copy.hpp +++ b/host/include/uhd/transport/udp_zero_copy.hpp @@ -20,6 +20,7 @@  #include <uhd/config.hpp>  #include <uhd/transport/zero_copy.hpp> +#include <uhd/types/device_addr.hpp>  #include <boost/shared_ptr.hpp>  namespace uhd{ namespace transport{ @@ -50,14 +51,12 @@ public:       *       * \param addr a string representing the destination address       * \param port a string representing the destination port -     * \param recv_buff_size size in bytes for the recv buffer, 0 for automatic -     * \param send_buff_size size in bytes for the send buffer, 0 for automatic +     * \param hints optional parameters to pass to the underlying transport       */      static sptr make(          const std::string &addr,          const std::string &port, -        size_t recv_buff_size = 0, -        size_t send_buff_size = 0 +        const device_addr_t &hints = device_addr_t()      );  }; diff --git a/host/include/uhd/transport/usb_control.hpp b/host/include/uhd/transport/usb_control.hpp index f9829c3ec..e6c32f78e 100644 --- a/host/include/uhd/transport/usb_control.hpp +++ b/host/include/uhd/transport/usb_control.hpp @@ -18,7 +18,7 @@  #ifndef INCLUDED_UHD_TRANSPORT_USB_CONTROL_HPP  #define INCLUDED_UHD_TRANSPORT_USB_CONTROL_HPP -#include "usb_device_handle.hpp" +#include <uhd/transport/usb_device_handle.hpp>  namespace uhd { namespace transport { diff --git a/host/include/uhd/transport/usb_zero_copy.hpp b/host/include/uhd/transport/usb_zero_copy.hpp index 61bf380ba..b39171fba 100644 --- a/host/include/uhd/transport/usb_zero_copy.hpp +++ b/host/include/uhd/transport/usb_zero_copy.hpp @@ -18,8 +18,9 @@  #ifndef INCLUDED_UHD_TRANSPORT_USB_ZERO_COPY_HPP  #define INCLUDED_UHD_TRANSPORT_USB_ZERO_COPY_HPP -#include "usb_device_handle.hpp" +#include <uhd/transport/usb_device_handle.hpp>  #include <uhd/transport/zero_copy.hpp> +#include <uhd/types/device_addr.hpp>  namespace uhd { namespace transport { @@ -47,19 +48,13 @@ public:       * \param handle a device handle that uniquely identifying the device       * \param recv_endpoint an integer specifiying an IN endpoint number       * \param send_endpoint an integer specifiying an OUT endpoint number -     * \param recv_xfer_size the number of bytes for each receive transfer -     * \param recv_num_xfers the number of simultaneous receive transfers -     * \param send_xfer_size the number of bytes for each send transfer -     * \param send_num_xfers the number of simultaneous send transfers +     * \param hints optional parameters to pass to the underlying transport       */      static sptr make(          usb_device_handle::sptr handle, -        unsigned int recv_endpoint, -        unsigned int send_endpoint, -        size_t recv_xfer_size = 0, -        size_t recv_num_xfers = 0, -        size_t send_xfer_size = 0, -        size_t send_num_xfers = 0 +        size_t recv_endpoint, +        size_t send_endpoint, +        const device_addr_t &hints = device_addr_t()      );  }; diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp index 9dd16280c..7d8fb4b83 100644 --- a/host/include/uhd/transport/zero_copy.hpp +++ b/host/include/uhd/transport/zero_copy.hpp @@ -155,15 +155,20 @@ namespace uhd{ namespace transport{          virtual managed_recv_buffer::sptr get_recv_buff(double timeout = 0.1) = 0;          /*! -         * Get the maximum number of receive frames: -         *   The maximum number of valid managed recv buffers, -         *   or the maximum number of frames in the ring buffer, -         *   depending upon the underlying implementation. +         * Get the number of receive frames: +         * The number of simultaneous receive buffers in use.           * \return number of frames           */          virtual size_t get_num_recv_frames(void) const = 0;          /*! +         * Get the size of a receive frame: +         * The maximum capacity of a single receive buffer. +         * \return frame size in bytes +         */ +        virtual size_t get_recv_frame_size(void) const = 0; + +        /*!           * Get a new send buffer from this transport object.           * \param timeout the timeout to get the buffer in seconds           * \return a managed buffer, or null sptr on timeout/error @@ -171,14 +176,19 @@ namespace uhd{ namespace transport{          virtual managed_send_buffer::sptr get_send_buff(double timeout = 0.1) = 0;          /*! -         * Get the maximum number of send frames: -         *   The maximum number of valid managed send buffers, -         *   or the maximum number of frames in the ring buffer, -         *   depending upon the underlying implementation. +         * Get the number of send frames: +         * The number of simultaneous send buffers in use.           * \return number of frames           */          virtual size_t get_num_send_frames(void) const = 0; +        /*! +         * Get the size of a send frame: +         * The maximum capacity of a single send buffer. +         * \return frame size in bytes +         */ +        virtual size_t get_send_frame_size(void) const = 0; +      };  }} //namespace diff --git a/host/include/uhd/types/device_addr.hpp b/host/include/uhd/types/device_addr.hpp index e359d9467..eb3394230 100644 --- a/host/include/uhd/types/device_addr.hpp +++ b/host/include/uhd/types/device_addr.hpp @@ -20,6 +20,8 @@  #include <uhd/config.hpp>  #include <uhd/types/dict.hpp> +#include <boost/lexical_cast.hpp> +#include <stdexcept>  #include <vector>  #include <string> @@ -62,6 +64,24 @@ namespace uhd{           * \return a string with delimiter markup           */          std::string to_string(void) const; + +        /*! +         * Lexically cast a parameter to the specified type, +         * or use the default value if the key is not found. +         * \param key the key as one of the address parameters +         * \param def the value to use when key is not present +         * \return the casted value as type T or the default +         * \throw error when the parameter cannot be casted +         */ +        template <typename T> T cast(const std::string &key, const T &def) const{ +            if (not this->has_key(key)) return def; +            try{ +                return boost::lexical_cast<T>((*this)[key]); +            } +            catch(const boost::bad_lexical_cast &){ +                throw std::runtime_error("cannot cast " + key + " = " + (*this)[key]); +            } +        }      };      //handy typedef for a vector of device addresses diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index eafdd57d2..b95d46381 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -37,7 +37,9 @@ IF(LIBUSB_FOUND)      ENDIF(MSVC)      SET(HAVE_USB_SUPPORT TRUE)  ELSE(LIBUSB_FOUND) -    #TODO dummy usb +    LIBUHD_APPEND_SOURCES( +        ${CMAKE_SOURCE_DIR}/lib/transport/usb_dummy_impl.cpp +    )  ENDIF(LIBUSB_FOUND)  IF(HAVE_USB_SUPPORT) diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp index 910b04fc8..cfa77d9ca 100644 --- a/host/lib/transport/libusb1_base.cpp +++ b/host/lib/transport/libusb1_base.cpp @@ -16,12 +16,10 @@  //  #include "libusb1_base.hpp" -#include <uhd/utils/thread_priority.hpp>  #include <uhd/utils/assert.hpp>  #include <uhd/types/dict.hpp>  #include <boost/weak_ptr.hpp>  #include <boost/foreach.hpp> -#include <boost/thread.hpp>  #include <iostream>  using namespace uhd; @@ -35,12 +33,9 @@ public:      libusb_session_impl(void){          UHD_ASSERT_THROW(libusb_init(&_context) == 0);          libusb_set_debug(_context, debug_level); -        _thread_group.create_thread(boost::bind(&libusb_session_impl::run_event_loop, this));      }      ~libusb_session_impl(void){ -        _running = false; -        _thread_group.join_all();          libusb_exit(_context);      } @@ -50,19 +45,6 @@ public:  private:      libusb_context *_context; -    boost::thread_group _thread_group; -    bool _running; - -    void run_event_loop(void){ -        set_thread_priority_safe(); -        _running = true; -        timeval tv; -        while(_running){ -            tv.tv_sec = 0; -            tv.tv_usec = 100000; //100ms -            libusb_handle_events_timeout(this->get_context(), &tv); -        } -    }  };  libusb::session::sptr libusb::session::get_global_session(void){ diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index 819874483..f589d7c77 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -18,6 +18,7 @@  #include "libusb1_base.hpp"  #include <uhd/transport/usb_zero_copy.hpp>  #include <uhd/transport/bounded_buffer.hpp> +#include <uhd/utils/thread_priority.hpp>  #include <uhd/utils/assert.hpp>  #include <boost/shared_array.hpp>  #include <boost/foreach.hpp> @@ -26,6 +27,7 @@  #include <vector>  #include <iostream> +using namespace uhd;  using namespace uhd::transport;  static const double CLEANUP_TIMEOUT   = 0.2;    //seconds @@ -284,16 +286,24 @@ public:      libusb_zero_copy_impl(          libusb::device_handle::sptr handle, -        unsigned int recv_endpoint, unsigned int send_endpoint, -        size_t recv_xfer_size, size_t recv_num_xfers, -        size_t send_xfer_size, size_t send_num_xfers +        size_t recv_endpoint, +        size_t send_endpoint, +        const device_addr_t &hints      ); +    ~libusb_zero_copy_impl(void){ +        _threads_running = false; +        _thread_group.join_all(); +    } +      managed_recv_buffer::sptr get_recv_buff(double);      managed_send_buffer::sptr get_send_buff(double); -    size_t get_num_recv_frames(void) const { return _recv_num_frames; } -    size_t get_num_send_frames(void) const { return _send_num_frames; } +    size_t get_num_recv_frames(void) const { return _num_recv_frames; } +    size_t get_num_send_frames(void) const { return _num_send_frames; } + +    size_t get_recv_frame_size(void) const { return _recv_frame_size; } +    size_t get_send_frame_size(void) const { return _send_frame_size; }  private:      void release(libusb_transfer *lut){ @@ -311,9 +321,25 @@ private:      }      libusb::device_handle::sptr _handle; -    size_t _recv_xfer_size, _send_xfer_size; -    size_t _recv_num_frames, _send_num_frames; +    const size_t _recv_frame_size, _num_recv_frames; +    const size_t _send_frame_size, _num_send_frames;      usb_endpoint::sptr _recv_ep, _send_ep; + +    //event handler threads +    boost::thread_group _thread_group; +    bool _threads_running; + +    void run_event_loop(void){ +        set_thread_priority_safe(); +        libusb::session::sptr session = libusb::session::get_global_session(); +        _threads_running = true; +        while(_threads_running){ +            timeval tv; +            tv.tv_sec = 0; +            tv.tv_usec = 100000; //100ms +            libusb_handle_events_timeout(session->get_context(), &tv); +        } +    }  };  /* @@ -323,24 +349,16 @@ private:   */  libusb_zero_copy_impl::libusb_zero_copy_impl(      libusb::device_handle::sptr handle, -    unsigned int recv_endpoint, unsigned int send_endpoint, -    size_t recv_xfer_size, size_t recv_num_xfers, -    size_t send_xfer_size, size_t send_num_xfers -){ -    _handle = handle; - -    //if the sizes are left at 0 (automatic) -> use the defaults -    if (recv_xfer_size == 0) recv_xfer_size = DEFAULT_XFER_SIZE; -    if (recv_num_xfers == 0) recv_num_xfers = DEFAULT_NUM_XFERS; -    if (send_xfer_size == 0) send_xfer_size = DEFAULT_XFER_SIZE; -    if (send_num_xfers == 0) send_num_xfers = DEFAULT_NUM_XFERS; - -    //store the num xfers for the num frames count -    _recv_xfer_size = recv_xfer_size; -    _recv_num_frames = recv_num_xfers; -    _send_xfer_size = send_xfer_size; -    _send_num_frames = send_num_xfers; - +    size_t recv_endpoint, +    size_t send_endpoint, +    const device_addr_t &hints +): +    _handle(handle), +    _recv_frame_size(size_t(hints.cast<double>("recv_frame_size", DEFAULT_XFER_SIZE))), +    _num_recv_frames(size_t(hints.cast<double>("num_recv_frames", DEFAULT_NUM_XFERS))), +    _send_frame_size(size_t(hints.cast<double>("send_frame_size", DEFAULT_XFER_SIZE))), +    _num_send_frames(size_t(hints.cast<double>("num_send_frames", DEFAULT_NUM_XFERS))) +{      _handle->claim_interface(2 /*in interface*/);      _handle->claim_interface(1 /*out interface*/); @@ -348,17 +366,23 @@ libusb_zero_copy_impl::libusb_zero_copy_impl(                                _handle,         // libusb device_handle                                recv_endpoint,   // USB endpoint number                                true,            // IN endpoint -                              recv_xfer_size,  // buffer size per transfer -                              recv_num_xfers   // number of libusb transfers +                              this->get_recv_frame_size(),  // buffer size per transfer +                              this->get_num_recv_frames()   // number of libusb transfers      ));      _send_ep = usb_endpoint::sptr(new usb_endpoint(                                _handle,         // libusb device_handle                                send_endpoint,   // USB endpoint number                                false,           // OUT endpoint -                              send_xfer_size,  // buffer size per transfer -                              send_num_xfers   // number of libusb transfers +                              this->get_send_frame_size(),  // buffer size per transfer +                              this->get_num_send_frames()   // number of libusb transfers      )); + +    //spawn the event handler threads +    size_t concurrency = hints.cast<size_t>("concurrency_hint", 1); +    for (size_t i = 0; i < concurrency; i++) _thread_group.create_thread( +        boost::bind(&libusb_zero_copy_impl::run_event_loop, this) +    );  }  /* @@ -394,7 +418,7 @@ managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff(double timeout){      }      else {          return managed_send_buffer::make_safe( -            boost::asio::mutable_buffer(lut->buffer, _send_xfer_size), +            boost::asio::mutable_buffer(lut->buffer, this->get_send_frame_size()),              boost::bind(&libusb_zero_copy_impl::commit, shared_from_this(), lut, _1)          );      } @@ -405,17 +429,14 @@ managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff(double timeout){   **********************************************************************/  usb_zero_copy::sptr usb_zero_copy::make(      usb_device_handle::sptr handle, -    unsigned int recv_endpoint, unsigned int send_endpoint, -    size_t recv_xfer_size, size_t recv_num_xfers, -    size_t send_xfer_size, size_t send_num_xfers +    size_t recv_endpoint, +    size_t send_endpoint, +    const device_addr_t &hints  ){      libusb::device_handle::sptr dev_handle(libusb::device_handle::get_cached_handle(          boost::static_pointer_cast<libusb::special_handle>(handle)->get_device()      ));      return sptr(new libusb_zero_copy_impl( -        dev_handle, -        recv_endpoint,  send_endpoint, -        recv_xfer_size, recv_num_xfers, -        send_xfer_size, send_num_xfers +        dev_handle, recv_endpoint, send_endpoint, hints      ));  } diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index e9d91fe45..7e28caf2d 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -44,7 +44,7 @@ static const size_t MIN_RECV_SOCK_BUFF_SIZE = size_t(4 * 25e6 * 0.5);  static const size_t MIN_SEND_SOCK_BUFF_SIZE = size_t(10e3);  //the number of async frames to allocate for each send and recv -static const size_t DEFAULT_NUM_ASYNC_FRAMES = 32; +static const size_t DEFAULT_NUM_FRAMES = 32;  //a single concurrent thread for io_service seems to be the fastest  static const size_t CONCURRENCY_HINT = 1; @@ -61,14 +61,15 @@ public:      typedef boost::shared_ptr<udp_zero_copy_asio_impl> sptr;      udp_zero_copy_asio_impl( -        const std::string &addr, const std::string &port, -        size_t recv_frame_size, size_t num_recv_frames, -        size_t send_frame_size, size_t num_send_frames +        const std::string &addr, +        const std::string &port, +        const device_addr_t &hints      ): -        _io_service(CONCURRENCY_HINT), -        _work(new asio::io_service::work(_io_service)), -        _recv_frame_size(recv_frame_size), _num_recv_frames(num_recv_frames), -        _send_frame_size(send_frame_size), _num_send_frames(num_send_frames) +        _io_service(hints.cast<size_t>("concurrency_hint", CONCURRENCY_HINT)), +        _recv_frame_size(size_t(hints.cast<double>("recv_frame_size", udp_simple::mtu))), +        _num_recv_frames(size_t(hints.cast<double>("num_recv_frames", DEFAULT_NUM_FRAMES))), +        _send_frame_size(size_t(hints.cast<double>("send_frame_size", udp_simple::mtu))), +        _num_send_frames(size_t(hints.cast<double>("num_send_frames", DEFAULT_NUM_FRAMES)))      {          //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl; @@ -99,6 +100,7 @@ public:          }          //spawn the service threads that will run the io service +        _work = new asio::io_service::work(_io_service); //new work to delete later          for (size_t i = 0; i < CONCURRENCY_HINT; i++) _thread_group.create_thread(              boost::bind(&udp_zero_copy_asio_impl::service, this)          ); @@ -141,6 +143,7 @@ public:      }      size_t get_num_recv_frames(void) const {return _num_recv_frames;} +    size_t get_recv_frame_size(void) const {return _recv_frame_size;}      //! pop an empty send buffer off of the fifo and bind with the commit callback      managed_send_buffer::sptr get_send_buff(double timeout){ @@ -159,6 +162,7 @@ public:      }      size_t get_num_send_frames(void) const {return _num_send_frames;} +    size_t get_send_frame_size(void) const {return _send_frame_size;}  private:      void service(void){ @@ -242,9 +246,12 @@ template<typename Opt> static void resize_buff_helper(              "Current %s sock buff size: %d bytes"          ) % name % actual_size << std::endl;          if (actual_size < target_size) uhd::print_warning(str(boost::format( -            "The %s buffer is smaller than the requested size.\n" -            "The minimum recommended buffer size is %d bytes.\n" -            "See the USRP2 application notes on buffer resizing.\n" +            "The %1% buffer is smaller than the requested size.\n" +            "The minimum recommended buffer size is %2% bytes.\n" +            "See the transport application notes on buffer resizing.\n" +            #if defined(UHD_PLATFORM_LINUX) +            "Please run: sudo sysctl -w net.core.rmem_max=%2%\n" +            #endif /*defined(UHD_PLATFORM_LINUX)*/          ) % name % min_sock_buff_size));      } @@ -260,14 +267,15 @@ template<typename Opt> static void resize_buff_helper(  udp_zero_copy::sptr udp_zero_copy::make(      const std::string &addr,      const std::string &port, -    size_t recv_buff_size, -    size_t send_buff_size +    const device_addr_t &hints  ){ -    udp_zero_copy_asio_impl::sptr udp_trans(new udp_zero_copy_asio_impl( -        addr, port, -        udp_simple::mtu, DEFAULT_NUM_ASYNC_FRAMES, //recv -        udp_simple::mtu, DEFAULT_NUM_ASYNC_FRAMES  //send -    )); +    udp_zero_copy_asio_impl::sptr udp_trans( +        new udp_zero_copy_asio_impl(addr, port, hints) +    ); + +    //extract buffer size hints from the device addr +    size_t recv_buff_size = size_t(hints.cast<double>("recv_buff_size", 0.0)); +    size_t send_buff_size = size_t(hints.cast<double>("send_buff_size", 0.0));      //call the helper to resize send and recv buffers      resize_buff_helper<asio::socket_base::receive_buffer_size>(udp_trans, recv_buff_size, "recv"); diff --git a/host/lib/transport/usb_dummy_impl.cpp b/host/lib/transport/usb_dummy_impl.cpp new file mode 100644 index 000000000..8a9772e7f --- /dev/null +++ b/host/lib/transport/usb_dummy_impl.cpp @@ -0,0 +1,39 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// 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/transport/usb_device_handle.hpp> +#include <uhd/transport/usb_control.hpp> +#include <uhd/transport/usb_zero_copy.hpp> +#include <uhd/utils/exception.hpp> + +using namespace uhd; +using namespace uhd::transport; + +std::vector<usb_device_handle::sptr> usb_device_handle::get_device_list(boost::uint16_t, boost::uint16_t){ +    return std::vector<usb_device_handle::sptr>(); //empty list +} + +usb_control::sptr usb_control::make(usb_device_handle::sptr){ +    throw std::runtime_error("no usb support -> usb_control::make not implemented"); +} + +usb_zero_copy::sptr usb_zero_copy::make( +    usb_device_handle::sptr, +    size_t, size_t, const device_addr_t & +){ +    throw std::runtime_error("no usb support -> usb_zero_copy::make not implemented"); +} diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index 676b1536a..0a16f7a43 100644 --- a/host/lib/usrp/usrp1/io_impl.cpp +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -33,6 +33,28 @@ using namespace uhd::usrp;  using namespace uhd::transport;  namespace asio = boost::asio; +static const size_t alignment_padding = 512; + +/*********************************************************************** + * Helper struct to associate an offset with a buffer + **********************************************************************/ +class offset_send_buffer{ +public: +    typedef boost::shared_ptr<offset_send_buffer> sptr; + +    static sptr make(managed_send_buffer::sptr buff, size_t offset = 0){ +        return sptr(new offset_send_buffer(buff, offset)); +    } + +    //member variables +    managed_send_buffer::sptr buff; +    size_t offset; /* in bytes */ + +private: +    offset_send_buffer(managed_send_buffer::sptr buff, size_t offset): +        buff(buff), offset(offset){/* NOP */} +}; +  /***********************************************************************   * IO Implementation Details   **********************************************************************/ @@ -41,8 +63,7 @@ struct usrp1_impl::io_impl{          data_transport(data_transport),          underflow_poll_samp_count(0),          overflow_poll_samp_count(0), -        send_buff(data_transport->get_send_buff()), -        num_bytes_committed(0) +        curr_buff(offset_send_buffer::make(data_transport->get_send_buff()))      {          /* NOP */      } @@ -62,98 +83,88 @@ struct usrp1_impl::io_impl{      size_t overflow_poll_samp_count;      //wrapper around the actual send buffer interface -    //all of this to ensure only full buffers are committed -    managed_send_buffer::sptr send_buff; -    size_t num_bytes_committed; -    double send_timeout; -    boost::uint8_t pseudo_buff[BYTES_PER_PACKET]; -    void phony_commit_pseudo_buff(size_t num_bytes); -    void phony_commit_send_buff(size_t num_bytes); -    void commit_send_buff(void); +    //all of this to ensure only aligned lengths are committed +    //NOTE: you must commit before getting a new buffer +    //since the vrt packet handler obeys this, we are ok +    offset_send_buffer::sptr curr_buff; +    void commit_send_buff(offset_send_buffer::sptr, offset_send_buffer::sptr, size_t);      void flush_send_buff(void);      bool get_send_buffs(vrt_packet_handler::managed_send_buffs_t &, double); - -    //helpers to get at the send buffer + offset -    inline void *get_send_mem_ptr(void){ -        return send_buff->cast<boost::uint8_t *>() + num_bytes_committed; -    } -    inline size_t get_send_mem_size(void){ -        return send_buff->size() - num_bytes_committed; -    }  };  /*! - * Accept a commit of num bytes to the pseudo buffer. - * Memcpy the entire contents of pseudo buffer into send buffers. - * - * Under most conditions: - *   The first loop iteration will fill the remainder of the send buffer. - *   The second loop iteration will empty the pseudo buffer remainder. + * Perform an actual commit on the send buffer: + * Copy the remainder of alignment to the next buffer. + * Commit the current buffer at multiples of alignment.   */ -void usrp1_impl::io_impl::phony_commit_pseudo_buff(size_t num_bytes){ -    size_t bytes_to_copy = num_bytes, bytes_copied = 0; -    while(bytes_to_copy){ -        size_t bytes_copied_here = std::min(bytes_to_copy, get_send_mem_size()); -        std::memcpy(get_send_mem_ptr(), pseudo_buff + bytes_copied, bytes_copied_here); -        phony_commit_send_buff(bytes_copied_here); -        bytes_to_copy -= bytes_copied_here; -        bytes_copied += bytes_copied_here; -    } -} +void usrp1_impl::io_impl::commit_send_buff( +    offset_send_buffer::sptr curr, +    offset_send_buffer::sptr next, +    size_t num_bytes +){ +    //total number of bytes now in the current buffer +    size_t bytes_in_curr_buffer = curr->offset + num_bytes; -/*! - * Accept a commit of num bytes to the send buffer. - * Conditionally commit the send buffer if full. - */ -void usrp1_impl::io_impl::phony_commit_send_buff(size_t num_bytes){ -    num_bytes_committed += num_bytes; -    if (num_bytes_committed != send_buff->size()) return; -    commit_send_buff(); +    //calculate how many to commit and remainder +    size_t num_bytes_remaining = bytes_in_curr_buffer % alignment_padding; +    size_t num_bytes_to_commit = bytes_in_curr_buffer - num_bytes_remaining; + +    //copy the remainder into the next buffer +    std::memcpy( +        next->buff->cast<char *>() + next->offset, +        curr->buff->cast<char *>() + num_bytes_to_commit, +        num_bytes_remaining +    ); + +    //update the offset into the next buffer +    next->offset += num_bytes_remaining; + +    //commit the current buffer +    curr->buff->commit(num_bytes_to_commit);  }  /*! - * Flush the send buffer: - * Zero-pad the send buffer to the nearest 512 byte boundary and commit. + * Flush the current buffer by padding out to alignment and committing.   */  void usrp1_impl::io_impl::flush_send_buff(void){ -    size_t bytes_to_pad = (-1*num_bytes_committed)%512; -    std::memset(get_send_mem_ptr(), 0, bytes_to_pad); -    num_bytes_committed += bytes_to_pad; -    commit_send_buff(); +    //calculate the number of bytes to alignment +    size_t bytes_to_pad = (-1*curr_buff->offset)%alignment_padding; + +    //get the buffer, clear, and commit (really current buffer) +    vrt_packet_handler::managed_send_buffs_t buffs(1); +    if (this->get_send_buffs(buffs, 0.1)){ +        std::memset(buffs[0]->cast<void *>(), 0, bytes_to_pad); +        buffs[0]->commit(bytes_to_pad); +    }  }  /*! - * Perform an actual commit on the send buffer: - * Commit the contents of the send buffer and request a new buffer. + * Get a managed send buffer with the alignment padding: + * Always grab the next send buffer so we can timeout here.   */ -void usrp1_impl::io_impl::commit_send_buff(void){ -    send_buff->commit(num_bytes_committed); -    send_buff = data_transport->get_send_buff(send_timeout); -    num_bytes_committed = 0; -} -  bool usrp1_impl::io_impl::get_send_buffs(      vrt_packet_handler::managed_send_buffs_t &buffs, double timeout  ){ -    send_timeout = timeout;      UHD_ASSERT_THROW(buffs.size() == 1); -    //not enough bytes free -> use the pseudo buffer -    if (get_send_mem_size() < BYTES_PER_PACKET){ -        buffs[0] = managed_send_buffer::make_safe( -            boost::asio::buffer(pseudo_buff), -            boost::bind(&usrp1_impl::io_impl::phony_commit_pseudo_buff, this, _1) -        ); -    } -    //otherwise use the send buffer offset by the bytes written -    else{ -        buffs[0] = managed_send_buffer::make_safe( -            boost::asio::buffer(get_send_mem_ptr(), get_send_mem_size()), -            boost::bind(&usrp1_impl::io_impl::phony_commit_send_buff, this, _1) -        ); -    } +    //try to get a new managed buffer with timeout +    offset_send_buffer::sptr next_buff(offset_send_buffer::make(data_transport->get_send_buff(timeout))); +    if (not next_buff->buff.get()) return false; /* propagate timeout here */ -    return buffs[0].get() != NULL; +    //calculate the buffer pointer and size given the offset +    //references to the buffers are held in the bound function +    buffs[0] = managed_send_buffer::make_safe( +        boost::asio::buffer( +            curr_buff->buff->cast<char *>() + curr_buff->offset, +            curr_buff->buff->size()         - curr_buff->offset +        ), +        boost::bind(&usrp1_impl::io_impl::commit_send_buff, this, curr_buff, next_buff, _1) +    ); + +    //store the next buffer for the next call +    curr_buff = next_buff; + +    return true;  }  /*********************************************************************** @@ -182,6 +193,13 @@ static void usrp1_bs_vrt_packer(      if_packet_info.num_packet_words32 = if_packet_info.num_payload_words32;  } +size_t usrp1_impl::get_max_send_samps_per_packet(void) const { +    return (_data_transport->get_send_frame_size() - alignment_padding) +        / _tx_otw_type.get_sample_size() +        / _tx_subdev_spec.size() +    ; +} +  size_t usrp1_impl::send(      const std::vector<const void *> &buffs, size_t num_samps,      const tx_metadata_t &metadata, const io_type_t &io_type, @@ -249,6 +267,13 @@ static bool get_recv_buffs(      return buffs[0].get() != NULL;  } +size_t usrp1_impl::get_max_recv_samps_per_packet(void) const { +    return _data_transport->get_recv_frame_size() +        / _rx_otw_type.get_sample_size() +        / _rx_subdev_spec.size() +    ; +} +  size_t usrp1_impl::recv(      const std::vector<void *> &buffs, size_t num_samps,      rx_metadata_t &metadata, const io_type_t &io_type, diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index 6ebd6bb09..276ca86f6 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -106,17 +106,8 @@ static device_addrs_t usrp1_find(const device_addr_t &hint)  /***********************************************************************   * Make   **********************************************************************/ -template<typename output_type> static output_type cast_from_dev_addr( -    const device_addr_t &device_addr, -    const std::string &key, -    output_type def_val -){ -    return (device_addr.has_key(key))? -        boost::lexical_cast<output_type>(device_addr[key]) : def_val; -} +static device::sptr usrp1_make(const device_addr_t &device_addr){ -static device::sptr usrp1_make(const device_addr_t &device_addr) -{      //extract the FPGA path for the USRP1      std::string usrp1_fpga_image = find_image_path(          device_addr.has_key("fpga")? device_addr["fpga"] : "usrp1_fpga.rbf" @@ -127,29 +118,26 @@ static device::sptr usrp1_make(const device_addr_t &device_addr)      std::vector<usb_device_handle::sptr> device_list =          usb_device_handle::get_device_list(USRP1_VENDOR_ID, USRP1_PRODUCT_ID); -    //create data and control transports -    usb_zero_copy::sptr data_transport; -    usrp_ctrl::sptr usrp_ctrl; - - -    BOOST_FOREACH(usb_device_handle::sptr handle, device_list) { -        if (handle->get_serial() == device_addr["serial"]) { -            usb_control::sptr ctrl_transport = usb_control::make(handle); -            usrp_ctrl = usrp_ctrl::make(ctrl_transport); -            usrp_ctrl->usrp_load_fpga(usrp1_fpga_image); - -            data_transport = usb_zero_copy::make( -                handle,        // identifier -                6,             // IN endpoint -                2,             // OUT endpoint -                size_t(cast_from_dev_addr<double>(device_addr, "recv_xfer_size", 0)), -                size_t(cast_from_dev_addr<double>(device_addr, "recv_num_xfers", 0)), -                size_t(cast_from_dev_addr<double>(device_addr, "send_xfer_size", 0)), -                size_t(cast_from_dev_addr<double>(device_addr, "send_num_xfers", 0)) -            ); +    //locate the matching handle in the device list +    usb_device_handle::sptr handle; +    BOOST_FOREACH(usb_device_handle::sptr dev_handle, device_list) { +        if (dev_handle->get_serial() == device_addr["serial"]){ +            handle = dev_handle;              break;          }      } +    UHD_ASSERT_THROW(handle.get() != NULL); //better be found + +    //create control objects and a data transport +    usb_control::sptr ctrl_transport = usb_control::make(handle); +    usrp_ctrl::sptr usrp_ctrl = usrp_ctrl::make(ctrl_transport); +    usrp_ctrl->usrp_load_fpga(usrp1_fpga_image); +    usb_zero_copy::sptr data_transport = usb_zero_copy::make( +        handle,        // identifier +        6,             // IN endpoint +        2,             // OUT endpoint +        device_addr    // param hints +    );      //create the usrp1 implementation guts      return device::sptr(new usrp1_impl(data_transport, usrp_ctrl)); diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp index f2c464610..ff4d40762 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.hpp +++ b/host/lib/usrp/usrp1/usrp1_impl.hpp @@ -90,15 +90,9 @@ public:                  const uhd::io_type_t &,                  recv_mode_t, double); -    static const size_t BYTES_PER_PACKET = 512*4; //under the transfer size +    size_t get_max_send_samps_per_packet(void) const; -    size_t get_max_send_samps_per_packet(void) const { -        return BYTES_PER_PACKET/_tx_otw_type.get_sample_size()/_tx_subdev_spec.size(); -    } - -    size_t get_max_recv_samps_per_packet(void) const { -        return BYTES_PER_PACKET/_rx_otw_type.get_sample_size()/_rx_subdev_spec.size(); -    } +    size_t get_max_recv_samps_per_packet(void) const;      bool recv_async_msg(uhd::async_metadata_t &, double); diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 33cec3cbc..07eda08c3 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -206,7 +206,7 @@ size_t usrp2_impl::send(          _io_impl->packet_handler_send_state,       //last state of the send handler          buffs, num_samps,                          //buffer to fill          metadata, send_mode,                       //samples metadata -        io_type, _io_helper.get_tx_otw_type(),     //input and output types to convert +        io_type, _tx_otw_type,                     //input and output types to convert          _mboards.front()->get_master_clock_freq(), //master clock tick rate          uhd::transport::vrt::if_hdr_pack_be,          boost::bind(&get_send_buffs, _data_transports, _1, timeout), @@ -226,7 +226,7 @@ size_t usrp2_impl::recv(          _io_impl->packet_handler_recv_state,       //last state of the recv handler          buffs, num_samps,                          //buffer to fill          metadata, recv_mode,                       //samples metadata -        io_type, _io_helper.get_rx_otw_type(),     //input and output types to convert +        io_type, _rx_otw_type,                     //input and output types to convert          _mboards.front()->get_master_clock_freq(), //master clock tick rate          uhd::transport::vrt::if_hdr_unpack_be,          boost::bind(&usrp2_impl::io_impl::get_recv_buffs, _io_impl.get(), _1, timeout) diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 0b9f8ee83..a0e6adfad 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -38,10 +38,10 @@ using namespace uhd::usrp;  usrp2_mboard_impl::usrp2_mboard_impl(      size_t index,      transport::udp_simple::sptr ctrl_transport, -    const usrp2_io_helper &io_helper +    size_t recv_frame_size  ):      _index(index), -    _io_helper(io_helper) +    _recv_frame_size(recv_frame_size)  {      //make a new interface for usrp2 stuff      _iface = usrp2_iface::make(ctrl_transport); @@ -75,7 +75,7 @@ usrp2_mboard_impl::usrp2_mboard_impl(      this->issue_ddc_stream_cmd(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);      //init the rx control registers -    _iface->poke32(U2_REG_RX_CTRL_NSAMPS_PER_PKT, _io_helper.get_max_recv_samps_per_packet()); +    _iface->poke32(U2_REG_RX_CTRL_NSAMPS_PER_PKT, _recv_frame_size);      _iface->poke32(U2_REG_RX_CTRL_NCHANNELS, 1);      _iface->poke32(U2_REG_RX_CTRL_CLEAR_OVERRUN, 1); //reset      _iface->poke32(U2_REG_RX_CTRL_VRT_HEADER, 0 @@ -178,7 +178,7 @@ void usrp2_mboard_impl::set_time_spec(const time_spec_t &time_spec, bool now){  void usrp2_mboard_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){      _iface->poke32(U2_REG_RX_CTRL_STREAM_CMD, dsp_type1::calc_stream_cmd_word( -        stream_cmd, _io_helper.get_max_recv_samps_per_packet() +        stream_cmd, _recv_frame_size      ));      _iface->poke32(U2_REG_RX_CTRL_TIME_SECS,  boost::uint32_t(stream_cmd.time_spec.get_full_secs()));      _iface->poke32(U2_REG_RX_CTRL_TIME_TICKS, stream_cmd.time_spec.get_tick_count(get_master_clock_freq())); diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 568c87a22..a680708ad 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -124,26 +124,7 @@ static uhd::device_addrs_t usrp2_find(const device_addr_t &hint){  /***********************************************************************   * Make   **********************************************************************/ -template <typename out_type, typename in_type> -out_type lexical_cast(const in_type &in){ -    try{ -        return boost::lexical_cast<out_type>(in); -    }catch(...){ -        throw std::runtime_error(str(boost::format( -            "failed to cast \"%s\" to type \"%s\"" -        ) % boost::lexical_cast<std::string>(in) % typeid(out_type).name())); -    } -} -  static device::sptr usrp2_make(const device_addr_t &device_addr){ -    //extract the receive and send buffer sizes -    size_t recv_buff_size = 0, send_buff_size= 0 ; -    if (device_addr.has_key("recv_buff_size")){ -        recv_buff_size = size_t(lexical_cast<double>(device_addr["recv_buff_size"])); -    } -    if (device_addr.has_key("send_buff_size")){ -        send_buff_size = size_t(lexical_cast<double>(device_addr["send_buff_size"])); -    }      //create a ctrl and data transport for each address      std::vector<udp_simple::sptr> ctrl_transports; @@ -154,8 +135,7 @@ static device::sptr usrp2_make(const device_addr_t &device_addr){              addr, num2str(USRP2_UDP_CTRL_PORT)          ));          data_transports.push_back(udp_zero_copy::make( -            addr, num2str(USRP2_UDP_DATA_PORT), -            recv_buff_size, send_buff_size +            addr, num2str(USRP2_UDP_DATA_PORT), device_addr          ));      } @@ -178,11 +158,23 @@ usrp2_impl::usrp2_impl(  ):      _data_transports(data_transports)  { +    //setup rx otw type +    _rx_otw_type.width = 16; +    _rx_otw_type.shift = 0; +    _rx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; + +    //setup tx otw type +    _tx_otw_type.width = 16; +    _tx_otw_type.shift = 0; +    _tx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; + +    //!!!!! set the otw type here before continuing, its used below +      //create a new mboard handler for each control transport      for(size_t i = 0; i < ctrl_transports.size(); i++){ -        _mboards.push_back(usrp2_mboard_impl::sptr( -            new usrp2_mboard_impl(i, ctrl_transports[i], _io_helper) -        )); +        _mboards.push_back(usrp2_mboard_impl::sptr(new usrp2_mboard_impl( +            i, ctrl_transports[i], this->get_max_recv_samps_per_packet() +        )));          //use an empty name when there is only one mboard          std::string name = (ctrl_transports.size() > 1)? boost::lexical_cast<std::string>(i) : "";          _mboard_dict[name] = _mboards.back(); diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index e8763b284..e12c4d6d4 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -72,54 +72,6 @@ private:  };  /*! - * The io helper class encapculates the max packet sizes and otw types. - * The otw types are read-only for now, this will be reimplemented - * when it becomes possible to change the otw type in the usrp2. - */ -class usrp2_io_helper{ -public: -    usrp2_io_helper(void){ -        //setup rx otw type -        _rx_otw_type.width = 16; -        _rx_otw_type.shift = 0; -        _rx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; - -        //setup tx otw type -        _tx_otw_type.width = 16; -        _tx_otw_type.shift = 0; -        _tx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; -    } - -    inline size_t get_max_send_samps_per_packet(void) const{ -        return _max_tx_bytes_per_packet/_tx_otw_type.get_sample_size(); -    } - -    inline size_t get_max_recv_samps_per_packet(void) const{ -        return _max_rx_bytes_per_packet/_rx_otw_type.get_sample_size(); -    } - -    inline const uhd::otw_type_t &get_rx_otw_type(void) const{ -        return _rx_otw_type; -    } - -    inline const uhd::otw_type_t &get_tx_otw_type(void) const{ -        return _tx_otw_type; -    } - -private: -    uhd::otw_type_t _rx_otw_type, _tx_otw_type; -    static const size_t _max_rx_bytes_per_packet = uhd::transport::udp_simple::mtu -        - uhd::transport::vrt::max_if_hdr_words32*sizeof(boost::uint32_t) -        - sizeof(uhd::transport::vrt::if_packet_info_t().tlr) //forced to have trailer -        + sizeof(uhd::transport::vrt::if_packet_info_t().cid) //no class id ever used -    ; -    static const size_t _max_tx_bytes_per_packet = uhd::transport::udp_simple::mtu -        - uhd::transport::vrt::max_if_hdr_words32*sizeof(boost::uint32_t) -        + sizeof(uhd::transport::vrt::if_packet_info_t().cid) //no class id ever used -    ; -}; - -/*!   * USRP2 mboard implementation guts:   * The implementation details are encapsulated here.   * Handles properties on the mboard, dboard, dsps... @@ -129,7 +81,11 @@ public:      typedef boost::shared_ptr<usrp2_mboard_impl> sptr;      //structors -    usrp2_mboard_impl(size_t index, uhd::transport::udp_simple::sptr, const usrp2_io_helper &); +    usrp2_mboard_impl( +        size_t index, +        uhd::transport::udp_simple::sptr, +        size_t recv_frame_size +    );      ~usrp2_mboard_impl(void);      inline double get_master_clock_freq(void){ @@ -139,7 +95,7 @@ public:  private:      size_t _index;      int _rev_hi, _rev_lo; -    const usrp2_io_helper &_io_helper; +    const size_t _recv_frame_size;      //properties for this mboard      void get(const wax::obj &, wax::obj &); @@ -229,7 +185,8 @@ public:      //the io interface      size_t get_max_send_samps_per_packet(void) const{ -        return _io_helper.get_max_send_samps_per_packet(); +        const size_t bytes_per_packet = _data_transports.front()->get_send_frame_size() - _max_tx_header_bytes; +        return bytes_per_packet/_tx_otw_type.get_sample_size();      }      size_t send(          const std::vector<const void *> &, size_t, @@ -237,7 +194,8 @@ public:          uhd::device::send_mode_t, double      );      size_t get_max_recv_samps_per_packet(void) const{ -        return _io_helper.get_max_recv_samps_per_packet(); +        const size_t bytes_per_packet = _data_transports.front()->get_recv_frame_size() - _max_rx_header_bytes; +        return bytes_per_packet/_rx_otw_type.get_sample_size();      }      size_t recv(          const std::vector<void *> &, size_t, @@ -257,9 +215,20 @@ private:      //io impl methods and members      std::vector<uhd::transport::udp_zero_copy::sptr> _data_transports; -    const usrp2_io_helper _io_helper;      UHD_PIMPL_DECL(io_impl) _io_impl;      void io_init(void); + +    //over-the-wire structs and constants +    uhd::otw_type_t _rx_otw_type, _tx_otw_type; +    static const size_t _max_rx_header_bytes = 0 +        + uhd::transport::vrt::max_if_hdr_words32*sizeof(boost::uint32_t) +        + sizeof(uhd::transport::vrt::if_packet_info_t().tlr) //forced to have trailer +        - sizeof(uhd::transport::vrt::if_packet_info_t().cid) //no class id ever used +    ; +    static const size_t _max_tx_header_bytes = 0 +        + uhd::transport::vrt::max_if_hdr_words32*sizeof(boost::uint32_t) +        - sizeof(uhd::transport::vrt::if_packet_info_t().cid) //no class id ever used +    ;  };  #endif /* INCLUDED_USRP2_IMPL_HPP */ | 
