diff options
| author | Josh Blum <josh@joshknows.com> | 2010-04-12 13:39:09 -0700 | 
|---|---|---|
| committer | Josh Blum <josh@joshknows.com> | 2010-04-12 13:39:09 -0700 | 
| commit | e611e610f64b473cdd9d0aa5e40690d7550c3cc0 (patch) | |
| tree | 235c21fd842e05264fd54f85d7ce4045fae42901 /host/lib | |
| parent | 0021abf18aaf3831d8aaa40574f1876c4f346a92 (diff) | |
| download | uhd-e611e610f64b473cdd9d0aa5e40690d7550c3cc0.tar.gz uhd-e611e610f64b473cdd9d0aa5e40690d7550c3cc0.tar.bz2 uhd-e611e610f64b473cdd9d0aa5e40690d7550c3cc0.zip | |
Added data type conversion routines to transport api.
Diffstat (limited to 'host/lib')
| -rw-r--r-- | host/lib/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | host/lib/transport/convert_types.cpp | 144 | ||||
| -rw-r--r-- | host/lib/transport/udp_zero_copy_asio.cpp | 11 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/io_impl.cpp | 128 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.hpp | 2 | 
5 files changed, 175 insertions, 111 deletions
| diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index a5345cae4..fac1bd19f 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -24,6 +24,7 @@ SET(libuhd_sources      load_modules.cpp      types.cpp      wax.cpp +    transport/convert_types.cpp      transport/if_addrs.cpp      transport/udp_simple.cpp      transport/vrt.cpp diff --git a/host/lib/transport/convert_types.cpp b/host/lib/transport/convert_types.cpp new file mode 100644 index 000000000..2a6854f50 --- /dev/null +++ b/host/lib/transport/convert_types.cpp @@ -0,0 +1,144 @@ +// +// 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/convert_types.hpp> +#include <uhd/utils/assert.hpp> +#include <boost/asio.hpp> //endianness conversion +#include <boost/cstdint.hpp> + +using namespace uhd; + +/*********************************************************************** + * Constants + **********************************************************************/ +typedef std::complex<float>          fc32_t; + +static const float shorts_per_float = float(1 << 15); +static const float floats_per_short = float(1.0/shorts_per_float); + +#define unrolled_loop(__inst, __len){ \ +    size_t __i = 0; \ +    for(; __i < (__len & ~0x3); __i+= 4){ \ +        __inst(__i+0); __inst(__i+1); \ +        __inst(__i+2); __inst(__i+3); \ +    } \ +    for(; __i < __len; __i++){ \ +        __inst(__i); \ +    } \ +} + +// set a boolean flag that indicates the endianess +#ifdef HAVE_BIG_ENDIAN +static const bool is_big_endian = true; +#else +static const bool is_big_endian = false; +#endif + +static inline void host_floats_to_usrp2_items( +    boost::uint32_t *usrp2_items, +    const fc32_t *host_floats, +    size_t num_samps +){ +    #define host_floats_to_usrp2_items_i(i){ \ +        boost::uint16_t real = boost::int16_t(host_floats[i].real()*shorts_per_float); \ +        boost::uint16_t imag = boost::int16_t(host_floats[i].imag()*shorts_per_float); \ +        usrp2_items[i] = htonl((real << 16) | (imag << 0)); \ +    } +    unrolled_loop(host_floats_to_usrp2_items_i, num_samps); +} + +static inline void usrp2_items_to_host_floats( +    fc32_t *host_floats, +    const boost::uint32_t *usrp2_items, +    size_t num_samps +){ +    #define usrp2_items_to_host_floats_i(i){ \ +        boost::uint32_t item = ntohl(usrp2_items[i]); \ +        boost::int16_t real = boost::uint16_t(item >> 16); \ +        boost::int16_t imag = boost::uint16_t(item >> 0); \ +        host_floats[i] = fc32_t(float(real*floats_per_short), float(imag*floats_per_short)); \ +    } +    unrolled_loop(usrp2_items_to_host_floats_i, num_samps); +} + +static inline void host_items_to_usrp2_items( +    boost::uint32_t *usrp2_items, +    const boost::uint32_t *host_items, +    size_t num_samps +){ +    #define host_items_to_usrp2_items_i(i) usrp2_items[i] = htonl(host_items[i]) +    if (is_big_endian){ +        std::memcpy(usrp2_items, host_items, num_samps*sizeof(boost::uint32_t)); +    } +    else{ +        unrolled_loop(host_items_to_usrp2_items_i, num_samps); +    } +} + +static inline void usrp2_items_to_host_items( +    boost::uint32_t *host_items, +    const boost::uint32_t *usrp2_items, +    size_t num_samps +){ +    #define usrp2_items_to_host_items_i(i) host_items[i] = ntohl(usrp2_items[i]) +    if (is_big_endian){ +        std::memcpy(host_items, usrp2_items, num_samps*sizeof(boost::uint32_t)); +    } +    else{ +        unrolled_loop(usrp2_items_to_host_items_i, num_samps); +    } +} + +void transport::convert_io_type_to_otw_type( +    const void *io_buff, const io_type_t &io_type, +    void *otw_buff, const otw_type_t &otw_type, +    size_t num_samps +){ +    //all we handle for now: +    ASSERT_THROW(otw_type.width == 16 and otw_type.byteorder == otw_type_t::BO_BIG_ENDIAN); + +    switch(io_type.tid){ +    case io_type_t::COMPLEX_FLOAT32: +        host_floats_to_usrp2_items((boost::uint32_t *)otw_buff, (const fc32_t*)io_buff, num_samps); +        break; +    case io_type_t::COMPLEX_INT16: +        host_items_to_usrp2_items((boost::uint32_t *)otw_buff, (const boost::uint32_t*)io_buff, num_samps); +        break; +    default: +        throw std::runtime_error(str(boost::format("convert_types: cannot handle type \"%c\"") % io_type.tid)); +    } +} + +void transport::convert_otw_type_to_io_type( +    const void *otw_buff, const otw_type_t &otw_type, +    void *io_buff, const io_type_t &io_type, +    size_t num_samps +){ +    //all we handle for now: +    ASSERT_THROW(otw_type.width == 16 and otw_type.byteorder == otw_type_t::BO_BIG_ENDIAN); + +    switch(io_type.tid){ +    case io_type_t::COMPLEX_FLOAT32: +        usrp2_items_to_host_floats((fc32_t*)io_buff, (const boost::uint32_t *)otw_buff, num_samps); +        break; +    case io_type_t::COMPLEX_INT16: +        usrp2_items_to_host_items((boost::uint32_t*)io_buff, (const boost::uint32_t *)otw_buff, num_samps); +        break; +    default: +        throw std::runtime_error(str(boost::format("convert_types: cannot handle type \"%c\"") % io_type.tid)); +    } +} diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index 13fd50f65..3e0e80bd8 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -110,6 +110,9 @@ private:      size_t get_recv_buff_size(void);      void set_recv_buff_size(size_t); + +    static const size_t _mtu = 1500; //FIXME we have no idea +    static const size_t _hdrs = (2 + 14 + 20 + 8); //size of headers (pad, eth, ip, udp)  };  udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::string &port){ @@ -143,7 +146,7 @@ udp_zero_copy_impl::~udp_zero_copy_impl(void){  }  managed_recv_buffer::sptr udp_zero_copy_impl::get_recv_buff(void){ -    boost::uint32_t *buff_mem = new boost::uint32_t[1500/sizeof(boost::uint32_t)]; +    boost::uint32_t *buff_mem = new boost::uint32_t[_mtu/sizeof(boost::uint32_t)];      //implement timeout through polling and sleeping      size_t available = 0; @@ -155,7 +158,7 @@ managed_recv_buffer::sptr udp_zero_copy_impl::get_recv_buff(void){      //receive only if data is available      if (available){ -        available = _socket->receive(boost::asio::buffer(buff_mem, available)); +        available = _socket->receive(boost::asio::buffer(buff_mem, _mtu));      }      //create a new managed buffer to house the data @@ -165,9 +168,9 @@ managed_recv_buffer::sptr udp_zero_copy_impl::get_recv_buff(void){  }  managed_send_buffer::sptr udp_zero_copy_impl::get_send_buff(void){ -    boost::uint32_t *buff_mem = new boost::uint32_t[1500/sizeof(boost::uint32_t)]; +    boost::uint32_t *buff_mem = new boost::uint32_t[_mtu/sizeof(boost::uint32_t)];      return managed_send_buffer::sptr( -        new managed_send_buffer_impl(boost::asio::buffer(buff_mem, 1500), _socket) +        new managed_send_buffer_impl(boost::asio::buffer(buff_mem, _mtu-_hdrs), _socket)      );  } diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index a54c0a409..19a1ecf0f 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -15,9 +15,10 @@  // along with this program.  If not, see <http://www.gnu.org/licenses/>.  // -#include <complex> -#include <boost/format.hpp>  #include "usrp2_impl.hpp" +#include <uhd/transport/convert_types.hpp> +#include <boost/format.hpp> +#include <complex>  using namespace uhd;  using namespace uhd::usrp; @@ -25,18 +26,14 @@ using namespace uhd::transport;  namespace asio = boost::asio;  /*********************************************************************** - * Constants - **********************************************************************/ -typedef std::complex<float>          fc32_t; -typedef std::complex<boost::int16_t> sc16_t; - -static const float shorts_per_float = float(1 << 15); -static const float floats_per_short = float(1.0/shorts_per_float); - -/***********************************************************************   * Helper Functions   **********************************************************************/  void usrp2_impl::io_init(void){ +    //setup otw type +    _otw_type.width = 16; +    _otw_type.shift = 0; +    _otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; +      //initially empty copy buffer      _rx_copy_buff = asio::buffer("", 0); @@ -51,79 +48,6 @@ void usrp2_impl::io_init(void){      send_buff->done(sizeof(data));  } -#define unrolled_loop(__inst, __len){ \ -    size_t __i = 0; \ -    for(; __i < (__len & ~0x3); __i+= 4){ \ -        __inst(__i+0); __inst(__i+1); \ -        __inst(__i+2); __inst(__i+3); \ -    } \ -    for(; __i < __len; __i++){ \ -        __inst(__i); \ -    } \ -} - -// set a boolean flag that indicates the endianess -#ifdef HAVE_BIG_ENDIAN -static const bool is_big_endian = true; -#else -static const bool is_big_endian = false; -#endif - -static inline void host_floats_to_usrp2_items( -    boost::uint32_t *usrp2_items, -    const fc32_t *host_floats, -    size_t num_samps -){ -    #define host_floats_to_usrp2_items_i(i){ \ -        boost::uint16_t real = boost::int16_t(host_floats[i].real()*shorts_per_float); \ -        boost::uint16_t imag = boost::int16_t(host_floats[i].imag()*shorts_per_float); \ -        usrp2_items[i] = htonl((real << 16) | (imag << 0)); \ -    } -    unrolled_loop(host_floats_to_usrp2_items_i, num_samps); -} - -static inline void usrp2_items_to_host_floats( -    fc32_t *host_floats, -    const boost::uint32_t *usrp2_items, -    size_t num_samps -){ -    #define usrp2_items_to_host_floats_i(i){ \ -        boost::uint32_t item = ntohl(usrp2_items[i]); \ -        boost::int16_t real = boost::uint16_t(item >> 16); \ -        boost::int16_t imag = boost::uint16_t(item >> 0); \ -        host_floats[i] = fc32_t(float(real*floats_per_short), float(imag*floats_per_short)); \ -    } -    unrolled_loop(usrp2_items_to_host_floats_i, num_samps); -} - -static inline void host_items_to_usrp2_items( -    boost::uint32_t *usrp2_items, -    const boost::uint32_t *host_items, -    size_t num_samps -){ -    #define host_items_to_usrp2_items_i(i) usrp2_items[i] = htonl(host_items[i]) -    if (is_big_endian){ -        std::memcpy(usrp2_items, host_items, num_samps*sizeof(boost::uint32_t)); -    } -    else{ -        unrolled_loop(host_items_to_usrp2_items_i, num_samps); -    } -} - -static inline void usrp2_items_to_host_items( -    boost::uint32_t *host_items, -    const boost::uint32_t *usrp2_items, -    size_t num_samps -){ -    #define usrp2_items_to_host_items_i(i) host_items[i] = ntohl(usrp2_items[i]) -    if (is_big_endian){ -        std::memcpy(host_items, usrp2_items, num_samps*sizeof(boost::uint32_t)); -    } -    else{ -        unrolled_loop(usrp2_items_to_host_items_i, num_samps); -    } -} -  /***********************************************************************   * Receive Raw Data   **********************************************************************/ @@ -182,7 +106,7 @@ size_t usrp2_impl::send(      boost::uint32_t *tx_mem = send_buff->cast<boost::uint32_t *>();      size_t num_samps = std::min(          asio::buffer_size(buff), -        send_buff->size() +        send_buff->size()-vrt::max_header_words32*sizeof(boost::uint32_t)      )/io_type.size;      //kill the end of burst flag if this is a fragment @@ -204,17 +128,12 @@ size_t usrp2_impl::send(      boost::uint32_t *items = tx_mem + num_header_words32; //offset for data -    //copy the samples into the send buffer -    switch(io_type.tid){ -    case io_type_t::COMPLEX_FLOAT32: -        host_floats_to_usrp2_items(items, asio::buffer_cast<const fc32_t*>(buff), num_samps); -        break; -    case io_type_t::COMPLEX_INT16: -        host_items_to_usrp2_items(items, asio::buffer_cast<const boost::uint32_t*>(buff), num_samps); -        break; -    default: -        throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%c\"") % io_type.tid)); -    } +    //copy-convert the samples into the send buffer +    convert_io_type_to_otw_type( +        asio::buffer_cast<const void*>(buff), io_type, +        (void*)items, _otw_type, +        num_samps +    );      //send and return number of samples      send_buff->done(num_packet_words32*sizeof(boost::uint32_t)); @@ -254,17 +173,12 @@ size_t usrp2_impl::recv(      metadata.fragment_offset = _fragment_offset_in_samps;      _fragment_offset_in_samps += num_samps; //set for next time -    //copy the samples from the recv buffer -    switch(io_type.tid){ -    case io_type_t::COMPLEX_FLOAT32: -        usrp2_items_to_host_floats(asio::buffer_cast<fc32_t*>(buff), items, num_samps); -        break; -    case io_type_t::COMPLEX_INT16: -        usrp2_items_to_host_items(asio::buffer_cast<boost::uint32_t*>(buff), items, num_samps); -        break; -    default: -        throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%c\"") % io_type.tid)); -    } +    //copy-convert the samples from the recv buffer +    convert_otw_type_to_io_type( +        (const void*)items, _otw_type, +        asio::buffer_cast<void*>(buff), io_type, +        num_samps +    );      //update the rx copy buffer to reflect the bytes copied      _rx_copy_buff = asio::buffer( diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index be09c4ee1..4e7154afa 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -20,6 +20,7 @@  #include <uhd/usrp/usrp2.hpp>  #include <uhd/types/dict.hpp> +#include <uhd/types/otw_type.hpp>  #include <uhd/types/stream_cmd.hpp>  #include <uhd/types/clock_config.hpp>  #include <boost/asio.hpp> @@ -139,6 +140,7 @@ private:      uhd::transport::managed_recv_buffer::sptr _rx_smart_buff;      boost::asio::const_buffer _rx_copy_buff;      size_t _fragment_offset_in_samps; +    uhd::otw_type_t _otw_type;      void io_init(void);      //udp transports for control and data | 
