diff options
| author | Josh Blum <josh@joshknows.com> | 2010-05-18 17:46:34 -0700 | 
|---|---|---|
| committer | Josh Blum <josh@joshknows.com> | 2010-05-18 17:46:34 -0700 | 
| commit | 21e9cf4bece884ced5b7294e012be971e941c511 (patch) | |
| tree | 634f4b8b27d9dc8a6ebfc2ab731bddf62d0bbe22 | |
| parent | 7c98884eda041b676584059ca3a63b11f1bbd505 (diff) | |
| parent | 4ea8822a50073b01ede9e0b0f7c8c713767ea1b8 (diff) | |
| download | uhd-21e9cf4bece884ced5b7294e012be971e941c511.tar.gz uhd-21e9cf4bece884ced5b7294e012be971e941c511.tar.bz2 uhd-21e9cf4bece884ced5b7294e012be971e941c511.zip | |
Merge branch 'work'
| -rw-r--r-- | host/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | host/examples/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | host/examples/rx_timed_samples.cpp | 13 | ||||
| -rw-r--r-- | host/examples/tx_timed_samples.cpp | 92 | ||||
| -rw-r--r-- | host/include/uhd/config.hpp | 9 | ||||
| -rw-r--r-- | host/include/uhd/device.hpp | 57 | ||||
| -rw-r--r-- | host/include/uhd/transport/zero_copy.hpp | 12 | ||||
| -rw-r--r-- | host/include/uhd/types/mac_addr.hpp | 2 | ||||
| -rw-r--r-- | host/include/uhd/types/otw_type.hpp | 6 | ||||
| -rw-r--r-- | host/include/uhd/usrp/device_props.hpp | 4 | ||||
| -rw-r--r-- | host/lib/transport/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | host/lib/transport/udp_zero_copy_asio.cpp | 136 | ||||
| -rw-r--r-- | host/lib/transport/vrt_packet_handler.hpp | 358 | ||||
| -rw-r--r-- | host/lib/types.cpp | 119 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/clock_ctrl.cpp | 8 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/io_impl.cpp | 162 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/mboard_impl.cpp | 2 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.cpp | 8 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.hpp | 50 | 
19 files changed, 749 insertions, 295 deletions
| diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index f2725e4b3..0b2d3f012 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -62,6 +62,7 @@ IF(UNIX)      UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-ansi      HAVE_ANSI)      #only export symbols that are declared to be part of the uhd api:      UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN) +    UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-O3 HAVE_O3) #have some optimizations  ENDIF(UNIX)  IF(WIN32) diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt index 242857625..a537c0901 100644 --- a/host/examples/CMakeLists.txt +++ b/host/examples/CMakeLists.txt @@ -18,3 +18,7 @@  ADD_EXECUTABLE(rx_timed_samples rx_timed_samples.cpp)  TARGET_LINK_LIBRARIES(rx_timed_samples uhd)  INSTALL(TARGETS rx_timed_samples RUNTIME DESTINATION ${PKG_DATA_DIR}/examples) + +ADD_EXECUTABLE(tx_timed_samples tx_timed_samples.cpp) +TARGET_LINK_LIBRARIES(tx_timed_samples uhd) +INSTALL(TARGETS tx_timed_samples RUNTIME DESTINATION ${PKG_DATA_DIR}/examples) diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp index 4b8774036..d2306c7c4 100644 --- a/host/examples/rx_timed_samples.cpp +++ b/host/examples/rx_timed_samples.cpp @@ -29,7 +29,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      std::string args;      int seconds_in_future;      size_t total_num_samps; -    double rx_rate; +    double rx_rate, freq;      //setup the program options      po::options_description desc("Allowed options"); @@ -39,10 +39,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){          ("secs", po::value<int>(&seconds_in_future)->default_value(3), "number of seconds in the future to receive")          ("nsamps", po::value<size_t>(&total_num_samps)->default_value(1000), "total number of samples to receive")          ("rxrate", po::value<double>(&rx_rate)->default_value(100e6/16), "rate of incoming samples") +        ("freq", po::value<double>(&freq)->default_value(0), "rf center frequency in Hz")      ;      po::variables_map vm;      po::store(po::parse_command_line(argc, argv, desc), vm); -    po::notify(vm);  +    po::notify(vm);      //print the help message      if (vm.count("help")){ @@ -62,6 +63,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      sdev->set_rx_rate(rx_rate);      std::cout << boost::format("Actual RX Rate: %f Msps...") % (sdev->get_rx_rate()/1e6) << std::endl;      std::cout << boost::format("Setting device timestamp to 0...") << std::endl; +    sdev->set_rx_freq(freq);      sdev->set_time_now(uhd::time_spec_t(0));      //setup streaming @@ -78,10 +80,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      size_t num_acc_samps = 0; //number of accumulated samples      while(num_acc_samps < total_num_samps){          uhd::rx_metadata_t md; -        std::complex<float> buff[1000]; +        std::vector<std::complex<float> > buff(dev->get_max_recv_samps_per_packet());          size_t num_rx_samps = dev->recv( -            boost::asio::buffer(buff, sizeof(buff)), -            md, uhd::io_type_t::COMPLEX_FLOAT32 +            boost::asio::buffer(buff), +            md, uhd::io_type_t::COMPLEX_FLOAT32, +            uhd::device::RECV_MODE_ONE_PACKET          );          if (num_rx_samps == 0) continue; //wait for packets with contents diff --git a/host/examples/tx_timed_samples.cpp b/host/examples/tx_timed_samples.cpp new file mode 100644 index 000000000..6dee69cd5 --- /dev/null +++ b/host/examples/tx_timed_samples.cpp @@ -0,0 +1,92 @@ +// +// 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/utils/safe_main.hpp> +#include <uhd/usrp/simple_usrp.hpp> +#include <boost/program_options.hpp> +#include <boost/format.hpp> +#include <iostream> +#include <complex> + +namespace po = boost::program_options; + +int UHD_SAFE_MAIN(int argc, char *argv[]){ +    //variables to be set by po +    std::string args; +    int seconds_in_future; +    size_t total_num_samps; +    double tx_rate, freq; +    float ampl; + +    //setup the program options +    po::options_description desc("Allowed options"); +    desc.add_options() +        ("help", "help message") +        ("args", po::value<std::string>(&args)->default_value(""), "simple uhd device address args") +        ("secs", po::value<int>(&seconds_in_future)->default_value(3), "number of seconds in the future to transmit") +        ("nsamps", po::value<size_t>(&total_num_samps)->default_value(1000), "total number of samples to transmit") +        ("txrate", po::value<double>(&tx_rate)->default_value(100e6/16), "rate of outgoing samples") +        ("freq", po::value<double>(&freq)->default_value(0), "rf center frequency in Hz") +        ("ampl", po::value<float>(&l)->default_value(0.3), "amplitude of each sample") +    ; +    po::variables_map vm; +    po::store(po::parse_command_line(argc, argv, desc), vm); +    po::notify(vm); + +    //print the help message +    if (vm.count("help")){ +        std::cout << boost::format("UHD TX Timed Samples %s") % desc << std::endl; +        return ~0; +    } + +    //create a usrp device +    std::cout << std::endl; +    std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; +    uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args); +    uhd::device::sptr dev = sdev->get_device(); +    std::cout << boost::format("Using Device: %s") % sdev->get_name() << std::endl; + +    //set properties on the device +    std::cout << boost::format("Setting TX Rate: %f Msps...") % (tx_rate/1e6) << std::endl; +    sdev->set_tx_rate(tx_rate); +    std::cout << boost::format("Actual TX Rate: %f Msps...") % (sdev->get_tx_rate()/1e6) << std::endl; +    std::cout << boost::format("Setting device timestamp to 0...") << std::endl; +    sdev->set_tx_freq(freq); +    sdev->set_time_now(uhd::time_spec_t(0)); + +    //data to send +    std::vector<std::complex<float> > buff(total_num_samps, std::complex<float>(ampl, ampl)); +    uhd::tx_metadata_t md; +    md.start_of_burst = true; +    md.end_of_burst = true; +    md.has_time_spec = true; +    md.time_spec = uhd::time_spec_t(seconds_in_future); + +    //send the entire buffer, let the driver handle fragmentation +    size_t num_tx_samps = dev->send( +        boost::asio::buffer(buff), +        md, uhd::io_type_t::COMPLEX_FLOAT32, +        uhd::device::SEND_MODE_FULL_BUFF +    ); +    std::cout << std::endl << boost::format("Sent %d samples") % num_tx_samps << std::endl; + + +    //finished +    std::cout << std::endl << "Done!" << std::endl << std::endl; + +    return 0; +} diff --git a/host/include/uhd/config.hpp b/host/include/uhd/config.hpp index 32eafc89b..fea95145c 100644 --- a/host/include/uhd/config.hpp +++ b/host/include/uhd/config.hpp @@ -76,4 +76,13 @@      #define UHD_LOCAL  #endif // UHD_DLL +// Define force inline macro +#ifdef BOOST_MSVC +    #define UHD_INLINE __forceinline +#elif defined(__GNUG__) && __GNUG__ >= 4 +    #define UHD_INLINE inline __attribute__((always_inline)) +#else +    #define UHD_INLINE inline +#endif +  #endif /* INCLUDED_UHD_CONFIG_HPP */ diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index ae75e6dc8..27b461184 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -77,15 +77,35 @@ public:      static sptr make(const device_addr_t &hint, size_t which = 0);      /*! +     * Send modes for the device send routine. +     */ +    enum send_mode_t{ +        //! Tells the send routine to send the entire buffer +        SEND_MODE_FULL_BUFF = 0, +        //! Tells the send routine to return after one packet +        SEND_MODE_ONE_PACKET = 1 +    }; + +    /*! +     * Recv modes for the device recv routine. +     */ +    enum recv_mode_t{ +        //! Tells the recv routine to recv the entire buffer +        RECV_MODE_FULL_BUFF = 0, +        //! Tells the recv routine to return after one packet +        RECV_MODE_ONE_PACKET = 1 +    }; + +    /*!       * Send a buffer containing IF data with its metadata.       *       * Send handles fragmentation as follows: -     * If the buffer has more samples than the maximum supported, -     * the send method will send the maximum number of samples -     * as supported by the transport and return the number sent. -     * In this case, the end of burst flag will be forced to false. -     * It is up to the caller to call send again on the un-sent -     * portions of the buffer, until the buffer is exhausted. +     * If the buffer has more samples than the maximum per packet, +     * the send method will fragment the samples across several packets. +     * Send will respect the burst flags when fragmenting to ensure +     * that start of burst can only be set on the first fragment and +     * that end of burst can only be set on the final fragment. +     * Fragmentation only applies in the full buffer send mode.       *       * This is a blocking call and will not return until the number       * of samples returned have been read out of the buffer. @@ -93,12 +113,14 @@ public:       * \param buff a buffer pointing to some read-only memory       * \param metadata data describing the buffer's contents       * \param io_type the type of data loaded in the buffer +     * \param send_mode tells send how to unload the buffer       * \return the number of samples sent       */      virtual size_t send(          const boost::asio::const_buffer &buff,          const tx_metadata_t &metadata, -        const io_type_t &io_type +        const io_type_t &io_type, +        send_mode_t send_mode = SEND_MODE_ONE_PACKET      ) = 0;      /*! @@ -123,16 +145,35 @@ public:       * immediately when no packets are available to the transport layer,       * and that the timeout duration is reasonably tuned for performance.       * +     * When using the full buffer recv mode, the metadata only applies +     * to the first packet received and written into the recv buffer. +     * Use the one packet recv mode to get per packet metadata. +     *       * \param buff the buffer to fill with IF data       * \param metadata data to fill describing the buffer       * \param io_type the type of data to fill into the buffer +     * \param recv_mode tells recv how to load the buffer       * \return the number of samples received       */      virtual size_t recv(          const boost::asio::mutable_buffer &buff,          rx_metadata_t &metadata, -        const io_type_t &io_type +        const io_type_t &io_type, +        recv_mode_t recv_mode = RECV_MODE_ONE_PACKET      ) = 0; + +    /*! +     * Get the maximum number of samples per packet on send. +     * \return the number of samples +     */ +    virtual size_t get_max_send_samps_per_packet(void) const = 0; + +    /*! +     * Get the maximum number of samples per packet on recv. +     * \return the number of samples +     */ +    virtual size_t get_max_recv_samps_per_packet(void) const = 0; +  };  } //namespace uhd diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp index 4fc1df9de..fdc5b141c 100644 --- a/host/include/uhd/transport/zero_copy.hpp +++ b/host/include/uhd/transport/zero_copy.hpp @@ -45,7 +45,7 @@ public:       * Get the size of the underlying buffer.       * \return the number of bytes       */ -    size_t size(void){ +    size_t size(void) const{          return boost::asio::buffer_size(this->get());      } @@ -53,7 +53,7 @@ public:       * Get a pointer to the underlying buffer.       * \return a pointer into memory       */ -    template <class T> T cast(void){ +    template <class T> T cast(void) const{          return boost::asio::buffer_cast<T>(this->get());      } @@ -63,7 +63,7 @@ private:       * The buffer has a reference to memory and a size.       * \return a boost asio const buffer       */ -    virtual const boost::asio::const_buffer &get(void) = 0; +    virtual const boost::asio::const_buffer &get(void) const = 0;  };  /*! @@ -87,7 +87,7 @@ public:       * Get the size of the underlying buffer.       * \return the number of bytes       */ -    size_t size(void){ +    size_t size(void) const{          return boost::asio::buffer_size(this->get());      } @@ -95,7 +95,7 @@ public:       * Get a pointer to the underlying buffer.       * \return a pointer into memory       */ -    template <class T> T cast(void){ +    template <class T> T cast(void) const{          return boost::asio::buffer_cast<T>(this->get());      } @@ -105,7 +105,7 @@ private:       * The buffer has a reference to memory and a size.       * \return a boost asio mutable buffer       */ -    virtual const boost::asio::mutable_buffer &get(void) = 0; +    virtual const boost::asio::mutable_buffer &get(void) const = 0;  };  /*! diff --git a/host/include/uhd/types/mac_addr.hpp b/host/include/uhd/types/mac_addr.hpp index 034b6a348..0ced2e734 100644 --- a/host/include/uhd/types/mac_addr.hpp +++ b/host/include/uhd/types/mac_addr.hpp @@ -58,7 +58,7 @@ namespace uhd{      private:          mac_addr_t(const byte_vector_t &bytes); //private constructor -        byte_vector_t _bytes; //internal representation +        const byte_vector_t _bytes; //internal representation      };  } //namespace uhd diff --git a/host/include/uhd/types/otw_type.hpp b/host/include/uhd/types/otw_type.hpp index f10664584..8e3e65d78 100644 --- a/host/include/uhd/types/otw_type.hpp +++ b/host/include/uhd/types/otw_type.hpp @@ -55,6 +55,12 @@ namespace uhd{              BO_NOT_APPLICABLE = '|'          } byteorder; +        /*! +         * Get the sample size of this otw type. +         * \return the size of a sample in bytes +         */ +        size_t get_sample_size(void) const; +          otw_type_t(void);      }; diff --git a/host/include/uhd/usrp/device_props.hpp b/host/include/uhd/usrp/device_props.hpp index b8f6f5cd4..983bcb672 100644 --- a/host/include/uhd/usrp/device_props.hpp +++ b/host/include/uhd/usrp/device_props.hpp @@ -31,9 +31,7 @@ namespace uhd{ namespace usrp{      enum device_prop_t{          DEVICE_PROP_NAME           = 'n', //ro, std::string          DEVICE_PROP_MBOARD         = 'm', //ro, wax::obj -        DEVICE_PROP_MBOARD_NAMES   = 'M', //ro, prop_names_t -        DEVICE_PROP_MAX_RX_SAMPLES = 'r', //ro, size_t -        DEVICE_PROP_MAX_TX_SAMPLES = 't'  //ro, size_t +        DEVICE_PROP_MBOARD_NAMES   = 'M'  //ro, prop_names_t      };      //////////////////////////////////////////////////////////////////////// diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index a36f0fc03..ed8c35225 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -49,4 +49,5 @@ LIBUHD_APPEND_SOURCES(      ${CMAKE_SOURCE_DIR}/lib/transport/if_addrs.cpp      ${CMAKE_SOURCE_DIR}/lib/transport/udp_simple.cpp      ${CMAKE_SOURCE_DIR}/lib/transport/udp_zero_copy_asio.cpp +    ${CMAKE_SOURCE_DIR}/lib/transport/vrt_packet_handler.hpp  ) diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index ee44803f4..56ba391d3 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -16,9 +16,9 @@  //  #include <uhd/transport/udp_zero_copy.hpp> +#include <uhd/utils/assert.hpp>  #include <boost/cstdint.hpp>  #include <boost/asio.hpp> -#include <boost/thread.hpp>  #include <boost/format.hpp>  #include <iostream> @@ -26,65 +26,56 @@ using namespace uhd::transport;  /***********************************************************************   * Managed receive buffer implementation for udp zero-copy asio: - *   Frees the memory held by the const buffer on done.   **********************************************************************/  class managed_recv_buffer_impl : public managed_recv_buffer{  public:      managed_recv_buffer_impl(const boost::asio::const_buffer &buff) : _buff(buff){ -        _done = false; +        /* NOP */      }      ~managed_recv_buffer_impl(void){ -        if (not _done) this->done(); +        /* NOP */      }      void done(void){ -        _done = true; -        delete [] boost::asio::buffer_cast<const boost::uint32_t *>(_buff); +        /* NOP */      }  private: -    const boost::asio::const_buffer &get(void){ +    const boost::asio::const_buffer &get(void) const{          return _buff;      }      const boost::asio::const_buffer _buff; -    bool _done;  };  /***********************************************************************   * Managed send buffer implementation for udp zero-copy asio: - *   Sends and frees the memory held by the mutable buffer on done.   **********************************************************************/  class managed_send_buffer_impl : public managed_send_buffer{  public:      managed_send_buffer_impl(          const boost::asio::mutable_buffer &buff,          boost::asio::ip::udp::socket *socket -    ) : _buff(buff){ -        _done = false; -        _socket = socket; +    ) : _buff(buff), _socket(socket){ +        /* NOP */      }      ~managed_send_buffer_impl(void){ -        if (not _done) this->done(0); +        /* NOP */      }      void done(size_t num_bytes){ -        _done = true; -        boost::uint32_t *mem = boost::asio::buffer_cast<boost::uint32_t *>(_buff); -        _socket->send(boost::asio::buffer(mem, num_bytes)); -        delete [] mem; +        _socket->send(boost::asio::buffer(_buff, num_bytes));      }  private: -    const boost::asio::mutable_buffer &get(void){ +    const boost::asio::mutable_buffer &get(void) const{          return _buff;      }      const boost::asio::mutable_buffer _buff;      boost::asio::ip::udp::socket      *_socket; -    bool _done;  };  /*********************************************************************** @@ -94,8 +85,12 @@ private:   *   However, it is not a true zero copy implementation as each   *   send and recv requires a copy operation to/from userspace.   **********************************************************************/ +static const size_t max_buff_size = 2000; //assume max size on send and recv +  class udp_zero_copy_impl : public udp_zero_copy{  public: +    typedef boost::shared_ptr<udp_zero_copy_impl> sptr; +      //structors      udp_zero_copy_impl(const std::string &addr, const std::string &port);      ~udp_zero_copy_impl(void); @@ -104,23 +99,27 @@ public:      managed_recv_buffer::sptr get_recv_buff(void);      managed_send_buffer::sptr get_send_buff(void); -    //resize -    size_t resize_recv_buff(size_t num_bytes){ -        boost::asio::socket_base::receive_buffer_size option(num_bytes); -        _socket->set_option(option); +    //manage buffer +    template <typename Opt> size_t get_buff_size(void){ +        Opt option;          _socket->get_option(option);          return option.value();      } -    size_t resize_send_buff(size_t num_bytes){ -        boost::asio::socket_base::send_buffer_size option(num_bytes); + +    template <typename Opt> size_t resize_buff(size_t num_bytes){ +        Opt option(num_bytes);          _socket->set_option(option); -        _socket->get_option(option); -        return option.value(); +        return get_buff_size<Opt>();      }  private:      boost::asio::ip::udp::socket   *_socket;      boost::asio::io_service        _io_service; + +    //send and recv buffer memory (allocated once) +    boost::uint8_t _send_mem[max_buff_size], _recv_mem[max_buff_size]; + +    managed_send_buffer::sptr _send_buff;  };  udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::string &port){ @@ -131,10 +130,25 @@ udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::strin      boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), addr, port);      boost::asio::ip::udp::endpoint receiver_endpoint = *resolver.resolve(query); -    // Create, open, and connect the socket +    // create, open, and connect the socket      _socket = new boost::asio::ip::udp::socket(_io_service);      _socket->open(boost::asio::ip::udp::v4());      _socket->connect(receiver_endpoint); + +    // create the managed send buff (just once) +    _send_buff = managed_send_buffer::sptr(new managed_send_buffer_impl( +        boost::asio::buffer(_send_mem, max_buff_size), _socket +    )); + +    // set recv timeout +    timeval tv; +    tv.tv_sec = 0; +    tv.tv_usec = 100*1000; //100 ms +    UHD_ASSERT_THROW(setsockopt( +        _socket->native(), +        SOL_SOCKET, SO_RCVTIMEO, +        (const char *)&tv, sizeof(timeval) +    ) == 0);  }  udp_zero_copy_impl::~udp_zero_copy_impl(void){ @@ -142,61 +156,55 @@ udp_zero_copy_impl::~udp_zero_copy_impl(void){  }  managed_recv_buffer::sptr udp_zero_copy_impl::get_recv_buff(void){ -    //implement timeout through polling and sleeping -    size_t available = 0; -    boost::asio::deadline_timer timer(_socket->get_io_service()); -    timer.expires_from_now(boost::posix_time::milliseconds(100)); -    while (not ((available = _socket->available()) or timer.expires_from_now().is_negative())){ -        boost::this_thread::sleep(boost::posix_time::milliseconds(1)); -    } - -    //receive only if data is available -    boost::uint32_t *buff_mem = new boost::uint32_t[available/sizeof(boost::uint32_t)]; -    if (available){ -        available = _socket->receive(boost::asio::buffer(buff_mem, available)); -    } +    //call recv() with timeout option +    size_t num_bytes = _socket->receive(boost::asio::buffer(_recv_mem, max_buff_size));      //create a new managed buffer to house the data      return managed_recv_buffer::sptr( -        new managed_recv_buffer_impl(boost::asio::buffer(buff_mem, available)) +        new managed_recv_buffer_impl(boost::asio::buffer(_recv_mem, num_bytes))      );  }  managed_send_buffer::sptr udp_zero_copy_impl::get_send_buff(void){ -    boost::uint32_t *buff_mem = new boost::uint32_t[2000/sizeof(boost::uint32_t)]; -    return managed_send_buffer::sptr( -        new managed_send_buffer_impl(boost::asio::buffer(buff_mem, 2000), _socket) -    ); +    return _send_buff;  }  /***********************************************************************   * UDP zero copy make function   **********************************************************************/ +template<typename Opt> static inline void resize_buff_helper( +    udp_zero_copy_impl::sptr udp_trans, +    size_t target_size, +    const std::string &name +){ +    static const size_t min_buff_size = size_t(100e3); + +    //resize the buffer if size was provided +    if (target_size > 0){ +        size_t actual_size = udp_trans->resize_buff<Opt>(target_size); +        if (target_size != actual_size) std::cout << boost::format( +            "Target %s buffer size: %d\n" +            "Actual %s byffer size: %d" +        ) % name % target_size % name % actual_size << std::endl; +    } + +    //otherwise, ensure that the buffer is at least the minimum size +    else if (udp_trans->get_buff_size<Opt>() < min_buff_size){ +        resize_buff_helper<Opt>(udp_trans, min_buff_size, name); +    } +} +  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  ){ -    boost::shared_ptr<udp_zero_copy_impl> udp_trans(new udp_zero_copy_impl(addr, port)); - -    //resize the recv buffer if size was provided -    if (recv_buff_size > 0){ -        size_t actual_bytes = udp_trans->resize_recv_buff(recv_buff_size); -        if (recv_buff_size != actual_bytes) std::cout << boost::format( -            "Target recv buffer size: %d\n" -            "Actual recv byffer size: %d" -        ) % recv_buff_size % actual_bytes << std::endl; -    } +    udp_zero_copy_impl::sptr udp_trans(new udp_zero_copy_impl(addr, port)); -    //resize the send buffer if size was provided -    if (send_buff_size > 0){ -        size_t actual_bytes = udp_trans->resize_send_buff(send_buff_size); -        if (send_buff_size != actual_bytes) std::cout << boost::format( -            "Target send buffer size: %d\n" -            "Actual send byffer size: %d" -        ) % send_buff_size % actual_bytes << std::endl; -    } +    //call the helper to resize send and recv buffers +    resize_buff_helper<boost::asio::socket_base::receive_buffer_size>(udp_trans, recv_buff_size, "recv"); +    resize_buff_helper<boost::asio::socket_base::send_buffer_size>   (udp_trans, send_buff_size, "send");      return udp_trans;  } diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp new file mode 100644 index 000000000..c857db1c4 --- /dev/null +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -0,0 +1,358 @@ +// +// 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/>. +// + +#ifndef INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP +#define INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP + +#include <uhd/config.hpp> +#include <uhd/device.hpp> +#include <uhd/types/io_type.hpp> +#include <uhd/types/otw_type.hpp> +#include <uhd/types/metadata.hpp> +#include <uhd/transport/vrt.hpp> +#include <uhd/transport/convert_types.hpp> +#include <uhd/transport/zero_copy.hpp> +#include <boost/asio/buffer.hpp> +#include <boost/function.hpp> +#include <iostream> + +namespace vrt_packet_handler{ + +/*********************************************************************** + * vrt packet handler for recv + **********************************************************************/ +    struct recv_state{ +        //init the expected seq number +        size_t next_packet_seq; + +        //state variables to handle fragments +        uhd::transport::managed_recv_buffer::sptr managed_buff; +        boost::asio::const_buffer copy_buff; +        size_t fragment_offset_in_samps; + +        recv_state(void){ +            //first expected seq is zero +            next_packet_seq = 0; + +            //initially empty copy buffer +            copy_buff = boost::asio::buffer("", 0); +        } +    }; + +    typedef boost::function<void(uhd::transport::managed_recv_buffer::sptr)> recv_cb_t; + +    static UHD_INLINE void recv_cb_nop(uhd::transport::managed_recv_buffer::sptr){ +        /* NOP */ +    } + +    /******************************************************************* +     * Unpack a received vrt header and set the copy buffer. +     *  - helper function for vrt_packet_handler::_recv1 +     ******************************************************************/ +    static UHD_INLINE void _recv1_helper( +        recv_state &state, +        uhd::rx_metadata_t &metadata, +        double tick_rate, +        size_t vrt_header_offset_words32 +    ){ +        size_t num_packet_words32 = state.managed_buff->size()/sizeof(boost::uint32_t); +        if (num_packet_words32 <= vrt_header_offset_words32){ +            state.copy_buff = boost::asio::buffer("", 0); +            return; //must exit here after setting the buffer +        } +        const boost::uint32_t *vrt_hdr = state.managed_buff->cast<const boost::uint32_t *>() + vrt_header_offset_words32; +        size_t num_header_words32_out, num_payload_words32_out, packet_count_out; +        uhd::transport::vrt::unpack( +            metadata,                //output +            vrt_hdr,                 //input +            num_header_words32_out,  //output +            num_payload_words32_out, //output +            num_packet_words32,      //input +            packet_count_out,        //output +            tick_rate +        ); + +        //handle the packet count / sequence number +        if (packet_count_out != state.next_packet_seq){ +            std::cerr << "S" << (packet_count_out - state.next_packet_seq)%16; +        } +        state.next_packet_seq = (packet_count_out+1)%16; + +        //setup the buffer to point to the data +        state.copy_buff = boost::asio::buffer( +            vrt_hdr + num_header_words32_out, +            num_payload_words32_out*sizeof(boost::uint32_t) +        ); +    } + +    /******************************************************************* +     * Recv data, unpack a vrt header, and copy-convert the data. +     *  - helper function for vrt_packet_handler::recv +     ******************************************************************/ +    static UHD_INLINE size_t _recv1( +        recv_state &state, +        void *recv_mem, +        size_t total_samps, +        uhd::rx_metadata_t &metadata, +        const uhd::io_type_t &io_type, +        const uhd::otw_type_t &otw_type, +        double tick_rate, +        uhd::transport::zero_copy_if::sptr zc_iface, +        //use these two params to handle a layer above vrt +        size_t vrt_header_offset_words32, +        const recv_cb_t& recv_cb +    ){ +        //perform a receive if no rx data is waiting to be copied +        if (boost::asio::buffer_size(state.copy_buff) == 0){ +            state.fragment_offset_in_samps = 0; +            state.managed_buff = zc_iface->get_recv_buff(); +            recv_cb(state.managed_buff); //callback before vrt unpack +            _recv1_helper( +                state, metadata, tick_rate, vrt_header_offset_words32 +            ); +        } + +        //extract the number of samples available to copy +        size_t bytes_per_item = otw_type.get_sample_size(); +        size_t bytes_available = boost::asio::buffer_size(state.copy_buff); +        size_t num_samps = std::min(total_samps, bytes_available/bytes_per_item); + +        //setup the fragment flags and offset +        metadata.more_fragments = total_samps < num_samps; +        metadata.fragment_offset = state.fragment_offset_in_samps; +        state.fragment_offset_in_samps += num_samps; //set for next call + +        //copy-convert the samples from the recv buffer +        uhd::transport::convert_otw_type_to_io_type( +            boost::asio::buffer_cast<const void*>(state.copy_buff), otw_type, +            recv_mem, io_type, num_samps +        ); + +        //update the rx copy buffer to reflect the bytes copied +        size_t bytes_copied = num_samps*bytes_per_item; +        state.copy_buff = boost::asio::buffer( +            boost::asio::buffer_cast<const boost::uint8_t*>(state.copy_buff) + bytes_copied, +            bytes_available - bytes_copied +        ); + +        return num_samps; +    } + +    /******************************************************************* +     * Recv vrt packets and copy convert the samples into the buffer. +     ******************************************************************/ +    static UHD_INLINE size_t recv( +        recv_state &state, +        const boost::asio::mutable_buffer &buff, +        uhd::rx_metadata_t &metadata, +        uhd::device::recv_mode_t recv_mode, +        const uhd::io_type_t &io_type, +        const uhd::otw_type_t &otw_type, +        double tick_rate, +        uhd::transport::zero_copy_if::sptr zc_iface, +        //use these two params to handle a layer above vrt +        size_t vrt_header_offset_words32 = 0, +        const recv_cb_t& recv_cb = &recv_cb_nop +    ){ +        metadata = uhd::rx_metadata_t(); //init the metadata +        const size_t total_num_samps = boost::asio::buffer_size(buff)/io_type.size; + +        switch(recv_mode){ + +        //////////////////////////////////////////////////////////////// +        case uhd::device::RECV_MODE_ONE_PACKET:{ +        //////////////////////////////////////////////////////////////// +            return _recv1( +                state, +                boost::asio::buffer_cast<void *>(buff), +                total_num_samps, +                metadata, +                io_type, otw_type, +                tick_rate, +                zc_iface, +                vrt_header_offset_words32, +                recv_cb +            ); +        } + +        //////////////////////////////////////////////////////////////// +        case uhd::device::RECV_MODE_FULL_BUFF:{ +        //////////////////////////////////////////////////////////////// +            size_t num_samps = 0; +            uhd::rx_metadata_t tmp_md; +            while(num_samps < total_num_samps){ +                num_samps += _recv1( +                    state, +                    boost::asio::buffer_cast<boost::uint8_t *>(buff) + (num_samps*io_type.size), +                    total_num_samps - num_samps, +                    (num_samps == 0)? metadata : tmp_md, //only the first metadata gets kept +                    io_type, otw_type, +                    tick_rate, +                    zc_iface, +                    vrt_header_offset_words32, +                    recv_cb +                ); +            } +            return total_num_samps; +        } +        }//switch(recv_mode) +    } + +/*********************************************************************** + * vrt packet handler for send + **********************************************************************/ +    struct send_state{ +        //init the expected seq number +        size_t next_packet_seq; + +        send_state(void){ +            next_packet_seq = 0; +        } +    }; + +    typedef boost::function<void(uhd::transport::managed_send_buffer::sptr)> send_cb_t; + +    static UHD_INLINE void send_cb_nop(uhd::transport::managed_send_buffer::sptr){ +        /* NOP */ +    } + +    /******************************************************************* +     * Pack a vrt header, copy-convert the data, and send it. +     *  - helper function for vrt_packet_handler::send +     ******************************************************************/ +    static UHD_INLINE void _send1( +        send_state &state, +        const void *send_mem, +        size_t num_samps, +        const uhd::tx_metadata_t &metadata, +        const uhd::io_type_t &io_type, +        const uhd::otw_type_t &otw_type, +        double tick_rate, +        uhd::transport::zero_copy_if::sptr zc_iface, +        size_t vrt_header_offset_words32, +        const send_cb_t& send_cb +    ){ +        //get a new managed send buffer +        uhd::transport::managed_send_buffer::sptr send_buff = zc_iface->get_send_buff(); +        boost::uint32_t *tx_mem = send_buff->cast<boost::uint32_t *>() + vrt_header_offset_words32; + +        size_t num_header_words32, num_packet_words32; +        size_t packet_count = state.next_packet_seq++; + +        //pack metadata into a vrt header +        uhd::transport::vrt::pack( +            metadata,            //input +            tx_mem,              //output +            num_header_words32,  //output +            num_samps,           //input +            num_packet_words32,  //output +            packet_count,        //input +            tick_rate +        ); + +        //copy-convert the samples into the send buffer +        uhd::transport::convert_io_type_to_otw_type( +            send_mem, io_type, +            tx_mem + num_header_words32, otw_type, +            num_samps +        ); + +        send_cb(send_buff); //callback after memory filled + +        //commit the samples to the zero-copy interface +        send_buff->done(num_packet_words32*sizeof(boost::uint32_t)); +    } + +    /******************************************************************* +     * Send vrt packets and copy convert the samples into the buffer. +     ******************************************************************/ +    static UHD_INLINE size_t send( +        send_state &state, +        const boost::asio::const_buffer &buff, +        const uhd::tx_metadata_t &metadata, +        uhd::device::send_mode_t send_mode, +        const uhd::io_type_t &io_type, +        const uhd::otw_type_t &otw_type, +        double tick_rate, +        uhd::transport::zero_copy_if::sptr zc_iface, +        size_t max_samples_per_packet, +        //use these two params to handle a layer above vrt +        size_t vrt_header_offset_words32 = 0, +        const send_cb_t& send_cb = &send_cb_nop +    ){ +        const size_t total_num_samps = boost::asio::buffer_size(buff)/io_type.size; +        switch(send_mode){ + +        //////////////////////////////////////////////////////////////// +        case uhd::device::SEND_MODE_ONE_PACKET:{ +        //////////////////////////////////////////////////////////////// +            size_t num_samps = std::min(total_num_samps, max_samples_per_packet); +            _send1( +                state, +                boost::asio::buffer_cast<const void *>(buff), +                num_samps, +                metadata, +                io_type, otw_type, +                tick_rate, +                zc_iface, +                vrt_header_offset_words32, +                send_cb +            ); +            return num_samps; +        } + +        //////////////////////////////////////////////////////////////// +        case uhd::device::SEND_MODE_FULL_BUFF:{ +        //////////////////////////////////////////////////////////////// +            //calculate constants for fragmentation +            const size_t final_packet_samps = total_num_samps%max_samples_per_packet; +            const size_t num_fragments = (total_num_samps+max_samples_per_packet-1)/max_samples_per_packet; +            static const size_t first_fragment_index = 0; +            const size_t final_fragment_index = num_fragments-1; + +            //make a rw copy of the metadata to re-flag below +            uhd::tx_metadata_t md(metadata); + +            //loop through the following fragment indexes +            for (size_t n = first_fragment_index; n <= final_fragment_index; n++){ + +                //calculate new flags for the fragments +                md.has_time_spec  = md.has_time_spec  and (n == first_fragment_index); +                md.start_of_burst = md.start_of_burst and (n == first_fragment_index); +                md.end_of_burst   = md.end_of_burst   and (n == final_fragment_index); + +                //send the fragment with the helper function +                _send1( +                    state, +                    boost::asio::buffer_cast<const boost::uint8_t *>(buff) + (n*max_samples_per_packet*io_type.size), +                    (n == final_fragment_index)?final_packet_samps:max_samples_per_packet, +                    md, +                    io_type, otw_type, +                    tick_rate, +                    zc_iface, +                    vrt_header_offset_words32, +                    send_cb +                ); +            } +            return total_num_samps; +        } +        }//switch(send_mode) +    } + +} //namespace vrt_packet_handler + +#endif /* INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP */ diff --git a/host/lib/types.cpp b/host/lib/types.cpp index 33eb550a1..daf3be7f7 100644 --- a/host/lib/types.cpp +++ b/host/lib/types.cpp @@ -42,73 +42,89 @@ using namespace uhd;  /***********************************************************************   * ranges   **********************************************************************/ -gain_range_t::gain_range_t(float min_, float max_, float step_){ -    min = min_; -    max = max_; -    step = step_; +gain_range_t::gain_range_t(float min, float max, float step): +    min(min), +    max(max), +    step(step) +{ +    /* NOP */  } -freq_range_t::freq_range_t(double min_, double max_){ -    min = min_; -    max = max_; +freq_range_t::freq_range_t(double min, double max): +    min(min), +    max(max) +{ +    /* NOP */  }  /***********************************************************************   * tune result   **********************************************************************/ -tune_result_t::tune_result_t(void){ -    target_inter_freq = 0.0; -    actual_inter_freq = 0.0; -    target_dsp_freq = 0.0; -    actual_dsp_freq = 0.0; -    spectrum_inverted = false; +tune_result_t::tune_result_t(void): +    target_inter_freq(0.0), +    actual_inter_freq(0.0), +    target_dsp_freq(0.0), +    actual_dsp_freq(0.0), +    spectrum_inverted(false) +{ +    /* NOP */  }  /***********************************************************************   * clock config   **********************************************************************/ -clock_config_t::clock_config_t(void){ -    ref_source = REF_INT, -    pps_source = PPS_INT, -    pps_polarity = PPS_NEG; +clock_config_t::clock_config_t(void): +    ref_source(REF_INT), +    pps_source(PPS_INT), +    pps_polarity(PPS_NEG) +{ +    /* NOP */  }  /***********************************************************************   * stream command   **********************************************************************/ -stream_cmd_t::stream_cmd_t(const stream_mode_t &stream_mode_){ -    stream_mode = stream_mode_; -    stream_now = true; -    num_samps = 0; +stream_cmd_t::stream_cmd_t(const stream_mode_t &stream_mode): +    stream_mode(stream_mode), +    num_samps(0), +    stream_now(true) +{ +    /* NOP */  }  /***********************************************************************   * metadata   **********************************************************************/ -rx_metadata_t::rx_metadata_t(void){ -    stream_id = 0; -    has_stream_id = false; -    time_spec = time_spec_t(); -    has_time_spec = false; -    more_fragments = false; -    fragment_offset = 0; +rx_metadata_t::rx_metadata_t(void): +    has_stream_id(false), +    stream_id(0), +    has_time_spec(false), +    time_spec(time_spec_t()), +    more_fragments(false), +    fragment_offset(0) +{ +    /* NOP */  } -tx_metadata_t::tx_metadata_t(void){ -    stream_id = 0; -    has_stream_id = false; -    time_spec = time_spec_t(); -    has_time_spec = false; -    start_of_burst = false; -    end_of_burst = false; +tx_metadata_t::tx_metadata_t(void): +    has_stream_id(false), +    stream_id(0), +    has_time_spec(false), +    time_spec(time_spec_t()), +    start_of_burst(false), +    end_of_burst(false) +{ +    /* NOP */  }  /***********************************************************************   * time spec   **********************************************************************/ -time_spec_t::time_spec_t(boost::uint32_t secs_, double nsecs_){ -    secs = secs_; -    nsecs = nsecs_; +time_spec_t::time_spec_t(boost::uint32_t secs, double nsecs): +    secs(secs), +    nsecs(nsecs) +{ +    /* NOP */  }  boost::uint32_t time_spec_t::get_ticks(double tick_rate) const{ @@ -165,9 +181,8 @@ std::string device_addr_t::to_string(void) const{  /***********************************************************************   * mac addr   **********************************************************************/ -mac_addr_t::mac_addr_t(const byte_vector_t &bytes){ -    UHD_ASSERT_THROW(bytes.size() == 6); -    _bytes = bytes; +mac_addr_t::mac_addr_t(const byte_vector_t &bytes) : _bytes(bytes){ +    UHD_ASSERT_THROW(_bytes.size() == 6);  }  mac_addr_t mac_addr_t::from_bytes(const byte_vector_t &bytes){ @@ -220,10 +235,16 @@ std::string mac_addr_t::to_string(void) const{  /***********************************************************************   * otw type   **********************************************************************/ -otw_type_t::otw_type_t(void){ -    width = 0; -    shift = 0; -    byteorder = BO_NATIVE; +size_t otw_type_t::get_sample_size(void) const{ +    return (this->width * 2) / 8; +} + +otw_type_t::otw_type_t(void): +    width(0), +    shift(0), +    byteorder(BO_NATIVE) +{ +    /* NOP */  }  /*********************************************************************** @@ -251,9 +272,11 @@ io_type_t::io_type_t(size_t size)  /***********************************************************************   * serial   **********************************************************************/ -spi_config_t::spi_config_t(edge_t edge){ -    mosi_edge = edge; -    miso_edge = edge; +spi_config_t::spi_config_t(edge_t edge): +    mosi_edge(edge), +    miso_edge(edge) +{ +    /* NOP */  }  void i2c_iface::write_eeprom( diff --git a/host/lib/usrp/usrp2/clock_ctrl.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp index db8d8a886..4c5207203 100644 --- a/host/lib/usrp/usrp2/clock_ctrl.cpp +++ b/host/lib/usrp/usrp2/clock_ctrl.cpp @@ -79,7 +79,9 @@ public:          _ad9510_regs.power_down_lvds_cmos_out7 = enb? 0 : 1;          _ad9510_regs.lvds_cmos_select_out7 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT7_CMOS;          _ad9510_regs.output_level_lvds_out7 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT7_1_75MA; +        _ad9510_regs.bypass_divider_out7 = 1;          this->write_reg(0x43); +        this->write_reg(0x57);          this->update_regs();      } @@ -88,7 +90,9 @@ public:          _ad9510_regs.power_down_lvds_cmos_out6 = enb? 0 : 1;          _ad9510_regs.lvds_cmos_select_out6 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT6_CMOS;          _ad9510_regs.output_level_lvds_out6 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT6_1_75MA; +        _ad9510_regs.bypass_divider_out6 = 1;          this->write_reg(0x42); +        this->write_reg(0x55);          this->update_regs();      } @@ -130,7 +134,9 @@ private:              ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_NORMAL :              ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_SAFE_PD;          _ad9510_regs.output_level_lvpecl_out3 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT3_810MV; +        _ad9510_regs.bypass_divider_out3 = 1;          this->write_reg(0x3F); +        this->write_reg(0x4F);          this->update_regs();      } @@ -139,7 +145,9 @@ private:          _ad9510_regs.power_down_lvds_cmos_out4 = enb? 0 : 1;          _ad9510_regs.lvds_cmos_select_out4 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT4_LVDS;          _ad9510_regs.output_level_lvds_out4 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT4_1_75MA; +        _ad9510_regs.bypass_divider_out4 = 1;          this->write_reg(0x40); +        this->write_reg(0x51);          this->update_regs();      } diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 7c9d003ce..b6ab919e7 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -31,16 +31,15 @@ namespace asio = boost::asio;   * 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; +    //setup rx otw type +    _rx_otw_type.width = 16; +    _rx_otw_type.shift = 0; +    _rx_otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; -    //initially empty copy buffer -    _rx_copy_buff = asio::buffer("", 0); - -    //init the expected rx seq number -    _rx_stream_id_to_packet_seq[0] = 0; +    //setup tx otw type +    _tx_otw_type.width = 16; +    _tx_otw_type.shift = 0; +    _tx_otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN;      //send a small data packet so the usrp2 knows the udp source port      managed_send_buffer::sptr send_buff = _data_transport->get_send_buff(); @@ -49,7 +48,8 @@ void usrp2_impl::io_init(void){      send_buff->done(sizeof(data));      //setup RX DSP regs -    _iface->poke32(FR_RX_CTRL_NSAMPS_PER_PKT, _max_rx_samples_per_packet); +    std::cout << "RX samples per packet: " << get_max_recv_samps_per_packet() << std::endl; +    _iface->poke32(FR_RX_CTRL_NSAMPS_PER_PKT, get_max_recv_samps_per_packet());      _iface->poke32(FR_RX_CTRL_NCHANNELS, 1);      _iface->poke32(FR_RX_CTRL_CLEAR_OVERRUN, 1); //reset      _iface->poke32(FR_RX_CTRL_VRT_HEADER, 0 @@ -63,98 +63,22 @@ void usrp2_impl::io_init(void){  }  /*********************************************************************** - * Receive Raw Data - **********************************************************************/ -void usrp2_impl::recv_raw(rx_metadata_t &metadata){ -    //do a receive -    _rx_smart_buff = _data_transport->get_recv_buff(); - -    //unpack the vrt header -    size_t num_packet_words32 = _rx_smart_buff->size()/sizeof(boost::uint32_t); -    if (num_packet_words32 == 0){ -        _rx_copy_buff = boost::asio::buffer("", 0); -        return; //must exit here after setting the buffer -    } -    const boost::uint32_t *vrt_hdr = _rx_smart_buff->cast<const boost::uint32_t *>(); -    size_t num_header_words32_out, num_payload_words32_out, packet_count_out; -    try{ -        vrt::unpack( -            metadata,                //output -            vrt_hdr,                 //input -            num_header_words32_out,  //output -            num_payload_words32_out, //output -            num_packet_words32,      //input -            packet_count_out,        //output -            get_master_clock_freq() -        ); -    }catch(const std::exception &e){ -        std::cerr << "bad vrt header: " << e.what() << std::endl; -        _rx_copy_buff = boost::asio::buffer("", 0); -        return; //must exit here after setting the buffer -    } - -    //handle the packet count / sequence number -    size_t expected_packet_count = _rx_stream_id_to_packet_seq[metadata.stream_id]; -    if (packet_count_out != expected_packet_count){ -        std::cerr << "S" << (packet_count_out - expected_packet_count)%16; -    } -    _rx_stream_id_to_packet_seq[metadata.stream_id] = (packet_count_out+1)%16; - -    //setup the rx buffer to point to the data -    _rx_copy_buff = asio::buffer( -        vrt_hdr + num_header_words32_out, -        num_payload_words32_out*sizeof(boost::uint32_t) -    ); -} - -/***********************************************************************   * Send Data   **********************************************************************/  size_t usrp2_impl::send(      const asio::const_buffer &buff, -    const tx_metadata_t &metadata_, -    const io_type_t &io_type +    const tx_metadata_t &metadata, +    const io_type_t &io_type, +    send_mode_t send_mode  ){ -    tx_metadata_t metadata = metadata_; //rw copy to change later - -    transport::managed_send_buffer::sptr send_buff = _data_transport->get_send_buff(); -    boost::uint32_t *tx_mem = send_buff->cast<boost::uint32_t *>(); -    size_t num_samps = std::min(std::min( -        asio::buffer_size(buff)/io_type.size, -        size_t(_max_tx_samples_per_packet)), -        send_buff->size()/io_type.size +    return vrt_packet_handler::send( +        _packet_handler_send_state, //last state of the send handler +        buff, metadata, send_mode,  //buffer to empty and samples metadata +        io_type, _tx_otw_type,      //input and output types to convert +        get_master_clock_freq(),    //master clock tick rate +        _data_transport,            //zero copy interface +        get_max_send_samps_per_packet()      ); - -    //kill the end of burst flag if this is a fragment -    if (asio::buffer_size(buff)/io_type.size < num_samps) -        metadata.end_of_burst = false; - -    size_t num_header_words32, num_packet_words32; -    size_t packet_count = _tx_stream_id_to_packet_seq[metadata.stream_id]++; - -    //pack metadata into a vrt header -    vrt::pack( -        metadata,            //input -        tx_mem,              //output -        num_header_words32,  //output -        num_samps,           //input -        num_packet_words32,  //output -        packet_count,        //input -        get_master_clock_freq() -    ); - -    boost::uint32_t *items = tx_mem + num_header_words32; //offset for data - -    //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)); -    return num_samps;  }  /*********************************************************************** @@ -163,44 +87,14 @@ size_t usrp2_impl::send(  size_t usrp2_impl::recv(      const asio::mutable_buffer &buff,      rx_metadata_t &metadata, -    const io_type_t &io_type +    const io_type_t &io_type, +    recv_mode_t recv_mode  ){ -    //perform a receive if no rx data is waiting to be copied -    if (asio::buffer_size(_rx_copy_buff) == 0){ -        _fragment_offset_in_samps = 0; -        recv_raw(metadata); -    } -    //otherwise flag the metadata to show that is is a fragment -    else{ -        metadata = rx_metadata_t(); -    } - -    //extract the number of samples available to copy -    //and a pointer into the usrp2 received items memory -    size_t bytes_to_copy = asio::buffer_size(_rx_copy_buff); -    if (bytes_to_copy == 0) return 0; //nothing to receive -    size_t num_samps = std::min( -        asio::buffer_size(buff)/io_type.size, -        bytes_to_copy/sizeof(boost::uint32_t) +    return vrt_packet_handler::recv( +        _packet_handler_recv_state, //last state of the recv handler +        buff, metadata, recv_mode,  //buffer to fill and samples metadata +        io_type, _rx_otw_type,      //input and output types to convert +        get_master_clock_freq(),    //master clock tick rate +        _data_transport             //zero copy interface      ); -    const boost::uint32_t *items = asio::buffer_cast<const boost::uint32_t*>(_rx_copy_buff); - -    //setup the fragment flags and offset -    metadata.more_fragments = asio::buffer_size(buff)/io_type.size < num_samps; -    metadata.fragment_offset = _fragment_offset_in_samps; -    _fragment_offset_in_samps += num_samps; //set for next time - -    //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( -        items + num_samps, bytes_to_copy - num_samps*sizeof(boost::uint32_t) -    ); - -    return num_samps;  } diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 9ae68d158..f17efd88e 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -111,7 +111,7 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){      //issue the stream command      _iface->poke32(FR_RX_CTRL_STREAM_CMD, FR_RX_CTRL_MAKE_CMD( -        (inst_samps)? stream_cmd.num_samps : ((inst_chain)? _max_rx_samples_per_packet : 1), +        (inst_samps)? stream_cmd.num_samps : ((inst_chain)? get_max_recv_samps_per_packet() : 1),          (stream_cmd.stream_now)? 1 : 0,          (inst_chain)? 1 : 0,          (inst_reload)? 1 : 0 diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 2b7bdeea2..af3ec216a 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -210,14 +210,6 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){          val = prop_names_t(1, "");          return; -    case DEVICE_PROP_MAX_RX_SAMPLES: -        val = size_t(_max_rx_samples_per_packet); -        return; - -    case DEVICE_PROP_MAX_TX_SAMPLES: -        val = size_t(_max_tx_samples_per_packet); -        return; -      default: UHD_THROW_PROP_GET_ERROR();      }  } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index c5b6af810..afea9683c 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -33,6 +33,7 @@  #include <uhd/transport/vrt.hpp>  #include <uhd/transport/udp_zero_copy.hpp>  #include <uhd/usrp/dboard_manager.hpp> +#include "../../transport/vrt_packet_handler.hpp"  /*!   * Make a usrp2 dboard interface. @@ -103,8 +104,24 @@ public:      ~usrp2_impl(void);      //the io interface -    size_t send(const boost::asio::const_buffer &, const uhd::tx_metadata_t &, const uhd::io_type_t &); -    size_t recv(const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, const uhd::io_type_t &); +    size_t get_max_send_samps_per_packet(void) const{ +        return _max_tx_bytes_per_packet/_tx_otw_type.get_sample_size(); +    } +    size_t send( +        const boost::asio::const_buffer &, +        const uhd::tx_metadata_t &, +        const uhd::io_type_t &, +        uhd::device::send_mode_t +    ); +    size_t get_max_recv_samps_per_packet(void) const{ +        return _max_rx_bytes_per_packet/_rx_otw_type.get_sample_size(); +    } +    size_t recv( +        const boost::asio::mutable_buffer &, +        uhd::rx_metadata_t &, +        const uhd::io_type_t &, +        uhd::device::recv_mode_t +    );  private:      double get_master_clock_freq(void){ @@ -121,25 +138,24 @@ private:      codec_ctrl::sptr _codec_ctrl;      serdes_ctrl::sptr _serdes_ctrl; -    //the raw io interface (samples are in the usrp2 native format) -    void recv_raw(uhd::rx_metadata_t &); -    uhd::dict<boost::uint32_t, size_t> _tx_stream_id_to_packet_seq; -    uhd::dict<boost::uint32_t, size_t> _rx_stream_id_to_packet_seq; +    /******************************************************************* +     * Deal with the rx and tx packet sizes +     ******************************************************************/      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) -    static const size_t _max_rx_samples_per_packet = -        (_mtu - _hdrs)/sizeof(boost::uint32_t) - -        USRP2_HOST_RX_VRT_HEADER_WORDS32 - -        USRP2_HOST_RX_VRT_TRAILER_WORDS32 +    static const size_t _max_rx_bytes_per_packet = +        _mtu - _hdrs - +        USRP2_HOST_RX_VRT_HEADER_WORDS32*sizeof(boost::uint32_t) - +        USRP2_HOST_RX_VRT_TRAILER_WORDS32*sizeof(boost::uint32_t)      ; -    static const size_t _max_tx_samples_per_packet = -        (_mtu - _hdrs)/sizeof(boost::uint32_t) - -        uhd::transport::vrt::max_header_words32 +    static const size_t _max_tx_bytes_per_packet = +        _mtu - _hdrs - +        uhd::transport::vrt::max_header_words32*sizeof(boost::uint32_t)      ; -    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; + +    vrt_packet_handler::recv_state _packet_handler_recv_state; +    vrt_packet_handler::send_state _packet_handler_send_state; +    uhd::otw_type_t _rx_otw_type, _tx_otw_type;      void io_init(void);      //udp transports for control and data | 
