diff options
| author | Josh Blum <josh@joshknows.com> | 2010-09-23 18:56:12 -0700 | 
|---|---|---|
| committer | Josh Blum <josh@joshknows.com> | 2010-09-23 18:56:12 -0700 | 
| commit | 5fc96b27b9493506bd7ad60eb37f98f651de6545 (patch) | |
| tree | b181775e041c3d78c641feb4080165fe96a198f4 | |
| parent | 1826421cd428f795b4b8cd0acdad4fea92262f72 (diff) | |
| parent | ea82d5fe9a9cde24409c528160e6ba6f3bced41b (diff) | |
| download | uhd-5fc96b27b9493506bd7ad60eb37f98f651de6545.tar.gz uhd-5fc96b27b9493506bd7ad60eb37f98f651de6545.tar.bz2 uhd-5fc96b27b9493506bd7ad60eb37f98f651de6545.zip | |
Merge branch 'xusrp'
30 files changed, 1049 insertions, 567 deletions
| diff --git a/host/docs/coding.rst b/host/docs/coding.rst index 23f350b0f..d6a19d250 100644 --- a/host/docs/coding.rst +++ b/host/docs/coding.rst @@ -23,11 +23,11 @@ The device API provides ways to:  See the documentation in *device.hpp* for reference.  ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -High-Level: The simple usrp +High-Level: The single usrp  ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The goal of the simple usrp API is to wrap high level functions around the device properties. -The simple usrp provides a fat interface to access the most common properties. -The simple usrp provides ways to: +The goal of the single usrp API is to wrap high level functions around the device properties. +The single usrp provides a fat interface to access the most common properties. +The single usrp provides ways to:  * Set and get daughterboard gains.  * Set and get daughterboard antennas. @@ -38,13 +38,13 @@ The simple usrp provides ways to:  * Set the usrp time registers.  * Get the underlying device (as discussed above). -See the documentation in *usrp/simple_usrp.hpp* for reference. +See the documentation in *usrp/single_usrp.hpp* for reference.  ^^^^^^^^^^^^^^^^^^^^^^^^^^^  High-Level: The mimo usrp  ^^^^^^^^^^^^^^^^^^^^^^^^^^^  The mimo usrp API provides a wrapper around a device that represents several motherboards. -This API provides convenience calls just like the simple usrp, +This API provides convenience calls just like the single usrp,  however the calls either work across all channels in the configuration,  or take a channel argument to specify which channel to configure.  The mimo usrp provides ways to: diff --git a/host/docs/dboards.rst b/host/docs/dboards.rst index 985fbc12b..738a0696d 100644 --- a/host/docs/dboards.rst +++ b/host/docs/dboards.rst @@ -15,11 +15,12 @@ properties of each board as well.  ^^^^^^^^^^^^^^^^^^^^^^^^^^^  Basic RX and and LFRX  ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The Basic RX and LFRX boards have 3 subdevices: +The Basic RX and LFRX boards have 4 subdevices:  * **Subdevice A:** real signal on antenna RXA  * **Subdevice B:** real signal on antenna RXB -* **Subdevice AB:** quadrature subdevice using both antennas +* **Subdevice AB:** quadrature subdevice using both antennas (IQ) +* **Subdevice BA:** quadrature subdevice using both antennas (QI)  The boards have no tunable elements or programmable gains.  Though the magic of aliasing, you can down-convert signals @@ -28,11 +29,12 @@ greater than the Nyquist rate of the ADC.  ^^^^^^^^^^^^^^^^^^^^^^^^^^^  Basic TX and and LFTX  ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The Basic TX and LFTX boards have 3 subdevices: +The Basic TX and LFTX boards have 4 subdevices:  * **Subdevice A:** real signal on antenna TXA  * **Subdevice B:** real signal on antenna TXB -* **Subdevice AB:** quadrature subdevice using both antennas +* **Subdevice AB:** quadrature subdevice using both antennas (IQ) +* **Subdevice BA:** quadrature subdevice using both antennas (QI)  The boards have no tunable elements or programmable gains.  Though the magic of aliasing, you can up-convert signals diff --git a/host/examples/benchmark_rx_rate.cpp b/host/examples/benchmark_rx_rate.cpp index 8fae813cf..36611f97f 100644 --- a/host/examples/benchmark_rx_rate.cpp +++ b/host/examples/benchmark_rx_rate.cpp @@ -17,7 +17,7 @@  #include <uhd/utils/thread_priority.hpp>  #include <uhd/utils/safe_main.hpp> -#include <uhd/usrp/simple_usrp.hpp> +#include <uhd/usrp/single_usrp.hpp>  #include <boost/math/special_functions/round.hpp>  #include <boost/program_options.hpp>  #include <boost/format.hpp> @@ -27,7 +27,7 @@  namespace po = boost::program_options;  static inline void test_device( -    uhd::usrp::simple_usrp::sptr sdev, +    uhd::usrp::single_usrp::sptr sdev,      double rx_rate_sps,      double duration_secs  ){ @@ -118,7 +118,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      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") +        ("args", po::value<std::string>(&args)->default_value(""), "single uhd device address args")          ("duration", po::value<double>(&duration)->default_value(10.0), "duration for each test in seconds")          ("rate", po::value<double>(&only_rate), "specify to perform a single test as this rate (sps)")      ; @@ -135,7 +135,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      //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::usrp::single_usrp::sptr sdev = uhd::usrp::single_usrp::make(args);      std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl;      sdev->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); //stop if left running diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp index 4856f6779..441665900 100644 --- a/host/examples/rx_timed_samples.cpp +++ b/host/examples/rx_timed_samples.cpp @@ -17,7 +17,7 @@  #include <uhd/utils/thread_priority.hpp>  #include <uhd/utils/safe_main.hpp> -#include <uhd/usrp/simple_usrp.hpp> +#include <uhd/usrp/single_usrp.hpp>  #include <boost/program_options.hpp>  #include <boost/format.hpp>  #include <iostream> @@ -38,7 +38,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      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") +        ("args", po::value<std::string>(&args)->default_value(""), "single uhd device address args")          ("secs", po::value<time_t>(&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") @@ -60,7 +60,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      //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::usrp::single_usrp::sptr sdev = uhd::usrp::single_usrp::make(args);      uhd::device::sptr dev = sdev->get_device();      std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl; diff --git a/host/examples/test_async_messages.cpp b/host/examples/test_async_messages.cpp index e02bc5f40..4c9d18121 100644 --- a/host/examples/test_async_messages.cpp +++ b/host/examples/test_async_messages.cpp @@ -18,7 +18,7 @@  #include <uhd/utils/thread_priority.hpp>  #include <uhd/utils/safe_main.hpp>  #include <uhd/utils/static.hpp> -#include <uhd/usrp/simple_usrp.hpp> +#include <uhd/usrp/single_usrp.hpp>  #include <boost/program_options.hpp>  #include <boost/format.hpp>  #include <complex> @@ -33,7 +33,7 @@ static const size_t async_to_ms = 100;   *    Send a burst of many samples that will fragment internally.   *    We expect to not get any async messages.   */ -void test_no_async_message(uhd::usrp::simple_usrp::sptr sdev){ +void test_no_async_message(uhd::usrp::single_usrp::sptr sdev){      uhd::device::sptr dev = sdev->get_device();      std::cout << "Test no async message... " << std::flush; @@ -73,7 +73,7 @@ void test_no_async_message(uhd::usrp::simple_usrp::sptr sdev){   *    Send a start of burst packet with no following end of burst.   *    We expect to get an underflow(within a burst) async message.   */ -void test_underflow_message(uhd::usrp::simple_usrp::sptr sdev){ +void test_underflow_message(uhd::usrp::single_usrp::sptr sdev){      uhd::device::sptr dev = sdev->get_device();      std::cout << "Test underflow message... " << std::flush; @@ -117,7 +117,7 @@ void test_underflow_message(uhd::usrp::simple_usrp::sptr sdev){   *    Send a burst packet that occurs at a time in the past.   *    We expect to get a time error async message.   */ -void test_time_error_message(uhd::usrp::simple_usrp::sptr sdev){ +void test_time_error_message(uhd::usrp::single_usrp::sptr sdev){      uhd::device::sptr dev = sdev->get_device();      std::cout << "Test time error message... " << std::flush; @@ -170,7 +170,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      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") +        ("args", po::value<std::string>(&args)->default_value(""), "single uhd device address args")          ("rate", po::value<double>(&rate)->default_value(1.5e6), "rate of outgoing samples")      ;      po::variables_map vm; @@ -186,7 +186,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      //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::usrp::single_usrp::sptr sdev = uhd::usrp::single_usrp::make(args);      std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl;      //set the tx sample rate diff --git a/host/examples/test_pps_input.cpp b/host/examples/test_pps_input.cpp index e01d32910..d1b49d320 100644 --- a/host/examples/test_pps_input.cpp +++ b/host/examples/test_pps_input.cpp @@ -17,7 +17,7 @@  #include <uhd/utils/thread_priority.hpp>  #include <uhd/utils/safe_main.hpp> -#include <uhd/usrp/simple_usrp.hpp> +#include <uhd/usrp/single_usrp.hpp>  #include <boost/program_options.hpp>  #include <boost/format.hpp>  #include <boost/thread.hpp> @@ -37,7 +37,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      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") +        ("args", po::value<std::string>(&args)->default_value(""), "single uhd device address args")      ;      po::variables_map vm;      po::store(po::parse_command_line(argc, argv, desc), vm); @@ -52,7 +52,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      //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::usrp::single_usrp::sptr sdev = uhd::usrp::single_usrp::make(args);      uhd::device::sptr dev = sdev->get_device();      std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl; diff --git a/host/examples/tx_timed_samples.cpp b/host/examples/tx_timed_samples.cpp index 5b72bd72f..f34c121d5 100644 --- a/host/examples/tx_timed_samples.cpp +++ b/host/examples/tx_timed_samples.cpp @@ -17,7 +17,7 @@  #include <uhd/utils/thread_priority.hpp>  #include <uhd/utils/safe_main.hpp> -#include <uhd/usrp/simple_usrp.hpp> +#include <uhd/usrp/single_usrp.hpp>  #include <boost/program_options.hpp>  #include <boost/format.hpp>  #include <iostream> @@ -40,7 +40,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      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") +        ("args", po::value<std::string>(&args)->default_value(""), "single uhd device address args")          ("secs", po::value<time_t>(&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")          ("spp", po::value<size_t>(&samps_per_packet)->default_value(1000), "number of samples per packet") @@ -64,7 +64,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      //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::usrp::single_usrp::sptr sdev = uhd::usrp::single_usrp::make(args);      uhd::device::sptr dev = sdev->get_device();      std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl; diff --git a/host/examples/tx_waveforms.cpp b/host/examples/tx_waveforms.cpp index 3f319cf68..50982cf88 100644 --- a/host/examples/tx_waveforms.cpp +++ b/host/examples/tx_waveforms.cpp @@ -18,7 +18,7 @@  #include <uhd/utils/thread_priority.hpp>  #include <uhd/utils/safe_main.hpp>  #include <uhd/utils/static.hpp> -#include <uhd/usrp/simple_usrp.hpp> +#include <uhd/usrp/single_usrp.hpp>  #include <boost/program_options.hpp>  #include <boost/thread/thread_time.hpp> //system time  #include <boost/math/special_functions/round.hpp> @@ -70,7 +70,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      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") +        ("args", po::value<std::string>(&args)->default_value(""), "single uhd device address args")          ("duration", po::value<size_t>(&total_duration)->default_value(3), "number of seconds to transmit")          ("spb", po::value<size_t>(&spb)->default_value(10000), "samples per buffer")          ("rate", po::value<double>(&rate)->default_value(1.5e6), "rate of outgoing samples") @@ -93,7 +93,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      //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::usrp::single_usrp::sptr sdev = uhd::usrp::single_usrp::make(args);      uhd::device::sptr dev = sdev->get_device();      std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl; diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index c48b3dfff..2077cae62 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -26,7 +26,6 @@  #include <boost/utility.hpp>  #include <boost/shared_ptr.hpp>  #include <boost/function.hpp> -#include <boost/asio/buffer.hpp>  #include <vector>  namespace uhd{ @@ -140,12 +139,6 @@ public:          send_mode_t send_mode      ); -    //! Deprecated -    size_t send( -        const boost::asio::const_buffer &, const tx_metadata_t &, -        const io_type_t &, send_mode_t send_mode -    ); -      /*!       * Receive buffers containing IF data described by the metadata.       * @@ -196,12 +189,6 @@ public:          size_t timeout_ms = default_recv_timeout_ms      ); -    //! Deprecated -    size_t recv( -        const boost::asio::mutable_buffer &, rx_metadata_t &, -        const io_type_t &, recv_mode_t -    ); -      /*!       * Get the maximum number of samples per packet on send.       * \return the number of samples diff --git a/host/include/uhd/device.ipp b/host/include/uhd/device.ipp index 603c52859..60a3f535d 100644 --- a/host/include/uhd/device.ipp +++ b/host/include/uhd/device.ipp @@ -34,19 +34,6 @@ namespace uhd{          );      } -    UHD_DEPRECATED UHD_INLINE size_t device::send( -        const boost::asio::const_buffer &buff, -        const tx_metadata_t &metadata, -        const io_type_t &io_type, -        send_mode_t send_mode -    ){ -        return this->send( -            boost::asio::buffer_cast<const void *>(buff), -            boost::asio::buffer_size(buff)/io_type.size, -            metadata, io_type, send_mode -        ); -    } -      UHD_INLINE size_t device::recv(          void *buff,          size_t nsamps_per_buff, @@ -62,19 +49,6 @@ namespace uhd{          );      } -    UHD_DEPRECATED UHD_INLINE size_t device::recv( -        const boost::asio::mutable_buffer &buff, -        rx_metadata_t &metadata, -        const io_type_t &io_type, -        recv_mode_t recv_mode -    ){ -        return this->recv( -            boost::asio::buffer_cast<void *>(buff), -            boost::asio::buffer_size(buff)/io_type.size, -            metadata, io_type, recv_mode -        ); -    } -  } //namespace uhd  #endif /* INCLUDED_UHD_DEVICE_IPP */ diff --git a/host/include/uhd/usrp/CMakeLists.txt b/host/include/uhd/usrp/CMakeLists.txt index 130956f8a..f973e401a 100644 --- a/host/include/uhd/usrp/CMakeLists.txt +++ b/host/include/uhd/usrp/CMakeLists.txt @@ -40,6 +40,7 @@ INSTALL(FILES      ### interfaces ###      simple_usrp.hpp +    single_usrp.hpp      mimo_usrp.hpp      DESTINATION ${INCLUDE_DIR}/uhd/usrp diff --git a/host/include/uhd/usrp/dsp_props.hpp b/host/include/uhd/usrp/dsp_props.hpp index 75d8c0a60..54ea5666b 100644 --- a/host/include/uhd/usrp/dsp_props.hpp +++ b/host/include/uhd/usrp/dsp_props.hpp @@ -37,11 +37,12 @@ namespace uhd{ namespace usrp{       *   Set the shift property and read it back to get actual shift.       */      enum dsp_prop_t{ -        DSP_PROP_NAME         = 'n', //ro, std::string -        DSP_PROP_OTHERS       = 'o', //ro, prop_names_t -        DSP_PROP_FREQ_SHIFT   = 'f', //rw, double Hz -        DSP_PROP_CODEC_RATE   = 'c', //ro, double Sps -        DSP_PROP_HOST_RATE    = 'h'  //rw, double Sps +        DSP_PROP_NAME              = 'n', //ro, std::string +        DSP_PROP_OTHERS            = 'o', //ro, prop_names_t +        DSP_PROP_FREQ_SHIFT        = 'f', //rw, double Hz +        DSP_PROP_FREQ_SHIFT_NAMES  = 'F', //ro, prop_names_t +        DSP_PROP_CODEC_RATE        = 'c', //ro, double Sps +        DSP_PROP_HOST_RATE         = 'h'  //rw, double Sps      };  }} //namespace diff --git a/host/include/uhd/usrp/simple_usrp.hpp b/host/include/uhd/usrp/simple_usrp.hpp index 08b9c01ea..6149f739c 100644 --- a/host/include/uhd/usrp/simple_usrp.hpp +++ b/host/include/uhd/usrp/simple_usrp.hpp @@ -33,12 +33,13 @@  namespace uhd{ namespace usrp{  /*! - * The simple USRP device class: + * The simple USRP device class (DEPRECATED): + * This interface has been deprecated in favor of the single USRP interface.   * A simple usrp facilitates ease-of-use for most use-case scenarios.   * The wrapper provides convenience functions to tune the devices   * as well as to set the dboard gains, antennas, and other properties.   */ -class UHD_API simple_usrp : boost::noncopyable{ +class UHD_API UHD_DEPRECATED simple_usrp : boost::noncopyable{  public:      typedef boost::shared_ptr<simple_usrp> sptr; diff --git a/host/include/uhd/usrp/single_usrp.hpp b/host/include/uhd/usrp/single_usrp.hpp new file mode 100644 index 000000000..1b89a3620 --- /dev/null +++ b/host/include/uhd/usrp/single_usrp.hpp @@ -0,0 +1,172 @@ +// +// 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_UHD_USRP_SINGLE_USRP_HPP +#define INCLUDED_UHD_USRP_SINGLE_USRP_HPP + +#include <uhd/config.hpp> +#include <uhd/device.hpp> +#include <uhd/types/ranges.hpp> +#include <uhd/types/stream_cmd.hpp> +#include <uhd/types/clock_config.hpp> +#include <uhd/types/tune_result.hpp> +#include <uhd/usrp/subdev_spec.hpp> +#include <uhd/usrp/dboard_iface.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/utility.hpp> +#include <vector> + +namespace uhd{ namespace usrp{ + +/*! + * The single USRP device class: + * A single usrp facilitates ease-of-use for most use-case scenarios. + * The wrapper provides convenience functions to tune the devices + * as well as to set the dboard gains, antennas, and other properties. + * This wrapper supports multi-channel configurations per motherboard. + */ +class UHD_API single_usrp : boost::noncopyable{ +public: +    typedef boost::shared_ptr<single_usrp> sptr; + +    /*! +     * Make a new single usrp from the device address. +     * \param dev_addr the device address +     * \return a new single usrp object +     */ +    static sptr make(const device_addr_t &dev_addr); + +    /*! +     * Get the underlying device object. +     * This is needed to get access to the streaming API and properties. +     * \return the device object within this single usrp +     */ +    virtual device::sptr get_device(void) = 0; + +    /*! +     * Get a printable name for this usrp. +     * \return a printable string +     */ +    virtual std::string get_pp_string(void) = 0; + +    /******************************************************************* +     * Misc +     ******************************************************************/ +    /*! +     * Gets the current time in the usrp time registers. +     * \return a timespec representing current usrp time +     */ +    virtual time_spec_t get_time_now(void) = 0; + +    /*! +     * Sets the time registers on the usrp immediately. +     * \param time_spec the time to latch into the usrp device +     */ +    virtual void set_time_now(const time_spec_t &time_spec) = 0; + +    /*! +     * Set the time registers on the usrp at the next pps tick. +     * The values will not be latched in until the pulse occurs. +     * It is recommended that the user sleep(1) after calling to ensure +     * that the time registers will be in a known state prior to use. +     * +     * Note: Because this call sets the time on the "next" pps, +     * the seconds in the time spec should be current seconds + 1. +     * +     * \param time_spec the time to latch into the usrp device +     */ +    virtual void set_time_next_pps(const time_spec_t &time_spec) = 0; + +    /*! +     * Issue a stream command to the usrp device. +     * This tells the usrp to send samples into the host. +     * See the documentation for stream_cmd_t for more info. +     * \param stream_cmd the stream command to issue +     */ +    virtual void issue_stream_cmd(const stream_cmd_t &stream_cmd) = 0; + +    /*! +     * Set the clock configuration for the usrp device. +     * This tells the usrp how to get a 10Mhz reference and PPS clock. +     * See the documentation for clock_config_t for more info. +     * \param clock_config the clock configuration to set +     */ +    virtual void set_clock_config(const clock_config_t &clock_config) = 0; + +    /******************************************************************* +     * RX methods +     ******************************************************************/ +    virtual void set_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec) = 0; +    virtual uhd::usrp::subdev_spec_t get_rx_subdev_spec(void) = 0; + +    virtual void set_rx_rate(double rate) = 0; +    virtual double get_rx_rate(void) = 0; + +    virtual tune_result_t set_rx_freq(double freq, size_t chan = 0) = 0; +    virtual tune_result_t set_rx_freq(double freq, double lo_off, size_t chan = 0) = 0; +    virtual double get_rx_freq(size_t chan = 0) = 0; +    virtual freq_range_t get_rx_freq_range(size_t chan = 0) = 0; + +    virtual void set_rx_gain(float gain, size_t chan = 0) = 0; +    virtual float get_rx_gain(size_t chan = 0) = 0; +    virtual gain_range_t get_rx_gain_range(size_t chan = 0) = 0; + +    virtual void set_rx_antenna(const std::string &ant, size_t chan = 0) = 0; +    virtual std::string get_rx_antenna(size_t chan = 0) = 0; +    virtual std::vector<std::string> get_rx_antennas(size_t chan = 0) = 0; + +    virtual bool get_rx_lo_locked(size_t chan = 0) = 0; + +    /*! +     * Read the RSSI value from a usrp device. +     * Or throw if the dboard does not support an RSSI readback. +     * \return the rssi in dB +     */ +    virtual float read_rssi(size_t chan = 0) = 0; + +    virtual dboard_iface::sptr get_rx_dboard_iface(size_t chan = 0) = 0; + +    /******************************************************************* +     * TX methods +     ******************************************************************/ +    virtual void set_tx_subdev_spec(const uhd::usrp::subdev_spec_t &spec) = 0; +    virtual uhd::usrp::subdev_spec_t get_tx_subdev_spec(void) = 0; + +    virtual void set_tx_rate(double rate) = 0; +    virtual double get_tx_rate(void) = 0; + +    virtual tune_result_t set_tx_freq(double freq, size_t chan = 0) = 0; +    virtual tune_result_t set_tx_freq(double freq, double lo_off, size_t chan = 0) = 0; +    virtual double get_tx_freq(size_t chan = 0) = 0; +    virtual freq_range_t get_tx_freq_range(size_t chan = 0) = 0; + +    virtual void set_tx_gain(float gain, size_t chan = 0) = 0; +    virtual float get_tx_gain(size_t chan = 0) = 0; +    virtual gain_range_t get_tx_gain_range(size_t chan = 0) = 0; + +    virtual void set_tx_antenna(const std::string &ant, size_t chan = 0) = 0; +    virtual std::string get_tx_antenna(size_t chan = 0) = 0; +    virtual std::vector<std::string> get_tx_antennas(size_t chan = 0) = 0; + +    virtual bool get_tx_lo_locked(size_t chan = 0) = 0; + +    virtual dboard_iface::sptr get_tx_dboard_iface(size_t chan = 0) = 0; +}; + +}} + +#endif /* INCLUDED_UHD_USRP_SINGLE_USRP_HPP */ diff --git a/host/include/uhd/usrp/tune_helper.hpp b/host/include/uhd/usrp/tune_helper.hpp index df3907b3e..ec133fa08 100644 --- a/host/include/uhd/usrp/tune_helper.hpp +++ b/host/include/uhd/usrp/tune_helper.hpp @@ -31,12 +31,13 @@ namespace uhd{ namespace usrp{       * The ddc cordic is setup to bring the IF down to baseband.       * \param subdev the dboard subdevice object with properties       * \param ddc the mboard dsp object with properties +     * \param chan the channel of the dsp to tune       * \param target_freq the desired center frequency       * \param lo_offset an offset for the subdevice IF from center       * \return a tune result struct       */      UHD_API tune_result_t tune_rx_subdev_and_dsp( -        wax::obj subdev, wax::obj ddc, +        wax::obj subdev, wax::obj ddc, size_t chan,          double target_freq, double lo_offset      ); @@ -46,17 +47,19 @@ namespace uhd{ namespace usrp{       * is calculated based on the subdevice and BW.       */      UHD_API tune_result_t tune_rx_subdev_and_dsp( -        wax::obj subdev, wax::obj ddc, double target_freq +        wax::obj subdev, wax::obj ddc, +        size_t chan, double target_freq      );      /*!       * Calculate the overall frequency from the combination of dboard IF and DDC shift.       * \param subdev the dboard subdevice object with properties       * \param ddc the mboard dsp object with properties +     * \param chan the channel of the dsp to tune       * \return the overall tune frequency of the system in Hz       */      UHD_API double derive_freq_from_rx_subdev_and_dsp( -        wax::obj subdev, wax::obj ddc +        wax::obj subdev, wax::obj ddc, size_t chan      );      /*! @@ -66,12 +69,13 @@ namespace uhd{ namespace usrp{       * The duc cordic is setup to bring the baseband up to IF.       * \param subdev the dboard subdevice object with properties       * \param duc the mboard dsp object with properties +     * \param chan the channel of the dsp to tune       * \param target_freq the desired center frequency       * \param lo_offset an offset for the subdevice IF from center       * \return a tune result struct       */      UHD_API tune_result_t tune_tx_subdev_and_dsp( -        wax::obj subdev, wax::obj duc, +        wax::obj subdev, wax::obj duc, size_t chan,          double target_freq, double lo_offset      ); @@ -81,17 +85,19 @@ namespace uhd{ namespace usrp{       * is calculated based on the subdevice and BW.       */      UHD_API tune_result_t tune_tx_subdev_and_dsp( -        wax::obj subdev, wax::obj duc, double target_freq +        wax::obj subdev, wax::obj duc, +        size_t chan, double target_freq      );      /*!       * Calculate the overall frequency from the combination of dboard IF and DUC shift.       * \param subdev the dboard subdevice object with properties       * \param duc the mboard dsp object with properties +     * \param chan the channel of the dsp to tune       * \return the overall tune frequency of the system in Hz       */      UHD_API double derive_freq_from_tx_subdev_and_dsp( -        wax::obj subdev, wax::obj duc +        wax::obj subdev, wax::obj duc, size_t chan      );  }} diff --git a/host/lib/transport/gen_convert_types.py b/host/lib/transport/gen_convert_types.py index adbd22868..f9509c81d 100755 --- a/host/lib/transport/gen_convert_types.py +++ b/host/lib/transport/gen_convert_types.py @@ -99,9 +99,9 @@ void transport::convert_io_type_to_otw_type(              nsamps_per_io_buff          );          #else -        for (size_t i = 0; i < nsamps_per_io_buff; i++){ +        for (size_t i = 0, j = 0; i < nsamps_per_io_buff; i++){              #for $j in range($num_chans) -            reinterpret_cast<$(out_type)_t *>(otw_buff)[i*$num_chans + $j] = +            reinterpret_cast<$(out_type)_t *>(otw_buff)[j++] =                  #if $ph.get_swap_type($pred) == 'bswap'                  uhd::byteswap($(converter)(reinterpret_cast<const $(in_type)_t *>(io_buffs[$j])[i]));                  #else @@ -139,13 +139,13 @@ void transport::convert_otw_type_to_io_type(              nsamps_per_io_buff          );          #else -        for (size_t i = 0; i < nsamps_per_io_buff; i++){ +        for (size_t i = 0, j = 0; i < nsamps_per_io_buff; i++){              #for $j in range($num_chans)              reinterpret_cast<$(out_type)_t *>(io_buffs[$j])[i] =                  #if $ph.get_swap_type($pred) == 'bswap' -                $(converter)(uhd::byteswap(reinterpret_cast<const $(in_type)_t *>(otw_buff)[i*$num_chans + $j])); +                $(converter)(uhd::byteswap(reinterpret_cast<const $(in_type)_t *>(otw_buff)[j++]));                  #else -                $(converter)(reinterpret_cast<const $(in_type)_t *>(otw_buff)[i*$num_chans + $j]); +                $(converter)(reinterpret_cast<const $(in_type)_t *>(otw_buff)[j++]);                  #end if              #end for          } diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 7e0588f03..b603f1371 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -150,7 +150,8 @@ template <typename T> UHD_INLINE T get_context_code(          const vrt_unpacker_t &vrt_unpacker,          const get_recv_buffs_t &get_recv_buffs,          const handle_overflow_t &handle_overflow, -        size_t vrt_header_offset_words32 +        size_t vrt_header_offset_words32, +        size_t chans_per_otw_buff      ){          metadata.error_code = uhd::rx_metadata_t::ERROR_CODE_NONE; @@ -184,15 +185,21 @@ template <typename T> UHD_INLINE T get_context_code(          //extract the number of samples available to copy          size_t bytes_per_item = otw_type.get_sample_size();          size_t nsamps_available = state.size_of_copy_buffs/bytes_per_item; -        size_t nsamps_to_copy = std::min(total_samps, nsamps_available); +        size_t nsamps_to_copy = std::min(total_samps*chans_per_otw_buff, nsamps_available);          size_t bytes_to_copy = nsamps_to_copy*bytes_per_item; +        size_t nsamps_to_copy_per_io_buff = nsamps_to_copy/chans_per_otw_buff; + +        std::vector<void *> io_buffs(chans_per_otw_buff); +        for (size_t i = 0; i < state.width; i+=chans_per_otw_buff){ + +            //fill a vector with pointers to the io buffers +            for (size_t j = 0; j < chans_per_otw_buff; j++){ +                io_buffs[j] = reinterpret_cast<boost::uint8_t *>(buffs[i+j]) + offset_bytes; +            } -        for (size_t i = 0; i < state.width; i++){              //copy-convert the samples from the recv buffer              uhd::transport::convert_otw_type_to_io_type( -                state.copy_buffs[i], otw_type, -                reinterpret_cast<boost::uint8_t *>(buffs[i]) + offset_bytes, -                io_type, nsamps_to_copy +                state.copy_buffs[i], otw_type, io_buffs, io_type, nsamps_to_copy_per_io_buff              );              //update the rx copy buffer to reflect the bytes copied @@ -206,7 +213,7 @@ template <typename T> UHD_INLINE T get_context_code(          metadata.fragment_offset = state.fragment_offset_in_samps;          state.fragment_offset_in_samps += nsamps_to_copy; //set for next call -        return nsamps_to_copy; +        return nsamps_to_copy_per_io_buff;      }      /******************************************************************* @@ -224,7 +231,8 @@ template <typename T> UHD_INLINE T get_context_code(          const vrt_unpacker_t &vrt_unpacker,          const get_recv_buffs_t &get_recv_buffs,          const handle_overflow_t &handle_overflow = &handle_overflow_nop, -        size_t vrt_header_offset_words32 = 0 +        size_t vrt_header_offset_words32 = 0, +        size_t chans_per_otw_buff = 1      ){          switch(recv_mode){ @@ -241,7 +249,8 @@ template <typename T> UHD_INLINE T get_context_code(                  vrt_unpacker,                  get_recv_buffs,                  handle_overflow, -                vrt_header_offset_words32 +                vrt_header_offset_words32, +                chans_per_otw_buff              );          } @@ -261,7 +270,8 @@ template <typename T> UHD_INLINE T get_context_code(                      vrt_unpacker,                      get_recv_buffs,                      handle_overflow, -                    vrt_header_offset_words32 +                    vrt_header_offset_words32, +                    chans_per_otw_buff                  );                  if (num_samps == 0) break; //had a recv timeout or error, break loop                  accum_num_samps += num_samps; @@ -303,29 +313,32 @@ template <typename T> UHD_INLINE T get_context_code(          const uhd::otw_type_t &otw_type,          const vrt_packer_t &vrt_packer,          const get_send_buffs_t &get_send_buffs, -        size_t vrt_header_offset_words32 +        size_t vrt_header_offset_words32, +        size_t chans_per_otw_buff      ){          //load the rest of the if_packet_info in here -        if_packet_info.num_payload_words32 = (num_samps*otw_type.get_sample_size())/sizeof(boost::uint32_t); +        if_packet_info.num_payload_words32 = (num_samps*chans_per_otw_buff*otw_type.get_sample_size())/sizeof(boost::uint32_t);          if_packet_info.packet_count = state.next_packet_seq++;          //get send buffers for each channel -        managed_send_buffs_t send_buffs(buffs.size()); +        managed_send_buffs_t send_buffs(buffs.size()/chans_per_otw_buff);          UHD_ASSERT_THROW(get_send_buffs(send_buffs)); -        for (size_t i = 0; i < buffs.size(); i++){ +        std::vector<const void *> io_buffs(chans_per_otw_buff); +        for (size_t i = 0; i < buffs.size(); i+=chans_per_otw_buff){              //calculate pointers with offsets to io and otw memory -            const boost::uint8_t *io_mem = reinterpret_cast<const boost::uint8_t *>(buffs[i]) + offset_bytes; +            for (size_t j = 0; j < chans_per_otw_buff; j++){ +                io_buffs[j] = reinterpret_cast<const boost::uint8_t *>(buffs[i+j]) + offset_bytes; +            }              boost::uint32_t *otw_mem = send_buffs[i]->cast<boost::uint32_t *>() + vrt_header_offset_words32;              //pack metadata into a vrt header              vrt_packer(otw_mem, if_packet_info); +            otw_mem += if_packet_info.num_header_words32;              //copy-convert the samples into the send buffer              uhd::transport::convert_io_type_to_otw_type( -                io_mem, io_type, -                otw_mem + if_packet_info.num_header_words32, otw_type, -                num_samps +                io_buffs, io_type, otw_mem, otw_type, num_samps              );              //commit the samples to the zero-copy interface @@ -351,7 +364,8 @@ template <typename T> UHD_INLINE T get_context_code(          const vrt_packer_t &vrt_packer,          const get_send_buffs_t &get_send_buffs,          size_t max_samples_per_packet, -        size_t vrt_header_offset_words32 = 0 +        size_t vrt_header_offset_words32 = 0, +        size_t chans_per_otw_buff = 1      ){          //translate the metadata to vrt if packet info          uhd::transport::vrt::if_packet_info_t if_packet_info; @@ -383,7 +397,8 @@ template <typename T> UHD_INLINE T get_context_code(                  io_type, otw_type,                  vrt_packer,                  get_send_buffs, -                vrt_header_offset_words32 +                vrt_header_offset_words32, +                chans_per_otw_buff              );              return num_samps;          } @@ -414,7 +429,8 @@ template <typename T> UHD_INLINE T get_context_code(                      io_type, otw_type,                      vrt_packer,                      get_send_buffs, -                    vrt_header_offset_words32 +                    vrt_header_offset_words32, +                    chans_per_otw_buff                  );              }              return total_num_samps; diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt index b5c545988..69a190bfa 100644 --- a/host/lib/usrp/CMakeLists.txt +++ b/host/lib/usrp/CMakeLists.txt @@ -26,6 +26,7 @@ LIBUHD_APPEND_SOURCES(      ${CMAKE_SOURCE_DIR}/lib/usrp/mimo_usrp.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/misc_utils.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/simple_usrp.cpp +    ${CMAKE_SOURCE_DIR}/lib/usrp/single_usrp.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/subdev_spec.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/tune_helper.cpp  ) diff --git a/host/lib/usrp/dboard/db_basic_and_lf.cpp b/host/lib/usrp/dboard/db_basic_and_lf.cpp index 2a9bf2ca5..4b0d8bf27 100644 --- a/host/lib/usrp/dboard/db_basic_and_lf.cpp +++ b/host/lib/usrp/dboard/db_basic_and_lf.cpp @@ -59,6 +59,7 @@ private:  static const uhd::dict<std::string, subdev_conn_t> sd_name_to_conn = map_list_of      ("AB", SUBDEV_CONN_COMPLEX_IQ) +    ("BA", SUBDEV_CONN_COMPLEX_QI)      ("A",  SUBDEV_CONN_REAL_I)      ("B",  SUBDEV_CONN_REAL_Q)  ; diff --git a/host/lib/usrp/mimo_usrp.cpp b/host/lib/usrp/mimo_usrp.cpp index e78d38fc0..9331c7fbb 100644 --- a/host/lib/usrp/mimo_usrp.cpp +++ b/host/lib/usrp/mimo_usrp.cpp @@ -179,15 +179,15 @@ public:      }      tune_result_t set_rx_freq(size_t chan, double target_freq){ -        return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), target_freq); +        return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), 0, target_freq);      }      tune_result_t set_rx_freq(size_t chan, double target_freq, double lo_off){ -        return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), target_freq, lo_off); +        return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), 0, target_freq, lo_off);      }      double get_rx_freq(size_t chan){ -        return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan)); +        return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), 0);      }      freq_range_t get_rx_freq_range(size_t chan){ @@ -255,15 +255,15 @@ public:      }      tune_result_t set_tx_freq(size_t chan, double target_freq){ -        return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), target_freq); +        return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), 0, target_freq);      }      tune_result_t set_tx_freq(size_t chan, double target_freq, double lo_off){ -        return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), target_freq, lo_off); +        return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), 0, target_freq, lo_off);      }      double get_tx_freq(size_t chan){ -        return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan)); +        return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), 0);      }      freq_range_t get_tx_freq_range(size_t chan){ diff --git a/host/lib/usrp/simple_usrp.cpp b/host/lib/usrp/simple_usrp.cpp index e573d0fc0..b89b76eed 100644 --- a/host/lib/usrp/simple_usrp.cpp +++ b/host/lib/usrp/simple_usrp.cpp @@ -15,35 +15,20 @@  // along with this program.  If not, see <http://www.gnu.org/licenses/>.  // +#include <uhd/usrp/single_usrp.hpp>  #include <uhd/usrp/simple_usrp.hpp> -#include <uhd/usrp/tune_helper.hpp> -#include <uhd/utils/assert.hpp> -#include <uhd/utils/gain_group.hpp> -#include <uhd/usrp/subdev_props.hpp> -#include <uhd/usrp/mboard_props.hpp> -#include <uhd/usrp/device_props.hpp> -#include <uhd/usrp/dboard_props.hpp> -#include <uhd/usrp/dsp_props.hpp> -#include <boost/foreach.hpp> -#include <boost/format.hpp> -#include <stdexcept> -#include <iostream> +#include <uhd/utils/warning.hpp>  using namespace uhd;  using namespace uhd::usrp; -static inline freq_range_t add_dsp_shift(const freq_range_t &range, wax::obj dsp){ -    double codec_rate = dsp[DSP_PROP_CODEC_RATE].as<double>(); -    return freq_range_t(range.min - codec_rate/2.0, range.max + codec_rate/2.0); -} -  /***********************************************************************   * Simple USRP Implementation   **********************************************************************/  class simple_usrp_impl : public simple_usrp{  public:      simple_usrp_impl(const device_addr_t &addr){ -        _dev = device::make(addr); +        _sdev = single_usrp::make(addr);      }      ~simple_usrp_impl(void){ @@ -51,235 +36,187 @@ public:      }      device::sptr get_device(void){ -        return _dev; +        return _sdev->get_device();      }      std::string get_pp_string(void){ -        return str(boost::format( -            "Simple USRP:\n" -            "  Device: %s\n" -            "  Mboard: %s\n" -            "  RX DSP: %s\n" -            "  RX Dboard: %s\n" -            "  RX Subdev: %s\n" -            "  TX DSP: %s\n" -            "  TX Dboard: %s\n" -            "  TX Subdev: %s\n" -        ) -            % (*_dev)[DEVICE_PROP_NAME].as<std::string>() -            % _mboard()[MBOARD_PROP_NAME].as<std::string>() -            % _rx_dsp()[DSP_PROP_NAME].as<std::string>() -            % _rx_dboard()[DBOARD_PROP_NAME].as<std::string>() -            % _rx_subdev()[SUBDEV_PROP_NAME].as<std::string>() -            % _tx_dsp()[DSP_PROP_NAME].as<std::string>() -            % _tx_dboard()[DBOARD_PROP_NAME].as<std::string>() -            % _tx_subdev()[SUBDEV_PROP_NAME].as<std::string>() -        ); +        return _sdev->get_pp_string();      }      /*******************************************************************       * Misc       ******************************************************************/      time_spec_t get_time_now(void){ -        return _mboard()[MBOARD_PROP_TIME_NOW].as<time_spec_t>(); +        return _sdev->get_time_now();      }      void set_time_now(const time_spec_t &time_spec){ -        _mboard()[MBOARD_PROP_TIME_NOW] = time_spec; +        return _sdev->set_time_now(time_spec);      }      void set_time_next_pps(const time_spec_t &time_spec){ -        _mboard()[MBOARD_PROP_TIME_NEXT_PPS] = time_spec; +        return _sdev->set_time_next_pps(time_spec);      }      void issue_stream_cmd(const stream_cmd_t &stream_cmd){ -        _mboard()[MBOARD_PROP_STREAM_CMD] = stream_cmd; +        return _sdev->issue_stream_cmd(stream_cmd);      }      void set_clock_config(const clock_config_t &clock_config){ -        _mboard()[MBOARD_PROP_CLOCK_CONFIG] = clock_config; +        return _sdev->set_clock_config(clock_config);      }      /*******************************************************************       * RX methods       ******************************************************************/      void set_rx_subdev_spec(const subdev_spec_t &spec){ -        _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC] = spec; -        std::cout << "RX " << _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().to_pp_string() << std::endl; +        return _sdev->set_rx_subdev_spec(spec);      }      subdev_spec_t get_rx_subdev_spec(void){ -        return _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>(); +        return _sdev->get_rx_subdev_spec();      }      void set_rx_rate(double rate){ -        _rx_dsp()[DSP_PROP_HOST_RATE] = rate; +        return _sdev->set_rx_rate(rate);      }      double get_rx_rate(void){ -        return _rx_dsp()[DSP_PROP_HOST_RATE].as<double>(); +        return _sdev->get_rx_rate();      }      tune_result_t set_rx_freq(double target_freq){ -        return tune_rx_subdev_and_dsp(_rx_subdev(), _rx_dsp(), target_freq); +        return _sdev->set_rx_freq(target_freq);      }      tune_result_t set_rx_freq(double target_freq, double lo_off){ -        return tune_rx_subdev_and_dsp(_rx_subdev(), _rx_dsp(), target_freq, lo_off); +        return _sdev->set_rx_freq(target_freq, lo_off);      }      double get_rx_freq(void){ -        return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(), _rx_dsp()); +        return _sdev->get_rx_freq();      }      freq_range_t get_rx_freq_range(void){ -        return add_dsp_shift(_rx_subdev()[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _rx_dsp()); +        return _sdev->get_rx_freq_range();      }      void set_rx_gain(float gain){ -        return _rx_gain_group()->set_value(gain); +        return _sdev->set_rx_gain(gain);      }      float get_rx_gain(void){ -        return _rx_gain_group()->get_value(); +        return _sdev->get_rx_gain();      }      gain_range_t get_rx_gain_range(void){ -        return _rx_gain_group()->get_range(); +        return _sdev->get_rx_gain_range();      }      void set_rx_antenna(const std::string &ant){ -        _rx_subdev()[SUBDEV_PROP_ANTENNA] = ant; +        return _sdev->set_rx_antenna(ant);      }      std::string get_rx_antenna(void){ -        return _rx_subdev()[SUBDEV_PROP_ANTENNA].as<std::string>(); +        return _sdev->get_rx_antenna();      }      std::vector<std::string> get_rx_antennas(void){ -        return _rx_subdev()[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>(); +        return _sdev->get_rx_antennas();      }      bool get_rx_lo_locked(void){ -        return _rx_subdev()[SUBDEV_PROP_LO_LOCKED].as<bool>(); +        return _sdev->get_rx_lo_locked();      }      float read_rssi(void){ -        return _rx_subdev()[SUBDEV_PROP_RSSI].as<float>(); +        return _sdev->read_rssi();      }      dboard_iface::sptr get_rx_dboard_iface(void){ -        return _rx_dboard()[DBOARD_PROP_DBOARD_IFACE].as<dboard_iface::sptr>(); +        return _sdev->get_rx_dboard_iface();      }      /*******************************************************************       * TX methods       ******************************************************************/      void set_tx_subdev_spec(const subdev_spec_t &spec){ -        _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC] = spec; -        std::cout << "TX " << _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().to_pp_string() << std::endl; +        return _sdev->set_tx_subdev_spec(spec);      }      subdev_spec_t get_tx_subdev_spec(void){ -        return _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>(); +        return _sdev->get_tx_subdev_spec();      }      void set_tx_rate(double rate){ -        _tx_dsp()[DSP_PROP_HOST_RATE] = rate; +        return _sdev->set_tx_rate(rate);      }      double get_tx_rate(void){ -        return _tx_dsp()[DSP_PROP_HOST_RATE].as<double>(); +        return _sdev->get_tx_rate();      }      tune_result_t set_tx_freq(double target_freq){ -        return tune_tx_subdev_and_dsp(_tx_subdev(), _tx_dsp(), target_freq); +        return _sdev->set_tx_freq(target_freq);      }      tune_result_t set_tx_freq(double target_freq, double lo_off){ -        return tune_tx_subdev_and_dsp(_tx_subdev(), _tx_dsp(), target_freq, lo_off); +        return _sdev->set_tx_freq(target_freq, lo_off);      }      double get_tx_freq(void){ -        return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(), _tx_dsp()); +        return _sdev->get_tx_freq();      }      freq_range_t get_tx_freq_range(void){ -        return add_dsp_shift(_tx_subdev()[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _tx_dsp()); +        return _sdev->get_tx_freq_range();      }      void set_tx_gain(float gain){ -        return _tx_gain_group()->set_value(gain); +        return _sdev->set_tx_gain(gain);      }      float get_tx_gain(void){ -        return _tx_gain_group()->get_value(); +        return _sdev->get_tx_gain();      }      gain_range_t get_tx_gain_range(void){ -        return _tx_gain_group()->get_range(); +        return _sdev->get_tx_gain_range();      }      void set_tx_antenna(const std::string &ant){ -        _tx_subdev()[SUBDEV_PROP_ANTENNA] = ant; +        return _sdev->set_tx_antenna(ant);      }      std::string get_tx_antenna(void){ -        return _tx_subdev()[SUBDEV_PROP_ANTENNA].as<std::string>(); +        return _sdev->get_tx_antenna();      }      std::vector<std::string> get_tx_antennas(void){ -        return _tx_subdev()[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>(); +        return _sdev->get_tx_antennas();      }      bool get_tx_lo_locked(void){ -        return _tx_subdev()[SUBDEV_PROP_LO_LOCKED].as<bool>(); +        return _sdev->get_tx_lo_locked();      }      dboard_iface::sptr get_tx_dboard_iface(void){ -        return _tx_dboard()[DBOARD_PROP_DBOARD_IFACE].as<dboard_iface::sptr>(); +        return _sdev->get_tx_dboard_iface();      }  private: -    device::sptr _dev; -    wax::obj _mboard(void){ -        return (*_dev)[DEVICE_PROP_MBOARD]; -    } -    wax::obj _rx_dsp(void){ -        return _mboard()[MBOARD_PROP_RX_DSP]; -    } -    wax::obj _tx_dsp(void){ -        return _mboard()[MBOARD_PROP_TX_DSP]; -    } -    wax::obj _rx_dboard(void){ -        std::string db_name = _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().front().db_name; -        return _mboard()[named_prop_t(MBOARD_PROP_RX_DBOARD, db_name)]; -    } -    wax::obj _tx_dboard(void){ -        std::string db_name = _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().front().db_name; -        return _mboard()[named_prop_t(MBOARD_PROP_TX_DBOARD, db_name)]; -    } -    wax::obj _rx_subdev(void){ -        std::string sd_name = _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name; -        return _rx_dboard()[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)]; -    } -    wax::obj _tx_subdev(void){ -        std::string sd_name = _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name; -        return _tx_dboard()[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)]; -    } -    gain_group::sptr _rx_gain_group(void){ -        std::string sd_name = _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name; -        return _rx_dboard()[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>(); -    } -    gain_group::sptr _tx_gain_group(void){ -        std::string sd_name = _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name; -        return _tx_dboard()[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>(); -    } +    single_usrp::sptr _sdev;  };  /***********************************************************************   * The Make Function   **********************************************************************/  simple_usrp::sptr simple_usrp::make(const device_addr_t &dev_addr){ +    uhd::print_warning( +        "The simple USRP interface has been deprecated.\n" +        "Please switch to the single USRP interface.\n" +        "#include <uhd/usrp/single_usrp.hpp>\n" +        "single_usrp::sptr sdev = single_usrp::make(args);\n" +    );      return sptr(new simple_usrp_impl(dev_addr));  } diff --git a/host/lib/usrp/single_usrp.cpp b/host/lib/usrp/single_usrp.cpp new file mode 100644 index 000000000..bb4af44b8 --- /dev/null +++ b/host/lib/usrp/single_usrp.cpp @@ -0,0 +1,307 @@ +// +// 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/usrp/single_usrp.hpp> +#include <uhd/usrp/tune_helper.hpp> +#include <uhd/utils/assert.hpp> +#include <uhd/utils/gain_group.hpp> +#include <uhd/usrp/subdev_props.hpp> +#include <uhd/usrp/mboard_props.hpp> +#include <uhd/usrp/device_props.hpp> +#include <uhd/usrp/dboard_props.hpp> +#include <uhd/usrp/dsp_props.hpp> +#include <boost/foreach.hpp> +#include <boost/format.hpp> +#include <stdexcept> +#include <iostream> + +using namespace uhd; +using namespace uhd::usrp; + +static inline freq_range_t add_dsp_shift(const freq_range_t &range, wax::obj dsp){ +    double codec_rate = dsp[DSP_PROP_CODEC_RATE].as<double>(); +    return freq_range_t(range.min - codec_rate/2.0, range.max + codec_rate/2.0); +} + +/*********************************************************************** + * Simple USRP Implementation + **********************************************************************/ +class single_usrp_impl : public single_usrp{ +public: +    single_usrp_impl(const device_addr_t &addr){ +        _dev = device::make(addr); +    } + +    ~single_usrp_impl(void){ +        /* NOP */ +    } + +    device::sptr get_device(void){ +        return _dev; +    } + +    std::string get_pp_string(void){ +        std::string buff = str(boost::format( +            "Single USRP:\n" +            "  Device: %s\n" +            "  Mboard: %s\n" +        ) +            % (*_dev)[DEVICE_PROP_NAME].as<std::string>() +            % _mboard()[MBOARD_PROP_NAME].as<std::string>() +        ); + +        //----------- rx side of life ---------------------------------- +        buff += str(boost::format( +            "  RX DSP: %s\n" +        ) +            % _rx_dsp()[DSP_PROP_NAME].as<std::string>() +        ); +        for (size_t chan = 0; chan < this->get_rx_subdev_spec().size(); chan++){ +            buff += str(boost::format( +                "  RX Channel: %u\n" +                "    RX Dboard: %s\n" +                "    RX Subdev: %s\n" +            ) % chan +                % _rx_dboard(chan)[DBOARD_PROP_NAME].as<std::string>() +                % _rx_subdev(chan)[SUBDEV_PROP_NAME].as<std::string>() +            ); +        } + +        //----------- tx side of life ---------------------------------- +        buff += str(boost::format( +            "  TX DSP: %s\n" +        ) +            % _tx_dsp()[DSP_PROP_NAME].as<std::string>() +        ); +        for (size_t chan = 0; chan < this->get_tx_subdev_spec().size(); chan++){ +            buff += str(boost::format( +                "  TX Channel: %u\n" +                "    TX Dboard: %s\n" +                "    TX Subdev: %s\n" +            ) % chan +                % _tx_dboard(chan)[DBOARD_PROP_NAME].as<std::string>() +                % _tx_subdev(chan)[SUBDEV_PROP_NAME].as<std::string>() +            ); +        } + +        return buff; +    } + +    /******************************************************************* +     * Misc +     ******************************************************************/ +    time_spec_t get_time_now(void){ +        return _mboard()[MBOARD_PROP_TIME_NOW].as<time_spec_t>(); +    } + +    void set_time_now(const time_spec_t &time_spec){ +        _mboard()[MBOARD_PROP_TIME_NOW] = time_spec; +    } + +    void set_time_next_pps(const time_spec_t &time_spec){ +        _mboard()[MBOARD_PROP_TIME_NEXT_PPS] = time_spec; +    } + +    void issue_stream_cmd(const stream_cmd_t &stream_cmd){ +        _mboard()[MBOARD_PROP_STREAM_CMD] = stream_cmd; +    } + +    void set_clock_config(const clock_config_t &clock_config){ +        _mboard()[MBOARD_PROP_CLOCK_CONFIG] = clock_config; +    } + +    /******************************************************************* +     * RX methods +     ******************************************************************/ +    void set_rx_subdev_spec(const subdev_spec_t &spec){ +        _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC] = spec; +    } + +    subdev_spec_t get_rx_subdev_spec(void){ +        return _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>(); +    } + +    void set_rx_rate(double rate){ +        _rx_dsp()[DSP_PROP_HOST_RATE] = rate; +    } + +    double get_rx_rate(void){ +        return _rx_dsp()[DSP_PROP_HOST_RATE].as<double>(); +    } + +    tune_result_t set_rx_freq(double target_freq, size_t chan){ +        return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(), chan, target_freq); +    } + +    tune_result_t set_rx_freq(double target_freq, double lo_off, size_t chan){ +        return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(), chan, target_freq, lo_off); +    } + +    double get_rx_freq(size_t chan){ +        return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(), chan); +    } + +    freq_range_t get_rx_freq_range(size_t chan){ +        return add_dsp_shift(_rx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _rx_dsp()); +    } + +    void set_rx_gain(float gain, size_t chan){ +        return _rx_gain_group(chan)->set_value(gain); +    } + +    float get_rx_gain(size_t chan){ +        return _rx_gain_group(chan)->get_value(); +    } + +    gain_range_t get_rx_gain_range(size_t chan){ +        return _rx_gain_group(chan)->get_range(); +    } + +    void set_rx_antenna(const std::string &ant, size_t chan){ +        _rx_subdev(chan)[SUBDEV_PROP_ANTENNA] = ant; +    } + +    std::string get_rx_antenna(size_t chan){ +        return _rx_subdev(chan)[SUBDEV_PROP_ANTENNA].as<std::string>(); +    } + +    std::vector<std::string> get_rx_antennas(size_t chan){ +        return _rx_subdev(chan)[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>(); +    } + +    bool get_rx_lo_locked(size_t chan){ +        return _rx_subdev(chan)[SUBDEV_PROP_LO_LOCKED].as<bool>(); +    } + +    float read_rssi(size_t chan){ +        return _rx_subdev(chan)[SUBDEV_PROP_RSSI].as<float>(); +    } + +    dboard_iface::sptr get_rx_dboard_iface(size_t chan){ +        return _rx_dboard(chan)[DBOARD_PROP_DBOARD_IFACE].as<dboard_iface::sptr>(); +    } + +    /******************************************************************* +     * TX methods +     ******************************************************************/ +    void set_tx_subdev_spec(const subdev_spec_t &spec){ +        _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC] = spec; +    } + +    subdev_spec_t get_tx_subdev_spec(void){ +        return _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>(); +    } + +    void set_tx_rate(double rate){ +        _tx_dsp()[DSP_PROP_HOST_RATE] = rate; +    } + +    double get_tx_rate(void){ +        return _tx_dsp()[DSP_PROP_HOST_RATE].as<double>(); +    } + +    tune_result_t set_tx_freq(double target_freq, size_t chan){ +        return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(), chan, target_freq); +    } + +    tune_result_t set_tx_freq(double target_freq, double lo_off, size_t chan){ +        return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(), chan, target_freq, lo_off); +    } + +    double get_tx_freq(size_t chan){ +        return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(), chan); +    } + +    freq_range_t get_tx_freq_range(size_t chan){ +        return add_dsp_shift(_tx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _tx_dsp()); +    } + +    void set_tx_gain(float gain, size_t chan){ +        return _tx_gain_group(chan)->set_value(gain); +    } + +    float get_tx_gain(size_t chan){ +        return _tx_gain_group(chan)->get_value(); +    } + +    gain_range_t get_tx_gain_range(size_t chan){ +        return _tx_gain_group(chan)->get_range(); +    } + +    void set_tx_antenna(const std::string &ant, size_t chan){ +        _tx_subdev(chan)[SUBDEV_PROP_ANTENNA] = ant; +    } + +    std::string get_tx_antenna(size_t chan){ +        return _tx_subdev(chan)[SUBDEV_PROP_ANTENNA].as<std::string>(); +    } + +    std::vector<std::string> get_tx_antennas(size_t chan){ +        return _tx_subdev(chan)[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>(); +    } + +    bool get_tx_lo_locked(size_t chan){ +        return _tx_subdev(chan)[SUBDEV_PROP_LO_LOCKED].as<bool>(); +    } + +    dboard_iface::sptr get_tx_dboard_iface(size_t chan){ +        return _tx_dboard(chan)[DBOARD_PROP_DBOARD_IFACE].as<dboard_iface::sptr>(); +    } + +private: +    device::sptr _dev; +    wax::obj _mboard(void){ +        return (*_dev)[DEVICE_PROP_MBOARD]; +    } +    wax::obj _rx_dsp(void){ +        return _mboard()[MBOARD_PROP_RX_DSP]; +    } +    wax::obj _tx_dsp(void){ +        return _mboard()[MBOARD_PROP_TX_DSP]; +    } +    wax::obj _rx_dboard(size_t chan){ +        std::string db_name = this->get_rx_subdev_spec().at(chan).db_name; +        return _mboard()[named_prop_t(MBOARD_PROP_RX_DBOARD, db_name)]; +    } +    wax::obj _tx_dboard(size_t chan){ +        std::string db_name = this->get_tx_subdev_spec().at(chan).db_name; +        return _mboard()[named_prop_t(MBOARD_PROP_TX_DBOARD, db_name)]; +    } +    wax::obj _rx_subdev(size_t chan){ +        std::string sd_name = this->get_rx_subdev_spec().at(chan).sd_name; +        return _rx_dboard(chan)[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)]; +    } +    wax::obj _tx_subdev(size_t chan){ +        std::string sd_name = this->get_tx_subdev_spec().at(chan).sd_name; +        return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)]; +    } +    gain_group::sptr _rx_gain_group(size_t chan){ +        std::string sd_name = this->get_rx_subdev_spec().at(chan).sd_name; +        return _rx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>(); +    } +    gain_group::sptr _tx_gain_group(size_t chan){ +        std::string sd_name = this->get_tx_subdev_spec().at(chan).sd_name; +        return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>(); +    } +}; + +/*********************************************************************** + * The Make Function + **********************************************************************/ +single_usrp::sptr single_usrp::make(const device_addr_t &dev_addr){ +    return sptr(new single_usrp_impl(dev_addr)); +} diff --git a/host/lib/usrp/tune_helper.cpp b/host/lib/usrp/tune_helper.cpp index e516477d3..7633c67f2 100644 --- a/host/lib/usrp/tune_helper.cpp +++ b/host/lib/usrp/tune_helper.cpp @@ -30,11 +30,12 @@ using namespace uhd::usrp;   **********************************************************************/  static tune_result_t tune_xx_subdev_and_dxc(      dboard_iface::unit_t unit, -    wax::obj subdev, wax::obj dxc, +    wax::obj subdev, wax::obj dxc, size_t chan,      double target_freq, double lo_offset  ){      wax::obj subdev_freq_proxy = subdev[SUBDEV_PROP_FREQ]; -    wax::obj dxc_freq_proxy = dxc[DSP_PROP_FREQ_SHIFT]; +    std::string freq_name = dxc[DSP_PROP_FREQ_SHIFT_NAMES].as<prop_names_t>().at(chan); +    wax::obj dxc_freq_proxy = dxc[named_prop_t(DSP_PROP_FREQ_SHIFT, freq_name)];      double dxc_sample_rate = dxc[DSP_PROP_CODEC_RATE].as<double>();      // Ask the d'board to tune as closely as it can to target_freq+lo_offset @@ -65,11 +66,12 @@ static tune_result_t tune_xx_subdev_and_dxc(  static double derive_freq_from_xx_subdev_and_dxc(      dboard_iface::unit_t unit, -    wax::obj subdev, wax::obj dxc +    wax::obj subdev, wax::obj dxc, size_t chan  ){      //extract actual dsp and IF frequencies      double actual_inter_freq = subdev[SUBDEV_PROP_FREQ].as<double>(); -    double actual_dxc_freq = dxc[DSP_PROP_FREQ_SHIFT].as<double>(); +    std::string freq_name = dxc[DSP_PROP_FREQ_SHIFT_NAMES].as<prop_names_t>().at(chan); +    double actual_dxc_freq = dxc[named_prop_t(DSP_PROP_FREQ_SHIFT, freq_name)].as<double>();      //invert the sign on the dxc freq given the following conditions      if (unit == dboard_iface::UNIT_TX) actual_dxc_freq *= -1.0; @@ -81,50 +83,54 @@ static double derive_freq_from_xx_subdev_and_dxc(   * RX Tune   **********************************************************************/  tune_result_t usrp::tune_rx_subdev_and_dsp( -    wax::obj subdev, wax::obj ddc, +    wax::obj subdev, wax::obj ddc, size_t chan,      double target_freq, double lo_offset  ){ -    return tune_xx_subdev_and_dxc(dboard_iface::UNIT_RX, subdev, ddc, target_freq, lo_offset); +    return tune_xx_subdev_and_dxc(dboard_iface::UNIT_RX, subdev, ddc, chan, target_freq, lo_offset);  }  tune_result_t usrp::tune_rx_subdev_and_dsp(      wax::obj subdev, wax::obj ddc, -    double target_freq +    size_t chan, double target_freq  ){      double lo_offset = 0.0;      //if the local oscillator will be in the passband, use an offset      if (subdev[SUBDEV_PROP_USE_LO_OFFSET].as<bool>()){          lo_offset = 2.0*ddc[DSP_PROP_HOST_RATE].as<double>();      } -    return tune_rx_subdev_and_dsp(subdev, ddc, target_freq, lo_offset); +    return tune_rx_subdev_and_dsp(subdev, ddc, chan, target_freq, lo_offset);  } -double usrp::derive_freq_from_rx_subdev_and_dsp(wax::obj subdev, wax::obj ddc){ -    return derive_freq_from_xx_subdev_and_dxc(dboard_iface::UNIT_RX, subdev, ddc); +double usrp::derive_freq_from_rx_subdev_and_dsp( +    wax::obj subdev, wax::obj ddc, size_t chan +){ +    return derive_freq_from_xx_subdev_and_dxc(dboard_iface::UNIT_RX, subdev, ddc, chan);  }  /***********************************************************************   * TX Tune   **********************************************************************/  tune_result_t usrp::tune_tx_subdev_and_dsp( -    wax::obj subdev, wax::obj duc, +    wax::obj subdev, wax::obj duc, size_t chan,      double target_freq, double lo_offset  ){ -    return tune_xx_subdev_and_dxc(dboard_iface::UNIT_TX, subdev, duc, target_freq, lo_offset); +    return tune_xx_subdev_and_dxc(dboard_iface::UNIT_TX, subdev, duc, chan, target_freq, lo_offset);  }  tune_result_t usrp::tune_tx_subdev_and_dsp(      wax::obj subdev, wax::obj duc, -    double target_freq +    size_t chan, double target_freq  ){      double lo_offset = 0.0;      //if the local oscillator will be in the passband, use an offset      if (subdev[SUBDEV_PROP_USE_LO_OFFSET].as<bool>()){          lo_offset = 2.0*duc[DSP_PROP_HOST_RATE].as<double>();      } -    return tune_tx_subdev_and_dsp(subdev, duc, target_freq, lo_offset); +    return tune_tx_subdev_and_dsp(subdev, duc, chan, target_freq, lo_offset);  } -double usrp::derive_freq_from_tx_subdev_and_dsp(wax::obj subdev, wax::obj duc){ -    return derive_freq_from_xx_subdev_and_dxc(dboard_iface::UNIT_TX, subdev, duc); +double usrp::derive_freq_from_tx_subdev_and_dsp( +    wax::obj subdev, wax::obj duc, size_t chan +){ +    return derive_freq_from_xx_subdev_and_dxc(dboard_iface::UNIT_TX, subdev, duc, chan);  } diff --git a/host/lib/usrp/usrp1/dsp_impl.cpp b/host/lib/usrp/usrp1/dsp_impl.cpp index d5a88fa2d..573bce21f 100644 --- a/host/lib/usrp/usrp1/dsp_impl.cpp +++ b/host/lib/usrp/usrp1/dsp_impl.cpp @@ -21,6 +21,8 @@  #include <uhd/usrp/dsp_props.hpp>  #include <boost/bind.hpp>  #include <boost/format.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/assign/list_of.hpp>  #include <iostream>  #include <cmath> @@ -42,11 +44,15 @@ void usrp1_impl::rx_dsp_init(void)  /***********************************************************************   * RX DDC Get   **********************************************************************/ -void usrp1_impl::rx_dsp_get(const wax::obj &key, wax::obj &val) -{ +void usrp1_impl::rx_dsp_get(const wax::obj &key_, wax::obj &val){ +    named_prop_t key = named_prop_t::extract(key_); +      switch(key.as<dsp_prop_t>()){      case DSP_PROP_NAME: -        val = std::string("usrp1 ddc0"); +        val = str(boost::format("usrp1 ddc %uX %s") +            % this->get_num_ddcs() +            % (this->has_rx_halfband()? "+ hb" : "") +        );          return;      case DSP_PROP_OTHERS: @@ -54,7 +60,16 @@ void usrp1_impl::rx_dsp_get(const wax::obj &key, wax::obj &val)          return;      case DSP_PROP_FREQ_SHIFT: -        val = _rx_dsp_freq; +        val = _rx_dsp_freqs[key.name]; +        return; + +    case DSP_PROP_FREQ_SHIFT_NAMES:{ +            prop_names_t names; +            for(size_t i = 0; i < this->get_num_ddcs(); i++){ +                names.push_back(boost::lexical_cast<std::string>(i)); +            } +            val = names; +        }          return;      case DSP_PROP_CODEC_RATE: @@ -73,25 +88,22 @@ void usrp1_impl::rx_dsp_get(const wax::obj &key, wax::obj &val)  /***********************************************************************   * RX DDC Set   **********************************************************************/ -void usrp1_impl::rx_dsp_set(const wax::obj &key, const wax::obj &val) -{ +void usrp1_impl::rx_dsp_set(const wax::obj &key_, const wax::obj &val){ +    named_prop_t key = named_prop_t::extract(key_); +      switch(key.as<dsp_prop_t>()) {      case DSP_PROP_FREQ_SHIFT: {              double new_freq = val.as<double>();              boost::uint32_t reg_word = dsp_type1::calc_cordic_word_and_update(                  new_freq, _clock_ctrl->get_master_clock_freq()); -            //TODO TODO TODO TODO TODO TODO TODO TODO TODO  -            // -            // Handle multiple receive channels / DDC's -            // -            //TODO TODO TODO TODO TODO TODO TODO TODO TODO -            _iface->poke32(FR_RX_FREQ_0, reg_word); -            _iface->poke32(FR_RX_FREQ_1, reg_word); -            _iface->poke32(FR_RX_FREQ_2, reg_word); -            _iface->poke32(FR_RX_FREQ_3, reg_word); - -            _rx_dsp_freq = new_freq; +            static const uhd::dict<std::string, boost::uint32_t> +            freq_name_to_reg_val = boost::assign::map_list_of +                ("0", FR_RX_FREQ_0) ("1", FR_RX_FREQ_1) +                ("2", FR_RX_FREQ_2) ("3", FR_RX_FREQ_3) +            ; +            _iface->poke32(freq_name_to_reg_val[key.name], reg_word); +            _rx_dsp_freqs[key.name] = new_freq;              return;          }      case DSP_PROP_HOST_RATE: { @@ -133,11 +145,15 @@ void usrp1_impl::tx_dsp_init(void)  /***********************************************************************   * TX DUC Get   **********************************************************************/ -void usrp1_impl::tx_dsp_get(const wax::obj &key, wax::obj &val) -{ +void usrp1_impl::tx_dsp_get(const wax::obj &key_, wax::obj &val){ +    named_prop_t key = named_prop_t::extract(key_); +      switch(key.as<dsp_prop_t>()) {      case DSP_PROP_NAME: -        val = std::string("usrp1 duc0"); +        val = str(boost::format("usrp1 duc %uX %s") +            % this->get_num_ducs() +            % (this->has_tx_halfband()? "+ hb" : "") +        );          return;      case DSP_PROP_OTHERS: @@ -145,7 +161,16 @@ void usrp1_impl::tx_dsp_get(const wax::obj &key, wax::obj &val)          return;      case DSP_PROP_FREQ_SHIFT: -        val = _tx_dsp_freq; +        val = _tx_dsp_freqs[key.name]; +        return; + +    case DSP_PROP_FREQ_SHIFT_NAMES:{ +            prop_names_t names; +            for(size_t i = 0; i < this->get_num_ducs(); i++){ +                names.push_back(boost::lexical_cast<std::string>(i)); +            } +            val = names; +        }          return;      case DSP_PROP_CODEC_RATE: @@ -164,20 +189,20 @@ void usrp1_impl::tx_dsp_get(const wax::obj &key, wax::obj &val)  /***********************************************************************   * TX DUC Set   **********************************************************************/ -void usrp1_impl::tx_dsp_set(const wax::obj &key, const wax::obj &val) -{ +void usrp1_impl::tx_dsp_set(const wax::obj &key_, const wax::obj &val){ +    named_prop_t key = named_prop_t::extract(key_); +      switch(key.as<dsp_prop_t>()) { -    //TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO -    // -    // Set both codec frequencies until we have duality properties  -    // -    //TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO      case DSP_PROP_FREQ_SHIFT: {              double new_freq = val.as<double>(); -            _codec_ctrls[DBOARD_SLOT_A]->set_duc_freq(new_freq); -            _codec_ctrls[DBOARD_SLOT_B]->set_duc_freq(new_freq); -            _tx_dsp_freq = new_freq; + +            //map the freq shift key to a subdev spec to a particular codec chip +            std::string db_name = _tx_subdev_spec.at(boost::lexical_cast<size_t>(key.name)).db_name; +            if (db_name == "A") _codec_ctrls[DBOARD_SLOT_A]->set_duc_freq(new_freq); +            if (db_name == "B") _codec_ctrls[DBOARD_SLOT_B]->set_duc_freq(new_freq); + +            _tx_dsp_freqs[key.name] = new_freq;              return;          } diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index 92e8bc20a..146038bd9 100644 --- a/host/lib/usrp/usrp1/io_impl.cpp +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -33,294 +33,283 @@ using namespace uhd::usrp;  using namespace uhd::transport;  namespace asio = boost::asio; -struct usrp1_send_state { -    uhd::transport::managed_send_buffer::sptr send_buff; -    size_t bytes_written; -    size_t underrun_poll_samp_count; - -    size_t bytes_free() +/*********************************************************************** + * Pseudo send buffer implementation + **********************************************************************/ +class pseudo_managed_send_buffer : public managed_send_buffer{ +public: + +    pseudo_managed_send_buffer( +        const boost::asio::mutable_buffer &buff, +        const boost::function<ssize_t(size_t)> &commit +    ): +        _buff(buff), +        _commit(commit)      { -        if (send_buff != NULL) -            return send_buff->size() - bytes_written; -        else -            return 0; +        /* NOP */      } -}; -struct usrp1_recv_state { -    uhd::transport::managed_recv_buffer::sptr recv_buff; -    size_t bytes_read; -    size_t overrun_poll_samp_count; +    ssize_t commit(size_t num_bytes){ +        return _commit(num_bytes); +    } -    size_t bytes_avail() -    { -        if (recv_buff != NULL) -            return recv_buff->size() - bytes_read; -        else -            return 0; +private: +    const boost::asio::mutable_buffer &get(void) const{ +        return _buff;      } -}; -/*********************************************************************** - * IO Implementation Details - **********************************************************************/ -struct usrp1_impl::io_impl { -    io_impl(); -    ~io_impl(void); - -    //state handling for buffer management  -    usrp1_recv_state recv_state; -    usrp1_send_state send_state; - -    //send transport management  -    bool get_send_buffer(zero_copy_if::sptr zc_if); -    size_t copy_convert_send_samps(const void *buff, size_t num_samps, -                              size_t sample_offset, const io_type_t io_type, -                              otw_type_t otw_type); -    bool conditional_buff_commit(bool force); -    bool check_underrun(usrp_ctrl::sptr ctrl_if, -                        size_t poll_interval, bool force); - -    //recv transport management  -    bool get_recv_buffer(zero_copy_if::sptr zc_if); -    size_t copy_convert_recv_samps(void *buff, size_t num_samps, -                              size_t sample_offset, const io_type_t io_type, -                              otw_type_t otw_type); -    bool check_overrun(usrp_ctrl::sptr ctrl_if, -                        size_t poll_interval, bool force); +    const boost::asio::mutable_buffer      _buff; +    const boost::function<ssize_t(size_t)> _commit;  }; -usrp1_impl::io_impl::io_impl() -{ -    send_state.send_buff = uhd::transport::managed_send_buffer::sptr(); -    recv_state.recv_buff = uhd::transport::managed_recv_buffer::sptr(); -} - -usrp1_impl::io_impl::~io_impl(void) -{ -   /* NOP */ -} - -void usrp1_impl::io_init(void) -{ -    _rx_otw_type.width = 16; -    _rx_otw_type.shift = 0; -    _rx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; - -    _tx_otw_type.width = 16; -    _tx_otw_type.shift = 0; -    _tx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; - -    _io_impl = UHD_PIMPL_MAKE(io_impl, ()); -} -  /*********************************************************************** - * Data Send + * IO Implementation Details   **********************************************************************/ -bool usrp1_impl::io_impl::get_send_buffer(zero_copy_if::sptr zc_if) -{ -    if (send_state.send_buff == NULL) { +struct usrp1_impl::io_impl{ +    io_impl(zero_copy_if::sptr data_transport): +        data_transport(data_transport), +        underflow_poll_samp_count(0), +        overflow_poll_samp_count(0), +        send_buff(data_transport->get_send_buff()), +        num_bytes_committed(0) +    { +        /* NOP */ +    } -        send_state.send_buff = zc_if->get_send_buff(); -        if (send_state.send_buff == NULL) -            return false; +    ~io_impl(void){ +        flush_send_buff(); +    } -        send_state.bytes_written = 0; +    zero_copy_if::sptr data_transport; + +    //state management for the vrt packet handler code +    vrt_packet_handler::recv_state packet_handler_recv_state; +    vrt_packet_handler::send_state packet_handler_send_state; + +    //state management for overflow and underflow +    size_t underflow_poll_samp_count; +    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; +    boost::uint8_t pseudo_buff[BYTES_PER_PACKET]; +    ssize_t phony_commit_pseudo_buff(size_t num_bytes); +    ssize_t phony_commit_send_buff(size_t num_bytes); +    ssize_t commit_send_buff(void); +    void flush_send_buff(void); +    bool get_send_buffs(vrt_packet_handler::managed_send_buffs_t &); + +    //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;      } +}; -    return true; +/*! + * 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. + */ +ssize_t 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); +        ssize_t ret = phony_commit_send_buff(bytes_copied_here); +        if (ret < 0) return ret; +        bytes_to_copy -= ret; +        bytes_copied += ret; +    } +    return bytes_copied;  } -size_t usrp1_impl::io_impl::copy_convert_send_samps(const void *buff, -                                                    size_t num_samps, -                                                    size_t sample_offset, -                                                    const io_type_t io_type, -                                                    otw_type_t otw_type) -{ -    UHD_ASSERT_THROW(send_state.bytes_free() % otw_type.get_sample_size() == 0); - -    size_t samps_free = send_state.bytes_free() / otw_type.get_sample_size(); -    size_t copy_samps = std::min(num_samps - sample_offset, samps_free);  - -    const boost::uint8_t *io_mem = -        reinterpret_cast<const boost::uint8_t *>(buff); - -    boost::uint8_t *otw_mem = send_state.send_buff->cast<boost::uint8_t *>(); - -    convert_io_type_to_otw_type(io_mem + sample_offset * io_type.size, -                                io_type, -                                otw_mem + send_state.bytes_written, -                                otw_type, -                                copy_samps); - -    send_state.bytes_written += copy_samps * otw_type.get_sample_size(); -    send_state.underrun_poll_samp_count += copy_samps; - -    return copy_samps; +/*! + * Accept a commit of num bytes to the send buffer. + * Conditionally commit the send buffer if full. + */ +ssize_t 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 num_bytes; +    ssize_t ret = commit_send_buff(); +    return (ret < 0)? ret : num_bytes;  } -bool usrp1_impl::io_impl::conditional_buff_commit(bool force) -{ -    if (send_state.bytes_written % 512) -        return false; - -    if (force || send_state.bytes_free() == 0) { -        send_state.send_buff->commit(send_state.bytes_written); -        send_state.send_buff = uhd::transport::managed_send_buffer::sptr(); -        return true; -    } -     -    return false; +/*! + * Flush the send buffer: + * Zero-pad the send buffer to the nearest 512 byte boundary and commit. + */ +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();  } -bool usrp1_impl::io_impl::check_underrun(usrp_ctrl::sptr ctrl_if, -                                         size_t poll_interval, -                                         bool force) -{ -    unsigned char underrun = 0; - -    bool ready_to_poll = send_state.underrun_poll_samp_count > poll_interval; - -    if (force || ready_to_poll) { -        int ret = ctrl_if->usrp_control_read(VRQ_GET_STATUS, -                                             0, -                                             GS_TX_UNDERRUN, -                                             &underrun, sizeof(char)); -        if (ret < 0) -            std::cerr << "USRP: underrun check failed" << std::endl; -        if (underrun) -            std::cerr << "U" << std::flush; - -        send_state.underrun_poll_samp_count = 0; -    } - -    return (bool) underrun; +/*! + * Perform an actual commit on the send buffer: + * Commit the contents of the send buffer and request a new buffer. + */ +ssize_t usrp1_impl::io_impl::commit_send_buff(void){ +    ssize_t ret = send_buff->commit(num_bytes_committed); +    send_buff = data_transport->get_send_buff(); +    num_bytes_committed = 0; +    return ret;  } -size_t usrp1_impl::send(const std::vector<const void *> &buffs, -                        size_t num_samps, -                        const tx_metadata_t &, -                        const io_type_t &io_type, -                        send_mode_t) -{ +bool usrp1_impl::io_impl::get_send_buffs( +    vrt_packet_handler::managed_send_buffs_t &buffs +){      UHD_ASSERT_THROW(buffs.size() == 1); -    size_t total_samps_sent = 0; - -    while (total_samps_sent < num_samps) { -        if (!_io_impl->get_send_buffer(_data_transport)) -            return 0; - -        total_samps_sent += _io_impl->copy_convert_send_samps(buffs[0], -                                                              num_samps, -                                                              total_samps_sent, -                                                              io_type, -                                                              _tx_otw_type); -        if (total_samps_sent == num_samps) -            _io_impl->conditional_buff_commit(true); -        else -            _io_impl->conditional_buff_commit(false); - -        _io_impl->check_underrun(_ctrl_transport, -                                 _tx_samps_per_poll_interval, false); +    //not enough bytes free -> use the pseudo buffer +    if (get_send_mem_size() < BYTES_PER_PACKET){ +        buffs[0] = managed_send_buffer::sptr(new pseudo_managed_send_buffer( +            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::sptr(new pseudo_managed_send_buffer( +            boost::asio::buffer(get_send_mem_ptr(), get_send_mem_size()), +            boost::bind(&usrp1_impl::io_impl::phony_commit_send_buff, this, _1) +        ));      } -    return total_samps_sent; +    return buffs[0].get();  }  /*********************************************************************** - * Data Recv + * Initialize internals within this file   **********************************************************************/ -bool usrp1_impl::io_impl::get_recv_buffer(zero_copy_if::sptr zc_if) -{ -    if ((recv_state.recv_buff == NULL) || (recv_state.bytes_avail() == 0)) { - -        recv_state.recv_buff = zc_if->get_recv_buff(); -        if (recv_state.recv_buff == NULL) -            return false; +void usrp1_impl::io_init(void){ +    _rx_otw_type.width = 16; +    _rx_otw_type.shift = 0; +    _rx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; -        recv_state.bytes_read = 0; -    } +    _tx_otw_type.width = 16; +    _tx_otw_type.shift = 0; +    _tx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; -    return true; +    _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transport));  } -size_t usrp1_impl::io_impl::copy_convert_recv_samps(void *buff, -                                                    size_t num_samps, -                                                    size_t sample_offset, -                                                    const io_type_t io_type, -                                                    otw_type_t otw_type) -{ -    UHD_ASSERT_THROW(recv_state.bytes_avail() % otw_type.get_sample_size() == 0); - -    size_t samps_avail = recv_state.bytes_avail() / otw_type.get_sample_size(); -    size_t copy_samps = std::min(num_samps - sample_offset, samps_avail);  - -    const boost::uint8_t *otw_mem = -        recv_state.recv_buff->cast<const boost::uint8_t *>(); - -    boost::uint8_t *io_mem = reinterpret_cast<boost::uint8_t *>(buff); - -    convert_otw_type_to_io_type(otw_mem + recv_state.bytes_read, -                                otw_type, -                                io_mem + sample_offset * io_type.size, -                                io_type, -                                copy_samps); - -    recv_state.bytes_read += copy_samps * otw_type.get_sample_size(); -    recv_state.overrun_poll_samp_count += copy_samps; - -    return copy_samps; +/*********************************************************************** + * Data send + helper functions + **********************************************************************/ +static void usrp1_bs_vrt_packer( +    boost::uint32_t *, +    vrt::if_packet_info_t &if_packet_info +){ +    if_packet_info.num_header_words32 = 0; +    if_packet_info.num_packet_words32 = if_packet_info.num_payload_words32;  } -bool usrp1_impl::io_impl::check_overrun(usrp_ctrl::sptr ctrl_if, -                                        size_t poll_interval, -                                        bool force) -{ -    unsigned char overrun = 0; - -    bool ready_to_poll = recv_state.overrun_poll_samp_count > poll_interval; - -    if (force || ready_to_poll) { -        int ret = ctrl_if->usrp_control_read(VRQ_GET_STATUS, -                                             0, -                                             GS_RX_OVERRUN, -                                             &overrun, sizeof(char)); -        if (ret < 0) -            std::cerr << "USRP: overrrun check failed" << std::endl; -        if (overrun) -            std::cerr << "O" << std::flush; - -        recv_state.overrun_poll_samp_count = 0; +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, +    send_mode_t send_mode +){ +    size_t num_samps_sent = vrt_packet_handler::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, _tx_otw_type,                     //input and output types to convert +        _clock_ctrl->get_master_clock_freq(),      //master clock tick rate +        &usrp1_bs_vrt_packer, +        boost::bind(&usrp1_impl::io_impl::get_send_buffs, _io_impl.get(), _1), +        get_max_send_samps_per_packet(), +        0,                                         //vrt header offset +        _tx_subdev_spec.size()                     //num channels +    ); + +    //Don't honor sob because it is normal to be always bursting... +    //handle eob flag (commit the buffer) +    if (metadata.end_of_burst) _io_impl->flush_send_buff(); + +    //handle the polling for underflow conditions +    _io_impl->underflow_poll_samp_count += num_samps_sent; +    if (_io_impl->underflow_poll_samp_count >= _tx_samps_per_poll_interval){ +        _io_impl->underflow_poll_samp_count = 0; //reset count +        boost::uint8_t underflow = 0; +        ssize_t ret = _ctrl_transport->usrp_control_read( +            VRQ_GET_STATUS, 0, GS_TX_UNDERRUN, +            &underflow, sizeof(underflow) +        ); +        if (ret < 0)        std::cerr << "USRP: underflow check failed" << std::endl; +        else if (underflow) std::cerr << "U" << std::flush;      } -    return (bool) overrun; +    return num_samps_sent;  } -size_t usrp1_impl::recv(const std::vector<void *> &buffs, -                        size_t num_samps, -                        rx_metadata_t &, -                        const io_type_t &io_type, -                        recv_mode_t, -                        size_t) -{ -    UHD_ASSERT_THROW(buffs.size() == 1); - -    size_t total_samps_recv = 0; - -    while (total_samps_recv < num_samps) { +/*********************************************************************** + * Data recv + helper functions + **********************************************************************/ +static void usrp1_bs_vrt_unpacker( +    const boost::uint32_t *, +    vrt::if_packet_info_t &if_packet_info +){ +    if_packet_info.packet_type = vrt::if_packet_info_t::PACKET_TYPE_DATA; +    if_packet_info.num_payload_words32 = if_packet_info.num_packet_words32; +    if_packet_info.num_header_words32 = 0; +    if_packet_info.packet_count = 0; +    if_packet_info.sob = false; +    if_packet_info.eob = false; +    if_packet_info.has_sid = false; +    if_packet_info.has_cid = false; +    if_packet_info.has_tsi = false; +    if_packet_info.has_tsf = false; +    if_packet_info.has_tlr = false; +} -        if (!_io_impl->get_recv_buffer(_data_transport)) -            return 0; +static bool get_recv_buffs( +    zero_copy_if::sptr zc_if, +    vrt_packet_handler::managed_recv_buffs_t &buffs +){ +    UHD_ASSERT_THROW(buffs.size() == 1); +    buffs[0] = zc_if->get_recv_buff(); +    return buffs[0].get(); +} -        total_samps_recv += _io_impl->copy_convert_recv_samps(buffs[0], -                                                              num_samps, -                                                              total_samps_recv, -                                                              io_type, -                                                              _rx_otw_type); -        _io_impl->check_overrun(_ctrl_transport, -                                _rx_samps_per_poll_interval, false); +size_t usrp1_impl::recv( +    const std::vector<void *> &buffs, size_t num_samps, +    rx_metadata_t &metadata, const io_type_t &io_type, +    recv_mode_t recv_mode, size_t /*timeout_ms TODO*/ +){ +    size_t num_samps_recvd = vrt_packet_handler::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, _rx_otw_type,                     //input and output types to convert +        _clock_ctrl->get_master_clock_freq(),      //master clock tick rate +        &usrp1_bs_vrt_unpacker, +        boost::bind(&get_recv_buffs, _data_transport, _1), +        &vrt_packet_handler::handle_overflow_nop, +        0,                                         //vrt header offset +        _rx_subdev_spec.size()                     //num channels +    ); + +    //handle the polling for overflow conditions +    _io_impl->overflow_poll_samp_count += num_samps_recvd; +    if (_io_impl->overflow_poll_samp_count >= _rx_samps_per_poll_interval){ +        _io_impl->overflow_poll_samp_count = 0; //reset count +        boost::uint8_t overflow = 0; +        ssize_t ret = _ctrl_transport->usrp_control_read( +            VRQ_GET_STATUS, 0, GS_RX_OVERRUN, +            &overflow, sizeof(overflow) +        ); +        if (ret < 0)       std::cerr << "USRP: overflow check failed" << std::endl; +        else if (overflow) std::cerr << "O" << std::flush;      } -    return total_samps_recv;  +    return num_samps_recvd;  } diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp index a90532cb8..fe3774eb4 100644 --- a/host/lib/usrp/usrp1/mboard_impl.cpp +++ b/host/lib/usrp/usrp1/mboard_impl.cpp @@ -36,6 +36,8 @@  using namespace uhd;  using namespace uhd::usrp; +static const bool usrp1_mboard_verbose = false; +  /***********************************************************************   * Calculate the RX mux value:   *    The I and Q mux values are intentionally reversed to flip I and Q @@ -146,6 +148,7 @@ static boost::uint32_t calc_tx_mux(      //calculate the channel flags      int channel_flags = 0, chan = 0; +    uhd::dict<std::string, int> slot_to_chan_count = boost::assign::map_list_of("A", 0)("B", 0);      BOOST_FOREACH(const subdev_spec_pair_t &pair, subdev_spec){          wax::obj dboard = mboard[named_prop_t(MBOARD_PROP_TX_DBOARD, pair.db_name)];          wax::obj subdev = dboard[named_prop_t(DBOARD_PROP_SUBDEV, pair.sd_name)]; @@ -155,6 +158,14 @@ static boost::uint32_t calc_tx_mux(          if (pair.db_name == "A") channel_flags |= chan_to_conn_to_flag[chan][conn] << 0;          if (pair.db_name == "B") channel_flags |= chan_to_conn_to_flag[chan][conn] << 8; +        //sanity check, only 1 channel per slot +        slot_to_chan_count[pair.db_name]++; +        if (slot_to_chan_count[pair.db_name] > 1){ +            throw std::runtime_error(str(boost::format( +                "dboard slot %s assigned to multiple channels in subdev spec %s" +            ) % pair.db_name % subdev_spec.to_string())); +        } +          //increment for the next channel          chan++;      } @@ -172,23 +183,23 @@ static boost::uint32_t calc_tx_mux(   * |               Reserved                        |T|DUCs |R|DDCs |   * +-----------------------------------------------+-+-----+-+-----+   */ -static int num_ddcs(boost::uint32_t regval) -{ +size_t usrp1_impl::get_num_ddcs(void){ +    boost::uint32_t regval = _iface->peek32(FR_RB_CAPS);      return (regval >> 0) & 0x0007;  } -static int num_ducs(boost::uint32_t regval) -{ +size_t usrp1_impl::get_num_ducs(void){ +    boost::uint32_t regval = _iface->peek32(FR_RB_CAPS);      return (regval >> 4) & 0x0007;  } -static bool has_rx_halfband(boost::uint32_t regval) -{ +bool usrp1_impl::has_rx_halfband(void){ +    boost::uint32_t regval = _iface->peek32(FR_RB_CAPS);      return (regval >> 3) & 0x0001;  } -static bool has_tx_halfband(boost::uint32_t regval) -{ +bool usrp1_impl::has_tx_halfband(void){ +    boost::uint32_t regval = _iface->peek32(FR_RB_CAPS);      return (regval >> 7) & 0x0001;  } @@ -220,26 +231,25 @@ void usrp1_impl::mboard_init(void)      // Set default for TX format to 16-bit I&Q      _iface->poke32(FR_TX_FORMAT, 0x00000000); -    // TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO  -    //  -    // Do something useful with the capabilities register -    // -    boost::uint32_t regval = _iface->peek32(FR_RB_CAPS); -    std::cout << "USRP1 Capabilities" << std::endl; -    std::cout << "    number of duc's: " << num_ddcs(regval) << std::endl; -    std::cout << "    number of ddc's: " << num_ducs(regval) << std::endl; -    std::cout << "    rx halfband:     " << has_rx_halfband(regval) << std::endl; -    std::cout << "    tx halfband:     " << has_tx_halfband(regval) << std::endl; +    if (usrp1_mboard_verbose){ +        std::cout << "USRP1 Capabilities" << std::endl; +        std::cout << "    number of duc's: " << get_num_ddcs() << std::endl; +        std::cout << "    number of ddc's: " << get_num_ducs() << std::endl; +        std::cout << "    rx halfband:     " << has_rx_halfband() << std::endl; +        std::cout << "    tx halfband:     " << has_tx_halfband() << std::endl; +    }  }  void usrp1_impl::issue_stream_cmd(const stream_cmd_t &stream_cmd)  { -    if (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS) { -        _iface->write_firmware_cmd(VRQ_FPGA_SET_RX_ENABLE, true, 0, 0, 0); -    } +    switch(stream_cmd.stream_mode){ +    case stream_cmd_t::STREAM_MODE_START_CONTINUOUS: +        return _iface->write_firmware_cmd(VRQ_FPGA_SET_RX_ENABLE, true, 0, 0, 0); + +    case stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS: +        return _iface->write_firmware_cmd(VRQ_FPGA_SET_RX_ENABLE, false, 0, 0, 0); -    if (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS) { -        _iface->write_firmware_cmd(VRQ_FPGA_SET_RX_ENABLE, false, 0, 0, 0); +    default: throw std::runtime_error("unsupported stream command type for USRP1");      }  } @@ -269,7 +279,7 @@ void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val)      //handle the get request conditioned on the key      switch(key.as<mboard_prop_t>()){      case MBOARD_PROP_NAME: -        val = std::string("usrp1 mboard"); +        val = std::string("usrp1 mboard - " + (*_mboard_proxy)[std::string("serial")].as<std::string>());          return;      case MBOARD_PROP_OTHERS: @@ -361,18 +371,26 @@ void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val)      case MBOARD_PROP_RX_SUBDEV_SPEC:          _rx_subdev_spec = val.as<subdev_spec_t>(); +        if (_rx_subdev_spec.size() > this->get_num_ddcs()){ +            throw std::runtime_error(str(boost::format( +                "USRP1 suports up to %u RX channels.\n" +                "However, this RX subdev spec requires %u channels\n" +            ) % this->get_num_ddcs() % _rx_subdev_spec.size())); +        }          verify_rx_subdev_spec(_rx_subdev_spec, _mboard_proxy->get_link()); -        //sanity check -        UHD_ASSERT_THROW(_rx_subdev_spec.size() <= 2);          //set the mux and set the number of rx channels          _iface->poke32(FR_RX_MUX, calc_rx_mux(_rx_subdev_spec, _mboard_proxy->get_link()));          return;      case MBOARD_PROP_TX_SUBDEV_SPEC:          _tx_subdev_spec = val.as<subdev_spec_t>(); +        if (_tx_subdev_spec.size() > this->get_num_ducs()){ +            throw std::runtime_error(str(boost::format( +                "USRP1 suports up to %u TX channels.\n" +                "However, this TX subdev spec requires %u channels\n" +            ) % this->get_num_ducs() % _tx_subdev_spec.size())); +        }          verify_tx_subdev_spec(_tx_subdev_spec, _mboard_proxy->get_link()); -        //sanity check -        UHD_ASSERT_THROW(_tx_subdev_spec.size() <= 2);          //set the mux and set the number of tx channels          _iface->poke32(FR_TX_MUX, calc_tx_mux(_tx_subdev_spec, _mboard_proxy->get_link()));          return; diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp index c2f693eeb..20ae3c02a 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.hpp +++ b/host/lib/usrp/usrp1/usrp1_impl.hpp @@ -91,8 +91,16 @@ public:                  recv_mode_t,                  size_t timeout); -    size_t get_max_send_samps_per_packet(void) const { return 0; } -    size_t get_max_recv_samps_per_packet(void) const { return 0; } +    static const size_t BYTES_PER_PACKET = 512*4; //under the transfer size + +    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(); +    } +      bool recv_async_msg(uhd::async_metadata_t &, size_t);  private: @@ -179,19 +187,27 @@ private:      void rx_dsp_init(void);      void rx_dsp_get(const wax::obj &, wax::obj &);      void rx_dsp_set(const wax::obj &, const wax::obj &); -    double _rx_dsp_freq; size_t _rx_dsp_decim; +    uhd::dict<std::string, double> _rx_dsp_freqs; +    size_t _rx_dsp_decim;      wax_obj_proxy::sptr _rx_dsp_proxy;      //tx dsp functions and settings      void tx_dsp_init(void);      void tx_dsp_get(const wax::obj &, wax::obj &);      void tx_dsp_set(const wax::obj &, const wax::obj &); -    double _tx_dsp_freq; size_t _tx_dsp_interp; +    uhd::dict<std::string, double> _tx_dsp_freqs; +    size_t _tx_dsp_interp;      wax_obj_proxy::sptr _tx_dsp_proxy;      //transports      uhd::transport::usb_zero_copy::sptr _data_transport;      usrp_ctrl::sptr _ctrl_transport; + +    //capabilities +    size_t get_num_ducs(void); +    size_t get_num_ddcs(void); +    bool has_rx_halfband(void); +    bool has_tx_halfband(void);  };  #endif /* INCLUDED_USRP1_IMPL_HPP */ diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 6422142ce..0c85e643f 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -56,7 +56,9 @@ void usrp2_mboard_impl::init_ddc_config(void){  /***********************************************************************   * DDC Properties   **********************************************************************/ -void usrp2_mboard_impl::ddc_get(const wax::obj &key, wax::obj &val){ +void usrp2_mboard_impl::ddc_get(const wax::obj &key_, wax::obj &val){ +    named_prop_t key = named_prop_t::extract(key_); +      switch(key.as<dsp_prop_t>()){      case DSP_PROP_NAME:          val = std::string("usrp2 ddc0"); @@ -70,6 +72,10 @@ void usrp2_mboard_impl::ddc_get(const wax::obj &key, wax::obj &val){          val = _ddc_freq;          return; +    case DSP_PROP_FREQ_SHIFT_NAMES: +        val = prop_names_t(1, ""); +        return; +      case DSP_PROP_CODEC_RATE:          val = get_master_clock_freq();          return; @@ -82,7 +88,9 @@ void usrp2_mboard_impl::ddc_get(const wax::obj &key, wax::obj &val){      }  } -void usrp2_mboard_impl::ddc_set(const wax::obj &key, const wax::obj &val){ +void usrp2_mboard_impl::ddc_set(const wax::obj &key_, const wax::obj &val){ +    named_prop_t key = named_prop_t::extract(key_); +      switch(key.as<dsp_prop_t>()){      case DSP_PROP_FREQ_SHIFT:{ @@ -131,7 +139,9 @@ void usrp2_mboard_impl::init_duc_config(void){  /***********************************************************************   * DUC Properties   **********************************************************************/ -void usrp2_mboard_impl::duc_get(const wax::obj &key, wax::obj &val){ +void usrp2_mboard_impl::duc_get(const wax::obj &key_, wax::obj &val){ +    named_prop_t key = named_prop_t::extract(key_); +      switch(key.as<dsp_prop_t>()){      case DSP_PROP_NAME:          val = std::string("usrp2 duc0"); @@ -145,6 +155,10 @@ void usrp2_mboard_impl::duc_get(const wax::obj &key, wax::obj &val){          val = _duc_freq;          return; +    case DSP_PROP_FREQ_SHIFT_NAMES: +        val = prop_names_t(1, ""); +        return; +      case DSP_PROP_CODEC_RATE:          val = get_master_clock_freq();          return; @@ -157,7 +171,9 @@ void usrp2_mboard_impl::duc_get(const wax::obj &key, wax::obj &val){      }  } -void usrp2_mboard_impl::duc_set(const wax::obj &key, const wax::obj &val){ +void usrp2_mboard_impl::duc_set(const wax::obj &key_, const wax::obj &val){ +    named_prop_t key = named_prop_t::extract(key_); +      switch(key.as<dsp_prop_t>()){      case DSP_PROP_FREQ_SHIFT:{ diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 4e883cf81..91a1b2344 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -189,7 +189,7 @@ bool usrp2_impl::recv_async_msg(  /***********************************************************************   * Send Data   **********************************************************************/ -bool get_send_buffs( +static bool get_send_buffs(      const std::vector<udp_zero_copy::sptr> &trans,      vrt_packet_handler::managed_send_buffs_t &buffs  ){ diff --git a/host/test/tune_helper_test.cpp b/host/test/tune_helper_test.cpp index 570f47293..1ef4af330 100644 --- a/host/test/tune_helper_test.cpp +++ b/host/test/tune_helper_test.cpp @@ -99,7 +99,8 @@ public:          /* NOP */      }  private: -    void get(const wax::obj &key, wax::obj &val){ +    void get(const wax::obj &key_, wax::obj &val){ +        named_prop_t key = named_prop_t::extract(key_);          switch(key.as<dsp_prop_t>()){          case DSP_PROP_CODEC_RATE:              val = _codec_rate; @@ -109,11 +110,16 @@ private:              val = _freq_shift;              return; +        case DSP_PROP_FREQ_SHIFT_NAMES: +            val = prop_names_t(1, ""); +            return; +          default: UHD_THROW_PROP_GET_ERROR();          }      } -    void set(const wax::obj &key, const wax::obj &val){ +    void set(const wax::obj &key_, const wax::obj &val){ +        named_prop_t key = named_prop_t::extract(key_);          switch(key.as<dsp_prop_t>()){          case DSP_PROP_FREQ_SHIFT:              _freq_shift = val.as<double>(); @@ -136,12 +142,12 @@ BOOST_AUTO_TEST_CASE(test_tune_helper_rx){      dummy_dsp dsp(100e6);      std::cout << "Testing tune helper RX automatic LO offset" << std::endl; -    tune_result_t tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.3451e9); +    tune_result_t tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0, 2.3451e9);      std::cout << tr.to_pp_string() << std::endl;      BOOST_CHECK_CLOSE(tr.actual_inter_freq, 2.345e9, tolerance);      BOOST_CHECK_CLOSE(tr.actual_dsp_freq, -100e3, tolerance); -    double freq_derived = derive_freq_from_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link()); +    double freq_derived = derive_freq_from_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0);      BOOST_CHECK_CLOSE(freq_derived, 2.3451e9, tolerance);  } @@ -150,12 +156,12 @@ BOOST_AUTO_TEST_CASE(test_tune_helper_tx){      dummy_dsp dsp(100e6);      std::cout << "Testing tune helper TX automatic LO offset" << std::endl; -    tune_result_t tr = tune_tx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.3451e9); +    tune_result_t tr = tune_tx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0, 2.3451e9);      std::cout << tr.to_pp_string() << std::endl;      BOOST_CHECK_CLOSE(tr.actual_inter_freq, 2.345e9, tolerance);      BOOST_CHECK_CLOSE(tr.actual_dsp_freq, 100e3, tolerance); -    double freq_derived = derive_freq_from_tx_subdev_and_dsp(subdev.get_link(), dsp.get_link()); +    double freq_derived = derive_freq_from_tx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0);      BOOST_CHECK_CLOSE(freq_derived, 2.3451e9, tolerance);  } @@ -164,11 +170,11 @@ BOOST_AUTO_TEST_CASE(test_tune_helper_rx_nyquist){      dummy_dsp dsp(100e6);      std::cout << "Testing tune helper RX dummy basic board" << std::endl; -    tune_result_t tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 55e6); +    tune_result_t tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0, 55e6);      std::cout << tr.to_pp_string() << std::endl;      BOOST_CHECK_CLOSE(tr.actual_inter_freq, 0.0, tolerance);      BOOST_CHECK_CLOSE(tr.actual_dsp_freq, 45e6, tolerance); -    double freq_derived = derive_freq_from_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link()); +    double freq_derived = derive_freq_from_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0);      BOOST_CHECK_CLOSE(freq_derived, -45e6, tolerance);  } | 
