diff options
| author | Nick Foster <nick@nerdnetworks.org> | 2010-09-28 17:46:39 -0700 | 
|---|---|---|
| committer | Nick Foster <nick@nerdnetworks.org> | 2010-09-28 17:46:39 -0700 | 
| commit | 450abc5b213fc477ae0f2d648405a8b6a55a7b03 (patch) | |
| tree | 01820d898ecd6541f988378413b4c55f16ebad6d | |
| parent | 7cb95203f8d7173e3d7070d24f68358be67d0b29 (diff) | |
| parent | b70d4430d4a898fe99b54740a1c4821ed9a1077b (diff) | |
| download | uhd-450abc5b213fc477ae0f2d648405a8b6a55a7b03.tar.gz uhd-450abc5b213fc477ae0f2d648405a8b6a55a7b03.tar.bz2 uhd-450abc5b213fc477ae0f2d648405a8b6a55a7b03.zip | |
Merge branch 'master' of ettus.sourcerepo.com:ettus/uhdpriv into tvrx_uhd
48 files changed, 1690 insertions, 1338 deletions
| diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index ceea5d024..566bfd538 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -30,7 +30,7 @@ INCLUDE(${CMAKE_SOURCE_DIR}/config/CPack.cmake)  # Install Dirs  ########################################################################  SET(RUNTIME_DIR bin) -SET(LIBRARY_DIR lib) +SET(LIBRARY_DIR lib${LIB_SUFFIX})  SET(INCLUDE_DIR include)  SET(PKG_DATA_DIR share/uhd)  SET(PKG_DOC_DIR share/doc/uhd) @@ -61,7 +61,9 @@ ENDIF(NOT CMAKE_BUILD_TYPE)  IF(CMAKE_COMPILER_IS_GNUCXX)      ADD_DEFINITIONS(-Wall)      ADD_DEFINITIONS(-Wextra) -    ADD_DEFINITIONS(-pedantic) +    #causes trouble when compiling libusb1.0 on macintosh +    #comment out until mac ports libusb gets its act together +    #ADD_DEFINITIONS(-pedantic)      ADD_DEFINITIONS(-ansi)      #only export symbols that are declared to be part of the uhd api:      UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN) diff --git a/host/docs/build.rst b/host/docs/build.rst index d7dfd05e5..f37b5dce7 100644 --- a/host/docs/build.rst +++ b/host/docs/build.rst @@ -40,7 +40,7 @@ CMake  ^^^^^^^^^^^^^^^^  * **Purpose:** generates project build files  * **Version:** at least 2.8 -* **Required for:** build time +* **Usage:** build time (required)  * **Download URL:** http://www.cmake.org/cmake/resources/software.html  ^^^^^^^^^^^^^^^^ @@ -48,16 +48,16 @@ Boost  ^^^^^^^^^^^^^^^^  * **Purpose:** C++ library  * **Version:** at least 3.6 unix, at least 4.0 windows -* **Required for:** build time + run time +* **Usage:** build time + run time (required)  * **Download URL:** http://www.boost.org/users/download/  * **Download URL (windows installer):** http://www.boostpro.com/download  ^^^^^^^^^^^^^^^^  LibUSB  ^^^^^^^^^^^^^^^^ -* **Purpose:** USB userspace library +* **Purpose:** USB-based hardware support  * **Version:** at least 1.0 -* **Required for:** build time + run time (optional) +* **Usage:** build time + run time (optional)  * **Download URL:** http://www.libusb.org/  ^^^^^^^^^^^^^^^^ @@ -65,7 +65,7 @@ Python  ^^^^^^^^^^^^^^^^  * **Purpose:** used by Cheetah and utility scripts  * **Version:** at least 2.6 -* **Required for:** build time + run time utility scripts +* **Usage:** build time + run time utility scripts (required)  * **Download URL:** http://www.python.org/download/  ^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ Cheetah  ^^^^^^^^^^^^^^^^  * **Purpose:** source code generation  * **Version:** at least 2.0 -* **Required for:** build time +* **Usage:** build time (required)  * **Download URL:** http://www.cheetahtemplate.org/download.html  * **Download URL (windows installer):** http://feisley.com/python/cheetah/ @@ -81,14 +81,14 @@ Cheetah  Doxygen  ^^^^^^^^^^^^^^^^  * **Purpose:** generates html api documentation -* **Required for:** build time (optional) +* **Usage:** build time (optional)  * **Download URL:** http://www.stack.nl/~dimitri/doxygen/download.html#latestsrc  ^^^^^^^^^^^^^^^^  Docutils  ^^^^^^^^^^^^^^^^  * **Purpose:** generates html user manual -* **Required for:** build time (optional) +* **Usage:** build time (optional)  * **Download URL:** http://docutils.sourceforge.net/  ------------------------------------------------------------------------ @@ -105,9 +105,16 @@ Generate Makefiles with cmake      cd build      cmake ../ -**Notes:** +Additionally, configuration variables can be passed into cmake via the command line. +The following common-use configuration variables are listed below: -* For a custom prefix, use: cmake -DCMAKE_INSTALL_PREFIX=<prefix> ../ +* For a custom install prefix: -DCMAKE_INSTALL_PREFIX=<prefix> +* To install libs into lib64: cmake -DLIB_SUFFIX=64 + +Example usage: +:: + +    cmake -DCMAKE_INSTALL_PREFIX=/opt/uhd ../  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  Build and install @@ -155,11 +162,15 @@ Build the project in MSVC  **Note:** you may not have permission to build the install target.  You need to be an administrator or to run MSVC as administrator. -** alternative command line instructions ** +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Build the project in MSVC (command line) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Open the Visual Studio Command Prompt Shorcut: +:: -* Open the Visual Studio Command Prompt Shorcut -* DevEnv <uhd-repo-path>\host\build\ALL_BUILD.vcproj /Build Release -* DevEnv <uhd-repo-path>\host\build\INSTALL.vcproj /Build Release +    cd <uhd-repo-path>\host\build +    DevEnv ALL_BUILD.vcproj /Build Release +    DevEnv INSTALL.vcproj /Build Release  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  Setup the PATH environment variable 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/docs/usrp2.rst b/host/docs/usrp2.rst index 745361b77..72a919d1a 100644 --- a/host/docs/usrp2.rst +++ b/host/docs/usrp2.rst @@ -174,7 +174,7 @@ buffer incoming samples faster than they can be processed.  However, if you application cannot process samples fast enough,  no amount of buffering can save you. -By default, the UHD will try to request a reasonably large buffer size for both send and receive. +By default, the UHD will try to resize both the send and receive buffer for optimum performance.  A warning will be printed on instantiation if the actual buffer size is insufficient.  See the OS specific notes below: @@ -211,6 +211,20 @@ Hardware setup notes  ------------------------------------------------------------------------  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Front panel LEDs +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The LEDs on the front panel can be useful in debugging hardware and software issues. +The LEDs reveal the following about the state of the device: + +* **LED A:** transmitting +* **LED B:** undocumented +* **LED C:** receiving +* **LED D:** firmware loaded +* **LED E:** undocumented +* **LED F:** FPGA loaded + + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  Ref Clock - 10MHz  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  Using an external 10MHz reference clock requires a signal level between 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..0a5c076ea 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; @@ -58,7 +58,7 @@ void test_no_async_message(uhd::usrp::simple_usrp::sptr sdev){              "    Got unexpected event code 0x%x.\n"          ) % async_md.event_code << std::endl;          //clear the async messages -        while (dev->recv_async_msg(async_md, 0)); +        while (dev->recv_async_msg(async_md, 0)){};      }      else{          std::cout << boost::format( @@ -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..4b2bb62a3 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> @@ -31,13 +31,13 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      //variables to be set by po      std::string args; -    float seconds; +    double seconds;      //setup the program options      po::options_description desc("Allowed options");      desc.add_options()          ("help", "help message") -        ("args", po::value<std::string>(&args)->default_value(""), "simple uhd device address args") +        ("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; @@ -60,20 +60,20 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      std::cout << "Set time to known value (100.0) without regard to pps:" << std::endl;      sdev->set_time_now(uhd::time_spec_t(100.0));      boost::this_thread::sleep(boost::posix_time::seconds(1)); -    std::cout << boost::format("Reading time 1 second later: %f\n") % (sdev->get_time_now().get_full_secs()) << std::endl; +    std::cout << boost::format("Reading time 1 second later: %f\n") % (sdev->get_time_now().get_real_secs()) << std::endl;      //store the time to see if PPS resets it -    seconds = sdev->get_time_now().get_full_secs(); +    seconds = sdev->get_time_now().get_real_secs();      //set a known time at next PPS, check that time increments      uhd::time_spec_t time_spec = uhd::time_spec_t(0.0);      std::cout << "Set time to known value (0.0) at next pps:" << std::endl;      sdev->set_time_next_pps(time_spec);      boost::this_thread::sleep(boost::posix_time::seconds(1)); -    std::cout << boost::format("Reading time 1 second later: %f\n") % (sdev->get_time_now().get_full_secs()) << std::endl; +    std::cout << boost::format("Reading time 1 second later: %f\n") % (sdev->get_time_now().get_real_secs()) << std::endl;      //finished -    if (seconds > sdev->get_time_now().get_full_secs()){ +    if (seconds > sdev->get_time_now().get_real_secs()){          std::cout << std::endl << "Success!" << std::endl << std::endl;          return 0;      } else { 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/transport/usb_device_handle.hpp b/host/include/uhd/transport/usb_device_handle.hpp index c3eb72b00..9bb7db9c4 100644 --- a/host/include/uhd/transport/usb_device_handle.hpp +++ b/host/include/uhd/transport/usb_device_handle.hpp @@ -38,7 +38,7 @@ namespace uhd { namespace transport {   *       a true descriptor serial number string. This interface returns the   *       actual string descriptor.   */ -class UHD_API usb_device_handle : boost::noncopyable { +class usb_device_handle : boost::noncopyable {  public:      typedef boost::shared_ptr<usb_device_handle> sptr; @@ -46,31 +46,25 @@ public:       * Return the device's serial number        * \return a string describing the device's serial number       */ -    virtual UHD_API std::string get_serial() const = 0; +    virtual std::string get_serial() const = 0;      /*!       * Return the device's Vendor ID (usually assigned by the USB-IF)       * \return a Vendor ID       */ -    virtual UHD_API boost::uint16_t get_vendor_id() const = 0; +    virtual boost::uint16_t get_vendor_id() const = 0;      /*!       * Return the device's Product ID (usually assigned by manufacturer)       * \return a Product ID       */ -    virtual UHD_API boost::uint16_t get_product_id() const = 0; - -    /*! -     * Return the device's USB address -     * \return a Product ID -     */ -    virtual UHD_API boost::uint16_t get_device_addr() const = 0; +    virtual boost::uint16_t get_product_id() const = 0;      /*!       * Return a vector of USB devices on this host        * \return a vector of USB device handles that match vid and pid       */ -    static UHD_API std::vector<usb_device_handle::sptr> get_device_list(boost::uint16_t vid, boost::uint16_t pid); +    static std::vector<usb_device_handle::sptr> get_device_list(boost::uint16_t vid, boost::uint16_t pid);  }; //namespace usb diff --git a/host/include/uhd/transport/usb_zero_copy.hpp b/host/include/uhd/transport/usb_zero_copy.hpp index 2edd6d91d..75232c22a 100644 --- a/host/include/uhd/transport/usb_zero_copy.hpp +++ b/host/include/uhd/transport/usb_zero_copy.hpp @@ -53,7 +53,7 @@ public:      static sptr make(usb_device_handle::sptr handle,                       unsigned int rx_endpoint,                       unsigned int tx_endpoint, -		     size_t buff_size = 0,  +                     size_t buff_size = 0,                       size_t block_size = 0);  }; 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/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index 71a3a1494..61616d077 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -30,8 +30,11 @@ IF(LIBUSB_FOUND)          ${CMAKE_SOURCE_DIR}/lib/transport/libusb1_control.cpp          ${CMAKE_SOURCE_DIR}/lib/transport/libusb1_zero_copy.cpp          ${CMAKE_SOURCE_DIR}/lib/transport/libusb1_base.cpp -        ${CMAKE_SOURCE_DIR}/lib/transport/libusb1_device_handle.cpp +        ${CMAKE_SOURCE_DIR}/lib/transport/libusb1_base.hpp      ) +    IF(MSVC) #include our custom stdint for libusb +        INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/transport/msvc) +    ENDIF(MSVC)      SET(HAVE_USB_SUPPORT TRUE)  ENDIF(LIBUSB_FOUND) 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/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp index e21c39aa3..26e864459 100644 --- a/host/lib/transport/libusb1_base.cpp +++ b/host/lib/transport/libusb1_base.cpp @@ -17,110 +17,258 @@  #include "libusb1_base.hpp"  #include <uhd/utils/assert.hpp> +#include <uhd/types/dict.hpp> +#include <boost/weak_ptr.hpp> +#include <boost/foreach.hpp> +#include <boost/thread.hpp>  #include <iostream>  using namespace uhd::transport; -/********************************************************** - * Helper Methods - **********************************************************/ +/*********************************************************************** + * libusb session + **********************************************************************/ +class libusb_session_impl : public libusb::session{ +public: +    libusb_session_impl(void){ +        UHD_ASSERT_THROW(libusb_init(&_context) == 0); +        libusb_set_debug(_context, debug_level); +        _thread_group.create_thread(boost::bind(&libusb_session_impl::run_event_loop, this)); +    } -/********************************************************** - * libusb namespace  - **********************************************************/ -void libusb::init(libusb_context **ctx, int debug_level) -{ -    if (libusb_init(ctx) < 0) -        std::cerr << "error: libusb_init" << std::endl; +    ~libusb_session_impl(void){ +        _running = false; +        _thread_group.join_all(); +        libusb_exit(_context); +    } -    libusb_set_debug(*ctx, debug_level); -} +    libusb_context *get_context(void) const{ +        return _context; +    } -libusb_device_handle *libusb::open_device(libusb_context *ctx, -                                          usb_device_handle::sptr handle) -{ -    libusb_device_handle *dev_handle = NULL; -    libusb_device **libusb_dev_list; -    size_t dev_cnt = libusb_get_device_list(ctx, &libusb_dev_list); - -    //find and open the USB device  -    for (size_t i = 0; i < dev_cnt; i++) { -        libusb_device *dev = libusb_dev_list[i]; - -        if (compare_device(dev, handle)) { -            libusb_open(dev, &dev_handle); -            libusb_unref_device(dev); -            break; +private: +    libusb_context *_context; +    boost::thread_group _thread_group; +    bool _running; + +    void run_event_loop(void){ +        _running = true; +        timeval tv; +        while(_running){ +            tv.tv_sec = 0; +            tv.tv_usec = 100000; //100ms +            libusb_handle_events_timeout(this->get_context(), &tv);          } -             -        libusb_unref_device(dev);      } +}; + +libusb::session::sptr libusb::session::get_global_session(void){ +    static boost::weak_ptr<session> global_session; + +    //not expired -> get existing session +    if (not global_session.expired()) return global_session.lock(); -    return dev_handle; +    //create a new global session +    sptr new_global_session(new libusb_session_impl()); +    global_session = new_global_session; +    return new_global_session;  } -//note: changed order of checks so it only tries to get_serial and get_device_address if vid and pid match -//doing this so it doesn't try to open the device if it's not ours -bool libusb::compare_device(libusb_device *dev, -                            usb_device_handle::sptr handle) -{ -    std::string serial         = handle->get_serial(); -    boost::uint16_t vendor_id  = handle->get_vendor_id(); -    boost::uint16_t product_id = handle->get_product_id(); -    boost::uint8_t device_addr = handle->get_device_addr(); - -    libusb_device_descriptor libusb_desc; -    if (libusb_get_device_descriptor(dev, &libusb_desc) < 0) -        return false; -    if (vendor_id != libusb_desc.idVendor) -        return false; -    if (product_id != libusb_desc.idProduct) -        return false;  -    if (serial != get_serial(dev)) -        return false; -    if (device_addr != libusb_get_device_address(dev)) -        return false; - -    return true; +/*********************************************************************** + * libusb device + **********************************************************************/ +class libusb_device_impl : public libusb::device{ +public: +    libusb_device_impl(libusb_device *dev){ +        _session = libusb::session::get_global_session(); +        _dev = dev; +    } + +    ~libusb_device_impl(void){ +        libusb_unref_device(this->get()); +    } + +    libusb_device *get(void) const{ +        return _dev; +    } + +private: +    libusb::session::sptr _session; //always keep a reference to session +    libusb_device *_dev; +}; + +/*********************************************************************** + * libusb device list + **********************************************************************/ +class libusb_device_list_impl : public libusb::device_list{ +public: +    libusb_device_list_impl(void){ +        libusb::session::sptr sess = libusb::session::get_global_session(); + +        //allocate a new list of devices +        libusb_device** dev_list; +        ssize_t ret = libusb_get_device_list(sess->get_context(), &dev_list); +        if (ret < 0) throw std::runtime_error("cannot enumerate usb devices"); + +        //fill the vector of device references +        for (size_t i = 0; i < size_t(ret); i++) _devs.push_back( +            libusb::device::sptr(new libusb_device_impl(dev_list[i])) +        ); + +        //free the device list but dont unref (done in ~device) +        libusb_free_device_list(dev_list, false/*dont unref*/); +    } + +    size_t size(void) const{ +        return _devs.size(); +    } + +    libusb::device::sptr at(size_t i) const{ +        return _devs.at(i); +    } + +private: +    std::vector<libusb::device::sptr> _devs; +}; + +libusb::device_list::sptr libusb::device_list::make(void){ +    return sptr(new libusb_device_list_impl());  } +/*********************************************************************** + * libusb device descriptor + **********************************************************************/ +class libusb_device_descriptor_impl : public libusb::device_descriptor{ +public: +    libusb_device_descriptor_impl(libusb::device::sptr dev){ +        _dev = dev; +        UHD_ASSERT_THROW(libusb_get_device_descriptor(_dev->get(), &_desc) == 0); +    } -bool libusb::open_interface(libusb_device_handle *dev_handle, -                            int interface) -{ -    int ret = libusb_claim_interface(dev_handle, interface); -    if (ret < 0) { -        std::cerr << "error: libusb_claim_interface() " << ret << std::endl; -        return false; +    const libusb_device_descriptor &get(void) const{ +        return _desc;      } -    else { -        return true; + +    std::string get_ascii_serial(void) const{ +        if (this->get().iSerialNumber == 0) return ""; + +        libusb::device_handle::sptr handle( +            libusb::device_handle::get_cached_handle(_dev) +        ); + +        unsigned char buff[512]; +        ssize_t ret = libusb_get_string_descriptor_ascii( +            handle->get(), this->get().iSerialNumber, buff, sizeof(buff) +        ); +        if (ret < 0) return ""; //on error, just return empty string + +        return std::string((char *)buff, ret);      } + +private: +    libusb::device::sptr _dev; //always keep a reference to device +    libusb_device_descriptor _desc; +}; + +libusb::device_descriptor::sptr libusb::device_descriptor::make(device::sptr dev){ +    return sptr(new libusb_device_descriptor_impl(dev));  } +/*********************************************************************** + * libusb device handle + **********************************************************************/ +class libusb_device_handle_impl : public libusb::device_handle{ +public: +    libusb_device_handle_impl(libusb::device::sptr dev){ +        _dev = dev; +        UHD_ASSERT_THROW(libusb_open(_dev->get(), &_handle) == 0); +    } + +    ~libusb_device_handle_impl(void){ +        //release all claimed interfaces +        for (size_t i = 0; i < _claimed.size(); i++){ +            libusb_release_interface(this->get(), _claimed[i]); +        } +        libusb_close(_handle); +    } + +    libusb_device_handle *get(void) const{ +        return _handle; +    } -std::string libusb::get_serial(libusb_device *dev) -{ -    unsigned char buff[32]; +    void claim_interface(int interface){ +        UHD_ASSERT_THROW(libusb_claim_interface(this->get(), interface) == 0); +        _claimed.push_back(interface); +    } -    libusb_device_descriptor desc; -    if (libusb_get_device_descriptor(dev, &desc) < 0) -        return ""; +private: +    libusb::device::sptr _dev; //always keep a reference to device +    libusb_device_handle *_handle; +    std::vector<int> _claimed; +}; -    if (desc.iSerialNumber == 0) -        return ""; +libusb::device_handle::sptr libusb::device_handle::get_cached_handle(device::sptr dev){ +    static uhd::dict<libusb_device *, boost::weak_ptr<device_handle> > handles; -    //open the device because we have to -    libusb_device_handle *dev_handle; -    if (libusb_open(dev, &dev_handle) < 0) -        return ""; +    //not expired -> get existing session +    if (handles.has_key(dev->get()) and not handles[dev->get()].expired()){ +        return handles[dev->get()].lock(); +    } -    if (libusb_get_string_descriptor_ascii(dev_handle, desc.iSerialNumber, -                                           buff, sizeof(buff)) < 0) { -        return ""; +    //create a new global session +    sptr new_handle(new libusb_device_handle_impl(dev)); +    handles[dev->get()] = new_handle; +    return new_handle; +} + +/*********************************************************************** + * libusb special handle + **********************************************************************/ +class libusb_special_handle_impl : public libusb::special_handle{ +public: +    libusb_special_handle_impl(libusb::device::sptr dev){ +        _dev = dev;      } -    libusb_close(dev_handle); +    libusb::device::sptr get_device(void) const{ +        return _dev; +    } + +    std::string get_serial(void) const{ +        return libusb::device_descriptor::make(this->get_device())->get_ascii_serial(); +    } + +    boost::uint16_t get_vendor_id(void) const{ +        return libusb::device_descriptor::make(this->get_device())->get().idVendor; +    } + +    boost::uint16_t get_product_id(void) const{ +        return libusb::device_descriptor::make(this->get_device())->get().idProduct; +    } + +private: +    libusb::device::sptr _dev; //always keep a reference to device +}; + +libusb::special_handle::sptr libusb::special_handle::make(device::sptr dev){ +    return sptr(new libusb_special_handle_impl(dev)); +} + +/*********************************************************************** + * list device handles implementations + **********************************************************************/ +std::vector<usb_device_handle::sptr> usb_device_handle::get_device_list( +    boost::uint16_t vid, boost::uint16_t pid +){ +    std::vector<usb_device_handle::sptr> handles; + +    libusb::device_list::sptr dev_list = libusb::device_list::make(); +    for (size_t i = 0; i < dev_list->size(); i++){ +        usb_device_handle::sptr handle = libusb::special_handle::make(dev_list->at(i)); +        if (handle->get_vendor_id() == vid and handle->get_product_id() == pid){ +            handles.push_back(handle); +        } +    } -    return (char*) buff; +    return handles;  } diff --git a/host/lib/transport/libusb1_base.hpp b/host/lib/transport/libusb1_base.hpp index abe5e22a2..04c1d6574 100644 --- a/host/lib/transport/libusb1_base.hpp +++ b/host/lib/transport/libusb1_base.hpp @@ -15,80 +15,135 @@  // along with this program.  If not, see <http://www.gnu.org/licenses/>.  // -#ifndef INCLUDED_TRANSPORT_LIBUSB_HPP -#define INCLUDED_TRANSPORT_LIBUSB_HPP +#ifndef INCLUDED_LIBUHD_TRANSPORT_LIBUSB_HPP +#define INCLUDED_LIBUHD_TRANSPORT_LIBUSB_HPP  #include <uhd/config.hpp> +#include <boost/utility.hpp> +#include <boost/shared_ptr.hpp>  #include <uhd/transport/usb_device_handle.hpp> -#include <libusb-1.0/libusb.h> +#include <libusb.h> +/*********************************************************************** + * Libusb object oriented smart pointer wrappers: + * The following wrappers provide allocation and automatic deallocation + * for various libusb data types and handles. The construction routines + * also store tables of already allocated structures to avoid multiple + * occurrences of opened handles (for example). + **********************************************************************/  namespace uhd { namespace transport {  namespace libusb { -    /* -     * Initialize libusb and set debug level -     * Takes a pointer to context pointer because that's -     * how libusb rolls. Debug levels. -     *      -     *   Level 0: no messages ever printed by the library (default) -     *   Level 1: error messages are printed to stderr -     *   Level 2: warning and error messages are printed to stderr -     *   Level 3: informational messages are printed to stdout, warning -     *            and error messages are printed to stderr -     * -     * \param ctx pointer to context pointer -     * \param debug_level + +    /*! +     * This session class holds a global libusb context for this process. +     * The get global session call will create a new context if none exists. +     * When all references to session are destroyed, the context will be freed.       */ -    void init(libusb_context **ctx, int debug_level); - -    /* -     * Open the device specified by a generic handle -     * Find the libusb_device cooresponding to the generic handle -     * and open it for I/O, which returns a libusb_device_handle -     * ready for an interface -     * \param ctx the libusb context used for init -     * \return a libusb_device_handle ready for action  +    class session : boost::noncopyable { +    public: +        typedef boost::shared_ptr<session> sptr; + +        /*! +         *   Level 0: no messages ever printed by the library (default) +         *   Level 1: error messages are printed to stderr +         *   Level 2: warning and error messages are printed to stderr +         *   Level 3: informational messages are printed to stdout, warning +         *            and error messages are printed to stderr +         */ +        static const int debug_level = 0; + +        //! get a shared pointer to the global session +        static sptr get_global_session(void); + +        //! get the underlying libusb context pointer +        virtual libusb_context *get_context(void) const = 0; +    }; + +    /*! +     * Holds a device pointer with a reference to the session.       */ -    libusb_device_handle *open_device(libusb_context *ctx, -                                      usb_device_handle::sptr handle); - -    /* -     * Compare a libusb device with a generic handle  -     * Check the descriptors and open the device to check the -     * serial number string. Compare values against the given -     * handle. The libusb context is already implied in the -     * libusb_device. -     * \param dev a libusb_device pointer -     * \param handle a generic handle specifier -     * \return true if handle and device match, false otherwise +    class device : boost::noncopyable { +    public: +        typedef boost::shared_ptr<device> sptr; + +        //! get the underlying device pointer +        virtual libusb_device *get(void) const = 0; +    }; + +    /*! +     * This device list class holds a device list that will be +     * automatically freed when the last reference is destroyed.       */ -    bool compare_device(libusb_device *dev, usb_device_handle::sptr handle); - -    /* -     * Open an interface to the device -     * This is a logical operation for operating system housekeeping as -     * nothing is sent over the bus. The interface much correspond -     * to the USB device descriptors. -     * \param dev_handle libusb handle to an opened device -     * \param interface integer of the interface to use -     * \return true on success, false on error +    class device_list : boost::noncopyable { +    public: +        typedef boost::shared_ptr<device_list> sptr; + +        //! make a new device list +        static sptr make(void); + +        //! the number of devices in this list +        virtual size_t size() const = 0; + +        //! get the device pointer at a particular index +        virtual device::sptr at(size_t index) const = 0; +    }; + +    /*! +     * Holds a device descriptor and a reference to the device.       */ -    bool open_interface(libusb_device_handle *dev_handle, int interface); - -    /* -     * Get serial number  -     * The standard USB device descriptor contains an index to an -     * actual serial number string descriptor. The index is readily -     * readble, but the string descriptor requires probing the device. -     * Because this call attempts to open the device, it may not -     * succeed because not all USB devices are readily opened. -     * The default language is used for the request (English). -     * \param dev a libusb_device pointer -     * \return string serial number or 0 on error or unavailablity +    class device_descriptor : boost::noncopyable { +    public: +        typedef boost::shared_ptr<device_descriptor> sptr; + +        //! make a new descriptor from a device reference +        static sptr make(device::sptr); + +        //! get the underlying device descriptor +        virtual const libusb_device_descriptor &get(void) const = 0; + +        virtual std::string get_ascii_serial(void) const = 0; +    }; + +    /*! +     * Holds a device handle and a reference to the device.       */ -    std::string get_serial(libusb_device *dev); +    class device_handle : boost::noncopyable { +    public: +        typedef boost::shared_ptr<device_handle> sptr; + +        //! get a cached handle or make a new one given the device +        static sptr get_cached_handle(device::sptr); + +        //! get the underlying device handle +        virtual libusb_device_handle *get(void) const = 0; + +        /*! +         * Open USB interfaces for control using magic value +         * IN interface:      2 +         * OUT interface:     1 +         * Control interface: 0 +         */ +        virtual void claim_interface(int) = 0; +    }; + +    /*! +     * The special handle is our internal implementation of the +     * usb device handle which is used publicly to identify a device. +     */ +    class special_handle : public usb_device_handle { +    public: +        typedef boost::shared_ptr<special_handle> sptr; + +        //! make a new special handle from device +        static sptr make(device::sptr); + +        //! get the underlying device reference +        virtual device::sptr get_device(void) const = 0; +    }; +  }  }} //namespace -#endif /* INCLUDED_TRANSPORT_LIBUSB_HPP */ +#endif /* INCLUDED_LIBUHD_TRANSPORT_LIBUSB_HPP */ diff --git a/host/lib/transport/libusb1_control.cpp b/host/lib/transport/libusb1_control.cpp index 3531128b2..c989a788c 100644 --- a/host/lib/transport/libusb1_control.cpp +++ b/host/lib/transport/libusb1_control.cpp @@ -20,7 +20,6 @@  using namespace uhd::transport; -const int libusb_debug_level = 0;  const int libusb_timeout = 0;  /*********************************************************************** @@ -28,68 +27,38 @@ const int libusb_timeout = 0;   **********************************************************************/  class libusb_control_impl : public usb_control {  public: -    libusb_control_impl(usb_device_handle::sptr handle); -    ~libusb_control_impl(); +    libusb_control_impl(libusb::device_handle::sptr handle): +        _handle(handle) +    { +        _handle->claim_interface(0 /* control interface */); +    }      size_t submit(boost::uint8_t request_type,                    boost::uint8_t request,                    boost::uint16_t value,                    boost::uint16_t index,                    unsigned char *buff, -                  boost::uint16_t length);  +                  boost::uint16_t length +    ){ +        return libusb_control_transfer(_handle->get(), +                                       request_type, +                                       request, +                                       value, +                                       index, +                                       buff, +                                       length, +                                       libusb_timeout); +    }  private: -    libusb_context       *_ctx; -    libusb_device_handle *_dev_handle; +    libusb::device_handle::sptr _handle;  }; - -libusb_control_impl::libusb_control_impl(usb_device_handle::sptr handle) -{ -    libusb::init(&_ctx, libusb_debug_level); - -    // Find and open the libusb_device corresponding to the -    // given handle and return the libusb_device_handle -    // that can be used for I/O purposes. -    _dev_handle = libusb::open_device(_ctx, handle); - -    // Open USB interfaces for control using magic value -    // IN interface:      2 -    // OUT interface:     1 -    // Control interface: 0 -    libusb::open_interface(_dev_handle, 0); -} - - -libusb_control_impl::~libusb_control_impl() -{ -    libusb_close(_dev_handle); -    libusb_exit(_ctx); -} - - -size_t libusb_control_impl::submit(boost::uint8_t request_type, -                                   boost::uint8_t request, -                                   boost::uint16_t value, -                                   boost::uint16_t index,  -                                   unsigned char *buff, -                                   boost::uint16_t length)  -{ -    return libusb_control_transfer(_dev_handle, -                                   request_type, -                                   request, -                                   value, -                                   index, -                                   buff,  -                                   length,  -                                   libusb_timeout); -} - -  /***********************************************************************   * USB control public make functions   **********************************************************************/ -usb_control::sptr usb_control::make(usb_device_handle::sptr handle) -{ -    return sptr(new libusb_control_impl(handle)); +usb_control::sptr usb_control::make(usb_device_handle::sptr handle){ +    return sptr(new libusb_control_impl(libusb::device_handle::get_cached_handle( +        boost::static_pointer_cast<libusb::special_handle>(handle)->get_device() +    )));  } diff --git a/host/lib/transport/libusb1_device_handle.cpp b/host/lib/transport/libusb1_device_handle.cpp deleted file mode 100644 index 43d0f0e26..000000000 --- a/host/lib/transport/libusb1_device_handle.cpp +++ /dev/null @@ -1,117 +0,0 @@ -// -// 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 "libusb1_base.hpp" -#include <uhd/utils/assert.hpp> -#include <iostream> - -using namespace uhd::transport; - -const int libusb_debug_level = 0; - -/**************************************************************** - * libusb USB device handle implementation class - ***************************************************************/ -class libusb1_device_handle_impl : public usb_device_handle { -public: -    libusb1_device_handle_impl(std::string serial, -                               boost::uint32_t product_id, -                               boost::uint32_t vendor_id, -                               boost::uint32_t device_addr) -      : _serial(serial), _product_id(product_id),  -        _vendor_id(vendor_id), _device_addr(device_addr) -    { -        /* NOP */ -    } - -    ~libusb1_device_handle_impl() -    { -        /* NOP */ -    } - -    std::string get_serial() const -    { -        return _serial; -    } - -    boost::uint16_t get_vendor_id() const -    { -        return _vendor_id; -    } - - -    boost::uint16_t get_product_id() const -    { -        return _product_id; -    } - -    boost::uint16_t get_device_addr() const -    { -        return _device_addr; -    } - -private: -    std::string     _serial; -    boost::uint32_t _product_id; -    boost::uint32_t _vendor_id; -    boost::uint32_t _device_addr; -}; - - -usb_device_handle::sptr make_usb_device_handle(libusb_device *dev) -{ -    libusb_device_descriptor desc; - -    if (libusb_get_device_descriptor(dev, &desc) < 0) { -        UHD_ASSERT_THROW("USB: failed to get device descriptor"); -    } - -    std::string     serial      = libusb::get_serial(dev); -    boost::uint32_t product_id  = desc.idProduct; -    boost::uint32_t vendor_id   = desc.idVendor; -    boost::uint32_t device_addr = libusb_get_device_address(dev); - -    return usb_device_handle::sptr(new libusb1_device_handle_impl( -        serial, -        product_id, -        vendor_id, -        device_addr)); -} - -std::vector<usb_device_handle::sptr> usb_device_handle::get_device_list(boost::uint16_t vid, boost::uint16_t pid) -{ -    libusb_context *ctx = NULL; -    libusb_device** libusb_device_list; -    std::vector<usb_device_handle::sptr> device_handle_list; -    libusb_device_descriptor desc; - -    libusb::init(&ctx, libusb_debug_level); - -    size_t dev_size = libusb_get_device_list(ctx, &libusb_device_list); -    for (size_t i = 0; i < dev_size; i++) { -        libusb_device *dev = libusb_device_list[i]; -        if(libusb_get_device_descriptor(dev, &desc) < 0) { -          UHD_ASSERT_THROW("USB: failed to get device descriptor"); -        } -        if(desc.idVendor == vid && desc.idProduct == pid) { -          device_handle_list.push_back(make_usb_device_handle(dev)); -        } -    } - -    libusb_exit(ctx); -    return device_handle_list;  -} diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index b890a87f9..b089d11e0 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -17,15 +17,17 @@  #include "libusb1_base.hpp"  #include <uhd/transport/usb_zero_copy.hpp> +#include <uhd/transport/bounded_buffer.hpp>  #include <uhd/utils/assert.hpp> -#include <boost/asio.hpp> -#include <boost/format.hpp> +#include <boost/shared_array.hpp> +#include <boost/foreach.hpp> +#include <boost/thread.hpp> +#include <vector>  #include <iostream>  #include <iomanip>  using namespace uhd::transport; -const int libusb_debug_level = 0;  const int libusb_timeout = 0;  /*********************************************************************** @@ -57,53 +59,57 @@ void pp_transfer(libusb_transfer *lut)   *   interface provided by the kernel.    **********************************************************************/  class usb_endpoint { +public: +    typedef boost::shared_ptr<usb_endpoint> sptr; + +    usb_endpoint( +        libusb::device_handle::sptr handle, +        int endpoint, +        bool input, +        size_t transfer_size, +        size_t num_transfers +    ); + +    ~usb_endpoint(void); + +    // Exposed interface for submitting / retrieving transfer buffers + +    //! Submit a new transfer that was presumably just filled or emptied. +    void submit(libusb_transfer *lut); + +    /*! +     * Get an available transfer: +     * For inputs, this is a just filled transfer. +     * For outputs, this is a just emptied transfer. +     * \param timeout_ms the timeout to wait for a lut +     * \return the transfer pointer or NULL if timeout +     */ +    libusb_transfer *get_lut_with_wait(size_t timeout_ms = 100); + +    //Callback use only +    void callback_handle_transfer(libusb_transfer *lut); +  private: -    libusb_device_handle *_dev_handle; -    libusb_context *_ctx; +    libusb::device_handle::sptr _handle;      int  _endpoint;      bool _input;      size_t _transfer_size;      size_t _num_transfers; -    // Transfer state lists (transfers are free, pending, or completed) -    std::list<libusb_transfer *>  _free_list; -    std::list<libusb_transfer *>  _pending_list; -    std::list<libusb_transfer *>  _completed_list; +    //! hold a bounded buffer of completed transfers +    typedef bounded_buffer<libusb_transfer *> lut_buff_type; +    lut_buff_type::sptr _completed_list; + +    //! a list of all transfer structs we allocated +    std::vector<libusb_transfer *>  _all_luts; + +    //! a list of shared arrays for the transfer buffers +    std::vector<boost::shared_array<boost::uint8_t> > _buffers;      // Calls for processing asynchronous I/O       libusb_transfer *allocate_transfer(int buff_len); -    bool cancel(libusb_transfer *lut); -    bool cancel_all(); -    bool reap_pending_list(); -    bool reap_pending_list_timeout(); -    bool reap_completed_list(); - -    // Transfer state manipulators  -    void free_list_add(libusb_transfer *lut); -    void pending_list_add(libusb_transfer *lut); -    void completed_list_add(libusb_transfer *lut); -    libusb_transfer *free_list_get(); -    libusb_transfer *completed_list_get(); -    bool pending_list_remove(libusb_transfer *lut); - -    // Debug use      void print_transfer_status(libusb_transfer *lut); - -public: -    usb_endpoint(libusb_device_handle *dev_handle, -                 libusb_context *ctx, int endpoint, bool input, -                 size_t transfer_size, size_t num_transfers); - -    ~usb_endpoint(); - -    // Exposed interface for submitting / retrieving transfer buffers -    bool submit(libusb_transfer *lut); -    libusb_transfer *get_completed_transfer(); -    libusb_transfer *get_free_transfer(); - -    //Callback use only -    void callback_handle_transfer(libusb_transfer *lut);  }; @@ -116,9 +122,8 @@ public:   * it from the pending to completed status list.   * \param lut pointer to libusb_transfer   */ -static void callback(libusb_transfer *lut) -{ -    usb_endpoint *endpoint = (usb_endpoint *) lut->user_data;  +static void callback(libusb_transfer *lut){ +    usb_endpoint *endpoint = (usb_endpoint *) lut->user_data;      endpoint->callback_handle_transfer(lut);  } @@ -127,14 +132,9 @@ static void callback(libusb_transfer *lut)   * Accessor call to allow list access from callback space   * \param pointer to libusb_transfer   */ -void usb_endpoint::callback_handle_transfer(libusb_transfer *lut) -{ -    if (!pending_list_remove(lut)) { -        std::cerr << "USB: pending remove failed" << std::endl; -        return; -    } - -    completed_list_add(lut);     +void usb_endpoint::callback_handle_transfer(libusb_transfer *lut){ +    boost::this_thread::disable_interruption di; //disable because the wait can throw +    _completed_list->push_with_wait(lut);  } @@ -144,19 +144,28 @@ void usb_endpoint::callback_handle_transfer(libusb_transfer *lut)   * submit the transfers so that they're ready to return when   * data is available.    */ -usb_endpoint::usb_endpoint(libusb_device_handle *dev_handle, -                          libusb_context *ctx, int endpoint, bool input, -                          size_t transfer_size, size_t num_transfers) -    : _dev_handle(dev_handle), -      _ctx(ctx), _endpoint(endpoint), _input(input), -      _transfer_size(transfer_size), _num_transfers(num_transfers) +usb_endpoint::usb_endpoint( +    libusb::device_handle::sptr handle, +    int endpoint, +    bool input, +    size_t transfer_size, +    size_t num_transfers +): +    _handle(handle), +    _endpoint(endpoint), +    _input(input), +    _transfer_size(transfer_size), +    _num_transfers(num_transfers)  { -    unsigned int i; -    for (i = 0; i < _num_transfers; i++) { -        free_list_add(allocate_transfer(_transfer_size)); +    _completed_list = lut_buff_type::make(num_transfers); -        if (_input) -            submit(free_list_get()); +    for (size_t i = 0; i < _num_transfers; i++){ +        _all_luts.push_back(allocate_transfer(_transfer_size)); + +        //input luts are immediately submitted to be filled +        //output luts go into the completed list as free buffers +        if (_input) this->submit(_all_luts.back()); +        else _completed_list->push_with_wait(_all_luts.back());      }  } @@ -168,22 +177,18 @@ usb_endpoint::usb_endpoint(libusb_device_handle *dev_handle,   * the transfers. Libusb will deallocate the data buffer held by   * each transfer.   */ -usb_endpoint::~usb_endpoint() -{ -    cancel_all(); - -    while (!_pending_list.empty()) { -        if (!reap_pending_list()) -            std::cerr << "error: destructor failed to reap" << std::endl; +usb_endpoint::~usb_endpoint(void){ +    //cancel all transfers +    BOOST_FOREACH(libusb_transfer *lut, _all_luts){ +        libusb_cancel_transfer(lut);      } -    while (!_completed_list.empty()) { -        if (!reap_completed_list()) -            std::cerr << "error: destructor failed to reap" << std::endl; -    } +    //collect canceled transfers (drain the queue) +    while (this->get_lut_with_wait() != NULL){}; -    while (!_free_list.empty()) { -        libusb_free_transfer(free_list_get()); +    //free all transfers +    BOOST_FOREACH(libusb_transfer *lut, _all_luts){ +        libusb_free_transfer(lut);      }  } @@ -195,20 +200,21 @@ usb_endpoint::~usb_endpoint()   * \param buff_len size of the individual buffer held by each transfer   * \return pointer to an allocated libusb_transfer   */ -libusb_transfer *usb_endpoint::allocate_transfer(int buff_len) -{ +libusb_transfer *usb_endpoint::allocate_transfer(int buff_len){      libusb_transfer *lut = libusb_alloc_transfer(0); -    unsigned char *buff = new unsigned char[buff_len]; +    boost::shared_array<boost::uint8_t> buff(new boost::uint8_t[buff_len]); +    _buffers.push_back(buff); //store a reference to this shared array      unsigned int endpoint = ((_endpoint & 0x7f) | (_input ? 0x80 : 0)); +    libusb_transfer_cb_fn lut_callback = libusb_transfer_cb_fn(&callback);      libusb_fill_bulk_transfer(lut,                // transfer -                              _dev_handle,        // dev_handle +                              _handle->get(),     // dev_handle                                endpoint,           // endpoint -                              buff,               // buffer +                              buff.get(),         // buffer                                buff_len,           // length -                              callback,           // callback +                              lut_callback,       // callback                                this,               // user_data                                0);                 // timeout      return lut; @@ -221,95 +227,15 @@ libusb_transfer *usb_endpoint::allocate_transfer(int buff_len)   * \param lut pointer to libusb_transfer   * \return true on success or false on error    */ -bool usb_endpoint::submit(libusb_transfer *lut) -{ -    int retval; -    if ((retval = libusb_submit_transfer(lut)) < 0) { -        std::cerr << "error: libusb_submit_transfer: " << retval << std::endl; -        return false; -    } - -    pending_list_add(lut); -    return true; +void usb_endpoint::submit(libusb_transfer *lut){ +    UHD_ASSERT_THROW(libusb_submit_transfer(lut) == 0);  } - -/* - * Cancel a pending transfer  - * Search the pending list for the transfer and cancel if found. - * \param lut pointer to libusb_transfer to cancel - * \return true on success or false if transfer is not found - * - * Note: success only indicates submission of cancelation request. - * Sucessful cancelation is not known until the callback occurs. - */ -bool usb_endpoint::cancel(libusb_transfer *lut) -{ -    std::list<libusb_transfer*>::iterator iter; -    for (iter = _pending_list.begin(); iter != _pending_list.end(); iter++) { -        if (*iter == lut) {  -            libusb_cancel_transfer(lut);  -            return true; -        } -    } -    return false; -} - - -/* - * Cancel all pending transfers  - * \return bool true if cancelation request is submitted - * - * Note: success only indicates submission of cancelation request. - * Sucessful cancelation is not known until the callback occurs. - */ -bool usb_endpoint::cancel_all() -{ -    std::list<libusb_transfer*>::iterator iter; - -    for (iter = _pending_list.begin(); iter != _pending_list.end(); iter++) { -        if (libusb_cancel_transfer(*iter) < 0) { -            std::cerr << "error: libusb_cancal_transfer() failed" << std::endl; -            return false; -        } -    } - -    return true; -} - - -/* - * Reap completed transfers - * return true if at least one transfer was reaped, false otherwise.  - * Check completed transfers for errors and mark as free. This is a - * blocking call.  - * \return bool true if a libusb transfer is reaped, false otherwise - */ -bool usb_endpoint::reap_completed_list() -{ -    libusb_transfer *lut; - -    if (_completed_list.empty()) { -        if (!reap_pending_list_timeout()) -            return false; -    } - -    while (!_completed_list.empty()) { -        lut = completed_list_get(); -        print_transfer_status(lut); -        free_list_add(lut); -    } - -    return true; -} - -  /*   * Print status errors of a completed transfer   * \param lut pointer to an libusb_transfer   */ -void usb_endpoint::print_transfer_status(libusb_transfer *lut) -{ +void usb_endpoint::print_transfer_status(libusb_transfer *lut){      switch (lut->status) {      case LIBUSB_TRANSFER_COMPLETED:          if (lut->actual_length < lut->length) { @@ -345,166 +271,15 @@ void usb_endpoint::print_transfer_status(libusb_transfer *lut)      }  } - -/* - * Reap pending transfers without timeout  - * This is a blocking call. Reaping submitted transfers is - * handled by libusb and the assigned callback function. - * Block until at least one transfer is reaped. - * \return true true if a transfer was reaped or false otherwise - */ -bool usb_endpoint::reap_pending_list() -{ -    int retval; - -    if ((retval = libusb_handle_events(_ctx)) < 0) { -        std::cerr << "error: libusb_handle_events: " << retval << std::endl; -        return false; -    } - -    return true; -} - - -/* - * Reap pending transfers with timeout  - * This call blocks until a transfer is reaped or timeout. - * Reaping submitted transfers is handled by libusb and the - * assigned callback function. Block until at least one - * transfer is reaped or timeout occurs. - * \return true if a transfer was reaped or false otherwise - */ -bool usb_endpoint::reap_pending_list_timeout() -{ -    int retval; -    timeval tv; - -    tv.tv_sec = 0; -    tv.tv_usec = 100000; //100ms - -    size_t pending_list_size = _pending_list.size(); - -    if ((retval = libusb_handle_events_timeout(_ctx, &tv)) < 0) { -        std::cerr << "error: libusb_handle_events: " << retval << std::endl; -        return false; -    } - -    if (_pending_list.size() < pending_list_size) { -        return true; -    } -    else { -        return false; -    } -} - - -/* - * Get a free transfer - * The transfer has an empty data bufer for OUT requests  - * \return pointer to a libusb_transfer - */ -libusb_transfer *usb_endpoint::get_free_transfer() -{ -    if (_free_list.empty()) { -        if (!reap_completed_list()) -            return NULL;  -    } - -    return free_list_get(); -} - - -/* - * Get a completed transfer  - * The transfer has a full data buffer for IN requests - * \return pointer to libusb_transfer - */ -libusb_transfer *usb_endpoint::get_completed_transfer() -{ -    if (_completed_list.empty()) { -        if (!reap_pending_list_timeout()) -            return NULL;  -    } - -    return completed_list_get(); -} - -/* - * List operations  - */ -void usb_endpoint::free_list_add(libusb_transfer *lut) -{ -    _free_list.push_back(lut); -} - -void usb_endpoint::pending_list_add(libusb_transfer *lut) -{ -    _pending_list.push_back(lut); -} - -void usb_endpoint::completed_list_add(libusb_transfer *lut) -{ -    _completed_list.push_back(lut); -} - - -/* - * Free and completed lists don't have ordered content  - * Pop transfers from the front as needed - */ -libusb_transfer *usb_endpoint::free_list_get() -{ +libusb_transfer *usb_endpoint::get_lut_with_wait(size_t timeout_ms){ +    boost::this_thread::disable_interruption di; //disable because the wait can throw      libusb_transfer *lut; - -    if (_free_list.size() == 0) { -        return NULL;  -    } -    else {  -        lut = _free_list.front(); -        _free_list.pop_front(); -        return lut; -    } -} - - -/* - * Free and completed lists don't have ordered content  - * Pop transfers from the front as needed - */ -libusb_transfer *usb_endpoint::completed_list_get() -{ -    libusb_transfer *lut; - -    if (_completed_list.empty()) { -        return NULL; -    } -    else {  -        lut = _completed_list.front(); -        _completed_list.pop_front(); -        return lut; -    } +    if (_completed_list->pop_with_timed_wait( +        lut, boost::posix_time::milliseconds(timeout_ms) +    )) return lut; +    return NULL;  } - -/* - * Search and remove transfer from pending list - * Assuming that the callbacks occur in order, the front element - * should yield the correct transfer. If not, then something else - * is going on. If no transfers match, then something went wrong. - */ -bool usb_endpoint::pending_list_remove(libusb_transfer *lut) -{ -    std::list<libusb_transfer*>::iterator iter; -    for (iter = _pending_list.begin(); iter != _pending_list.end(); iter++) { -        if (*iter == lut) {  -            _pending_list.erase(iter); -            return true; -        } -    } -    return false; -} - -  /***********************************************************************   * Managed buffers    **********************************************************************/ @@ -518,17 +293,15 @@ bool usb_endpoint::pending_list_remove(libusb_transfer *lut)  class libusb_managed_recv_buffer_impl : public managed_recv_buffer {  public:      libusb_managed_recv_buffer_impl(libusb_transfer *lut, -                                    usb_endpoint *endpoint) +                                    usb_endpoint::sptr endpoint)          : _buff(lut->buffer, lut->length)      {          _lut = lut;          _endpoint = endpoint;      } -    ~libusb_managed_recv_buffer_impl() -    { -       if (!_endpoint->submit(_lut)) -           std::cerr << "USB: failed to submit IN transfer" << std::endl; +    ~libusb_managed_recv_buffer_impl(void){ +        _endpoint->submit(_lut);      }  private: @@ -538,7 +311,7 @@ private:      }      libusb_transfer *_lut; -    usb_endpoint *_endpoint; +    usb_endpoint::sptr _endpoint;      const boost::asio::const_buffer _buff;  }; @@ -554,7 +327,7 @@ private:  class libusb_managed_send_buffer_impl : public managed_send_buffer {  public:      libusb_managed_send_buffer_impl(libusb_transfer *lut, -                                    usb_endpoint *endpoint, +                                    usb_endpoint::sptr endpoint,                                      size_t buff_size)          : _buff(lut->buffer, buff_size), _committed(false)      { @@ -562,8 +335,7 @@ public:          _endpoint = endpoint;      } -    ~libusb_managed_send_buffer_impl() -    { +    ~libusb_managed_send_buffer_impl(void){          if (!_committed) {              _lut->length = 0;              _lut->actual_length = 0; @@ -583,12 +355,14 @@ public:          _lut->length = num_bytes;          _lut->actual_length = 0; -        if (_endpoint->submit(_lut)) { +        try{ +            _endpoint->submit(_lut);              _committed = true;              return num_bytes;          } -        else { -            return 0; +        catch(const std::exception &e){ +            std::cerr << "Error in commit: " << e.what() << std::endl; +            return -1;          }      } @@ -599,7 +373,7 @@ private:      }      libusb_transfer *_lut; -    usb_endpoint *_endpoint; +    usb_endpoint::sptr _endpoint;      const boost::asio::mutable_buffer _buff;      bool _committed;  }; @@ -611,14 +385,9 @@ private:  class libusb_zero_copy_impl : public usb_zero_copy  {  private: -    usb_endpoint          *_rx_ep; -    usb_endpoint          *_tx_ep; +    usb_endpoint::sptr _rx_ep, _tx_ep; -    // Maintain libusb values -    libusb_context       *_rx_ctx; -    libusb_context       *_tx_ctx; -    libusb_device_handle *_rx_dev_handle; -    libusb_device_handle *_tx_dev_handle; +    libusb::device_handle::sptr _handle;      size_t _recv_buff_size;      size_t _send_buff_size; @@ -627,13 +396,11 @@ private:  public:      typedef boost::shared_ptr<libusb_zero_copy_impl> sptr; -    libusb_zero_copy_impl(usb_device_handle::sptr handle, +    libusb_zero_copy_impl(libusb::device_handle::sptr handle,                            unsigned int rx_endpoint,                            unsigned int tx_endpoint,                            size_t recv_buff_size,                            size_t send_buff_size); -     -    ~libusb_zero_copy_impl();      managed_recv_buffer::sptr get_recv_buff(void);      managed_send_buffer::sptr get_send_buff(void); @@ -647,73 +414,43 @@ public:   * Initializes libusb, opens devices, and sets up interfaces for I/O.   * Finally, creates endpoints for asynchronous I/O.    */ -libusb_zero_copy_impl::libusb_zero_copy_impl(usb_device_handle::sptr handle, +libusb_zero_copy_impl::libusb_zero_copy_impl(libusb::device_handle::sptr handle,                                               unsigned int rx_endpoint,                                               unsigned int tx_endpoint,                                               size_t buff_size,                                               size_t block_size) - : _rx_ctx(NULL), _tx_ctx(NULL), _rx_dev_handle(NULL), _tx_dev_handle(NULL), + : _handle(handle),     _recv_buff_size(block_size), _send_buff_size(block_size),     _num_frames(buff_size / block_size)  { -    // Initialize libusb with separate contexts to allow -    // thread safe operation of transmit and receive  -    libusb::init(&_rx_ctx, libusb_debug_level); -    libusb::init(&_tx_ctx, libusb_debug_level); - -    UHD_ASSERT_THROW((_rx_ctx != NULL) && (_tx_ctx != NULL)); - -    // Find and open the libusb_device corresponding to the -    // given handle and return the libusb_device_handle -    // that can be used for I/O purposes. -    _rx_dev_handle = libusb::open_device(_rx_ctx, handle); -    _tx_dev_handle = libusb::open_device(_tx_ctx, handle); - -    // Open USB interfaces for tx/rx using magic values. -    // IN interface:      2 -    // OUT interface:     1 -    // Control interface: 0 -    libusb::open_interface(_rx_dev_handle, 2); -    libusb::open_interface(_tx_dev_handle, 1); - -    _rx_ep = new usb_endpoint(_rx_dev_handle,  // libusb device_handle -                              _rx_ctx,         // libusb context +    _handle->claim_interface(2 /*in interface*/); +    _handle->claim_interface(1 /*out interface*/); + +    _rx_ep = usb_endpoint::sptr(new usb_endpoint( +                              _handle,         // libusb device_handle                                rx_endpoint,     // USB endpoint number                                true,            // IN endpoint                                _recv_buff_size, // buffer size per transfer  -                              _num_frames);    // number of libusb transfers +                              _num_frames      // number of libusb transfers +    )); -    _tx_ep = new usb_endpoint(_tx_dev_handle,  // libusb device_handle -                              _tx_ctx,         // libusb context +    _tx_ep = usb_endpoint::sptr(new usb_endpoint( +                              _handle,         // libusb device_handle                                tx_endpoint,     // USB endpoint number                                false,           // OUT endpoint                                _send_buff_size, // buffer size per transfer -                              _num_frames);    // number of libusb transfers +                              _num_frames      // number of libusb transfers +    ));  } - -libusb_zero_copy_impl::~libusb_zero_copy_impl() -{ -    delete _rx_ep; -    delete _tx_ep;  - -    libusb_close(_rx_dev_handle); -    libusb_close(_tx_dev_handle); - -    libusb_exit(_rx_ctx); -    libusb_exit(_tx_ctx); -} - -  /*   * Construct a managed receive buffer from a completed libusb transfer   * (happy with buffer full of data) obtained from the receive endpoint.   * Return empty pointer if no transfer is available (timeout or error).   * \return pointer to a managed receive buffer    */ -managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff() -{ -    libusb_transfer *lut = _rx_ep->get_completed_transfer(); +managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff(void){ +    libusb_transfer *lut = _rx_ep->get_lut_with_wait(/* TODO timeout API */);      if (lut == NULL) {          return managed_recv_buffer::sptr();      } @@ -731,9 +468,8 @@ managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff()   * (timeout or error).   * \return pointer to a managed send buffer    */ -managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff() -{ -    libusb_transfer *lut = _tx_ep->get_free_transfer(); +managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff(void){ +    libusb_transfer *lut = _tx_ep->get_lut_with_wait(/* TODO timeout API */);      if (lut == NULL) {          return managed_send_buffer::sptr();      } @@ -756,12 +492,12 @@ usb_zero_copy::sptr usb_zero_copy::make(usb_device_handle::sptr handle,                                          size_t block_size)  { -    return sptr(new libusb_zero_copy_impl(handle, +    libusb::device_handle::sptr dev_handle(libusb::device_handle::get_cached_handle( +        boost::static_pointer_cast<libusb::special_handle>(handle)->get_device() +    )); +    return sptr(new libusb_zero_copy_impl(dev_handle,                                            rx_endpoint,                                            tx_endpoint,                                            buff_size,                                             block_size));  } - - - diff --git a/host/lib/transport/msvc/stdint.h b/host/lib/transport/msvc/stdint.h new file mode 100644 index 000000000..b3eb61aae --- /dev/null +++ b/host/lib/transport/msvc/stdint.h @@ -0,0 +1,35 @@ +//
 +// Copyright 2010 Ettus Research LLC
 +//
 +// This program is free software: you can redistribute it and/or modify
 +// it under the terms of the GNU General Public License as published by
 +// the Free Software Foundation, either version 3 of the License, or
 +// (at your option) any later version.
 +//
 +// This program is distributed in the hope that it will be useful,
 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +// GNU General Public License for more details.
 +//
 +// You should have received a copy of the GNU General Public License
 +// along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +//
 +
 +#ifndef INCLUDED_LIBUHD_TRANSPORT_STDINT_H
 +#define INCLUDED_LIBUHD_TRANSPORT_STDINT_H
 +
 +#include <boost/cstdint.hpp>
 +
 +//provide a stdint implementation for libusb
 +
 +typedef boost::uint64_t uint64_t;
 +typedef boost::uint32_t uint32_t;
 +typedef boost::uint16_t uint16_t;
 +typedef boost::uint8_t uint8_t;
 +
 +typedef boost::int64_t int64_t;
 +typedef boost::int32_t int32_t;
 +typedef boost::int16_t int16_t;
 +typedef boost::int8_t int8_t;
 +
 +#endif /* INCLUDED_LIBUHD_TRANSPORT_STDINT_H */
 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/dboard/db_wbx.cpp b/host/lib/usrp/dboard/db_wbx.cpp index ccd897674..e473ce41e 100644 --- a/host/lib/usrp/dboard/db_wbx.cpp +++ b/host/lib/usrp/dboard/db_wbx.cpp @@ -154,7 +154,7 @@ static dboard_base::sptr make_wbx(dboard_base::ctor_args_t args){  }  UHD_STATIC_BLOCK(reg_wbx_dboards){ -    dboard_manager::register_dboard(0x0052, 0x0053, &make_wbx, "WBX"); +    dboard_manager::register_dboard(0x0053, 0x0052, &make_wbx, "WBX");  }  /*********************************************************************** diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp index ab80875f5..181f843a0 100644 --- a/host/lib/usrp/dboard_manager.cpp +++ b/host/lib/usrp/dboard_manager.cpp @@ -18,6 +18,7 @@  #include "dboard_ctor_args.hpp"  #include <uhd/usrp/dboard_manager.hpp>  #include <uhd/usrp/subdev_props.hpp> +#include <uhd/utils/warning.hpp>  #include <uhd/utils/static.hpp>  #include <uhd/utils/assert.hpp>  #include <uhd/types/dict.hpp> @@ -176,10 +177,6 @@ static args_t get_dboard_args(  ){      //special case, the none id was provided, use the following ids      if (dboard_id == dboard_id_t::none() or force_to_unknown){ -        std::cerr << boost::format( -            "Warning: unknown dboard-id or dboard-id combination: %s\n" -            "    -> defaulting to the unknown board type" -        ) % dboard_id.to_pp_string() << std::endl;          UHD_ASSERT_THROW(get_id_to_args_map().has_key(0xfff1));          UHD_ASSERT_THROW(get_id_to_args_map().has_key(0xfff0));          switch(unit){ @@ -191,6 +188,9 @@ static args_t get_dboard_args(      //verify that there is a registered constructor for this id      if (not get_id_to_args_map().has_key(dboard_id)){ +        uhd::print_warning(str(boost::format( +            "Unknown dboard ID: %s.\n" +        ) % dboard_id.to_pp_string()));          return get_dboard_args(unit, dboard_id, true);      } @@ -214,12 +214,25 @@ dboard_manager_impl::dboard_manager_impl(          (get_xcvr_id_to_id_map()[tx_dboard_id] == rx_dboard_id)      ); +    //warn for invalid dboard id xcvr combinations +    if (rx_dboard_is_xcvr != this_dboard_is_xcvr or tx_dboard_is_xcvr != this_dboard_is_xcvr){ +        uhd::print_warning(str(boost::format( +            "Unknown transceiver board ID combination...\n" +            "RX dboard ID: %s\n" +            "TX dboard ID: %s\n" +        ) % rx_dboard_id.to_pp_string() % tx_dboard_id.to_pp_string())); +    } +      //extract dboard constructor and settings (force to unknown for messed up xcvr status)      dboard_ctor_t rx_dboard_ctor; std::string rx_name; prop_names_t rx_subdevs; -    boost::tie(rx_dboard_ctor, rx_name, rx_subdevs) = get_dboard_args(dboard_iface::UNIT_RX, rx_dboard_id, rx_dboard_is_xcvr != this_dboard_is_xcvr); +    boost::tie(rx_dboard_ctor, rx_name, rx_subdevs) = get_dboard_args( +        dboard_iface::UNIT_RX, rx_dboard_id, rx_dboard_is_xcvr != this_dboard_is_xcvr +    );      dboard_ctor_t tx_dboard_ctor; std::string tx_name; prop_names_t tx_subdevs; -    boost::tie(tx_dboard_ctor, tx_name, tx_subdevs) = get_dboard_args(dboard_iface::UNIT_TX, tx_dboard_id, tx_dboard_is_xcvr != this_dboard_is_xcvr); +    boost::tie(tx_dboard_ctor, tx_name, tx_subdevs) = get_dboard_args( +        dboard_iface::UNIT_TX, tx_dboard_id, tx_dboard_is_xcvr != this_dboard_is_xcvr +    );      //initialize the gpio pins before creating subdevs      set_nice_dboard_if(); 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/codec_ctrl.cpp b/host/lib/usrp/usrp1/codec_ctrl.cpp index 3ab02eeeb..33b18b196 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.cpp +++ b/host/lib/usrp/usrp1/codec_ctrl.cpp @@ -129,7 +129,7 @@ usrp1_codec_ctrl_impl::usrp1_codec_ctrl_impl(usrp1_iface::sptr iface,      _ad9862_regs.clkout2_div_factor = ad9862_regs_t::CLKOUT2_DIV_FACTOR_2;      //write the register settings to the codec -    for (uint8_t addr = 0; addr <= 25; addr++) { +    for (boost::uint8_t addr = 0; addr <= 25; addr++) {          this->send_reg(addr);      } @@ -202,7 +202,7 @@ float usrp1_codec_ctrl_impl::get_rx_pga_gain(char which){   **********************************************************************/  static float aux_adc_to_volts(boost::uint8_t high, boost::uint8_t low)  { -    return float((boost::uint16_t(high) << 2) | low)*3.3/0x3ff; +    return float(((boost::uint16_t(high) << 2) | low)*3.3)/0x3ff;  }  float usrp1_codec_ctrl_impl::read_aux_adc(aux_adc_t which) diff --git a/host/lib/usrp/usrp1/dsp_impl.cpp b/host/lib/usrp/usrp1/dsp_impl.cpp index d5a88fa2d..e9a5e60a6 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,30 +88,26 @@ 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: { -            unsigned int rate = -                    _clock_ctrl->get_master_clock_freq() / val.as<double>(); +            size_t rate = size_t(_clock_ctrl->get_master_clock_freq() / val.as<double>());              if ((rate & 0x01) || (rate < 4) || (rate > 256)) {                  std::cerr << "Decimation must be even and between 4 and 256" @@ -106,7 +117,7 @@ void usrp1_impl::rx_dsp_set(const wax::obj &key, const wax::obj &val)              _rx_dsp_decim = rate;              //TODO Poll every 100ms. Make it selectable? -            _rx_samps_per_poll_interval = 0.1 * _clock_ctrl->get_master_clock_freq() / rate; +            _rx_samps_per_poll_interval = size_t(0.1 * _clock_ctrl->get_master_clock_freq() / rate);              _iface->poke32(FR_DECIM_RATE, _rx_dsp_decim/2 - 1);          } @@ -133,11 +144,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 +160,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,26 +188,25 @@ 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;          }      case DSP_PROP_HOST_RATE: { -            unsigned int rate = -                    _clock_ctrl->get_master_clock_freq() * 2 / val.as<double>(); +            size_t rate = size_t(_clock_ctrl->get_master_clock_freq() * 2 / val.as<double>());              if ((rate & 0x01) || (rate < 8) || (rate > 512)) {                  std::cerr << "Interpolation rate must be even and between 8 and 512" @@ -194,7 +217,7 @@ void usrp1_impl::tx_dsp_set(const wax::obj &key, const wax::obj &val)              _tx_dsp_interp = rate;              //TODO Poll every 100ms. Make it selectable?  -            _tx_samps_per_poll_interval = 0.1 * _clock_ctrl->get_master_clock_freq() * 2 / rate; +            _tx_samps_per_poll_interval = size_t(0.1 * _clock_ctrl->get_master_clock_freq() * 2 / rate);              _iface->poke32(FR_INTERP_RATE, _tx_dsp_interp / 4 - 1);              return; diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index 92e8bc20a..73974f2d6 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() != NULL;  }  /*********************************************************************** - * 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() != NULL; +} -        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_ctrl.cpp b/host/lib/usrp/usrp1/usrp1_ctrl.cpp index 451129ef5..76e8ce368 100644 --- a/host/lib/usrp/usrp1/usrp1_ctrl.cpp +++ b/host/lib/usrp/usrp1/usrp1_ctrl.cpp @@ -38,6 +38,8 @@ enum firmware_code {  #define FX2_FIRMWARE_LOAD 0xa0 +static const bool load_img_msg = true; +  /***********************************************************************   * Helper Functions   **********************************************************************/ @@ -178,6 +180,7 @@ public:          unsigned char reset_n = 0;          //hit the reset line +        if (load_img_msg) std::cout << "Loading firmware image " << filestring << "..." << std::flush;          usrp_control_write(FX2_FIRMWARE_LOAD, 0xe600, 0,                             &reset_y, 1); @@ -213,7 +216,7 @@ public:                  //wait for things to settle                  boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); - +                if (load_img_msg) std::cout << " done" << std::endl;                  return USRP_FIRMWARE_LOAD_SUCCESS;               }              //type anything else is unhandled @@ -249,45 +252,48 @@ public:          unsigned char buf[ep0_size];          int ret; -        FILE *fp; -        if ((fp = fopen(filename, "rb")) == NULL) { +        if (load_img_msg) std::cout << "Loading FPGA image: " << filestring << "..." << std::flush; +        std::ifstream file; +        file.open(filename, std::ios::in | std::ios::binary); +        if (not file.good()) {              std::cerr << "cannot open fpga input file" << std::endl; -            fclose(fp); +            file.close();              return -1;          }          if (usrp_control_write_cmd(VRQ_FPGA_LOAD, 0, FL_BEGIN) < 0) {              std::cerr << "fpga load error" << std::endl; -            fclose(fp); +            file.close();              return -1;          }          ssize_t n; -        while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) { +        while ((n = file.readsome((char *)buf, sizeof(buf))) > 0) {              ret = usrp_control_write(VRQ_FPGA_LOAD, 0, FL_XFER,                                       buf, n);              if (ret != n) {                  std::cerr << "fpga load error " << ret << std::endl; -                fclose(fp); +                file.close();                  return -1;              }          }          if (usrp_control_write_cmd(VRQ_FPGA_LOAD, 0, FL_END) < 0) {              std::cerr << "fpga load error" << std::endl; -            fclose(fp); +            file.close();              return -1;          }          usrp_set_fpga_hash(hash); -        fclose(fp); +        file.close(); +        if (load_img_msg) std::cout << " done" << std::endl;          return 0;       }      int usrp_load_eeprom(std::string filestring)      {          const char *filename = filestring.c_str(); -        const uint16_t i2c_addr = 0x50; +        const boost::uint16_t i2c_addr = 0x50;          //FIXME: verify types          int len; @@ -416,7 +422,7 @@ public:      } -    int usrp_control_write_cmd(uint8_t request, uint16_t value, uint16_t index) +    int usrp_control_write_cmd(boost::uint8_t request, boost::uint16_t value, boost::uint16_t index)      {          return usrp_control_write(request, value, index, 0, 0);      } diff --git a/host/lib/usrp/usrp1/usrp1_iface.cpp b/host/lib/usrp/usrp1/usrp1_iface.cpp index 4bc18dd16..5fd3987d5 100644 --- a/host/lib/usrp/usrp1/usrp1_iface.cpp +++ b/host/lib/usrp/usrp1/usrp1_iface.cpp @@ -80,7 +80,7 @@ public:      boost::uint32_t peek32(boost::uint32_t addr)      { -        uint32_t value_out; +        boost::uint32_t value_out;          boost::uint8_t w_index_h = SPI_ENABLE_FPGA & 0xff;          boost::uint8_t w_index_l = (SPI_FMT_MSB | SPI_FMT_HDR_1) & 0xff; @@ -100,7 +100,7 @@ public:      boost::uint16_t peek16(boost::uint32_t addr)      { -        uint32_t val = peek32(addr); +        boost::uint32_t val = peek32(addr);          return boost::uint16_t(val & 0xff);      } diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index a6806dbc3..80ea49e9d 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -62,7 +62,7 @@ static device_addrs_t usrp1_find(const device_addr_t &hint)              hint.has_key("fw")? hint["fw"] : "usrp1_fw.ihx"          );      } -    catch(const std::exception &e){ +    catch(...){          uhd::print_warning(              "Could not locate USRP1 firmware.\n"              "Please install the images package.\n" @@ -96,7 +96,10 @@ static device_addrs_t usrp1_find(const device_addr_t &hint)              device_addr_t new_addr;              new_addr["type"] = "usrp1";              new_addr["serial"] = handle->get_serial(); -            usrp1_addrs.push_back(new_addr); +            //this is a found usrp1 when a hint serial is not specified or it matches +            if (not hint.has_key("serial") or hint["serial"] == new_addr["serial"]){ +                usrp1_addrs.push_back(new_addr); +            }      }      return usrp1_addrs; 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..65411801d 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -150,7 +150,7 @@ void usrp2_impl::io_init(void){          std::memcpy(send_buff->cast<void*>(), &data, sizeof(data));          send_buff->commit(sizeof(data));          //drain the recv buffers (may have junk) -        while (data_transport->get_recv_buff().get()); +        while (data_transport->get_recv_buff().get()){};      }      //the number of recv frames is the number for the first transport @@ -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);  } | 
