diff options
author | Nick Foster <nick@nerdnetworks.org> | 2010-09-30 12:28:29 -0700 |
---|---|---|
committer | Nick Foster <nick@nerdnetworks.org> | 2010-09-30 12:28:29 -0700 |
commit | 6dd502737bcf6e59933be01720672db9a496803b (patch) | |
tree | 5ab70f1c7cb4f2fdd8b5924b5d7abacbd772c9be | |
parent | ed245848df8cc011ae8fe30833ecc28049139db5 (diff) | |
parent | e4fffed05dda57bb37d693a3a26ea6a903c925f7 (diff) | |
download | uhd-6dd502737bcf6e59933be01720672db9a496803b.tar.gz uhd-6dd502737bcf6e59933be01720672db9a496803b.tar.bz2 uhd-6dd502737bcf6e59933be01720672db9a496803b.zip |
Merge branch 'master' of ettus.sourcerepo.com:ettus/uhdpriv into usrp2p
Conflicts:
host/lib/usrp/usrp2/io_impl.cpp
52 files changed, 1908 insertions, 1451 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..9cf37db4a 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,24 +48,25 @@ 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) -* **Download URL:** http://www.libusb.org/ +* **Usage:** build time + run time (optional) +* **Download URL:** http://sourceforge.net/projects/libusb/files/libusb-1.0/ +* **Download URL (windows binaries):** http://www.libusb.org/wiki/windows_backend#LatestBinarySnapshots ^^^^^^^^^^^^^^^^ 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 +74,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 +82,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 +106,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 @@ -145,6 +153,19 @@ Generate the project with cmake * Click generate and a project file will be created in the build directory. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LibUSB cmake notes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +On Windows, cmake does not have the advantage of pkg-config, +so we must manually tell cmake how to locate the LibUSB header and lib. + +From the cmake gui, select "Advanded View": + +* Set LIBUSB_INCLUDE_DIR to the directory with "libusb.h". +* Set LIBUSB_LIBRARIES to the full path for "libusb-1.0.lib". + +Then check the boxes to enable USRP1 support, click configure and generate. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Build the project in MSVC ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * Open the generated project file in MSVC. @@ -155,14 +176,23 @@ 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 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * Add the boost library path to %PATH% (usually c:\\program files\\boost\\<version>\\lib) * Add the uhd library path to %PATH% (usually c:\\program files\\uhd\\lib) +* Add the libusb library to %PATH% (if using usb support) + +**Note:** +The interface for editing environment variable paths in Windows is very poor. +I recommend using "Rapid Environment Editor" (http://www.rapidee.com) over the default editor. 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/usrp1.rst b/host/docs/usrp1.rst index 3c1431d30..0baa93a45 100644 --- a/host/docs/usrp1.rst +++ b/host/docs/usrp1.rst @@ -60,6 +60,29 @@ Example device address string representations to specify non-standard firmware a fpga=usrp1_fpga_4rx.rbf, fw=usrp1_fw_custom.ihx +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Change USB transfer parameters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The advanced user may manipulate parameters of the usb bulk transfers +for various reasons, such as lowering latency or increasing buffer size. +By default, the UHD will use values for these parameters +that are known to perform well on a variety of systems. +The following device address parameters can be used to manipulate USB bulk transfers: + +* **recv_xfer_size:** the size of each receive bulk transfer in bytes +* **recv_num_xfers:** the number of simultaneous receive bulk transfers +* **send_xfer_size:** the size of each send bulk transfer in bytes +* **send_num_xfers:** the number of simultaneous send bulk transfers + +Example usage, set the device address markup string to the following: +:: + + serial=12345678, recv_num_xfers=16 + + -- OR -- + + serial=12345678, recv_xfer_size=2048, recv_num_xfers=16 + ------------------------------------------------------------------------ Specifying the subdevice to use ------------------------------------------------------------------------ @@ -100,10 +123,10 @@ OS Specific Notes ------------------------------------------------------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Setup Udev on Linux +Linux - setup udev ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -On Linux, Udev handles USB plug and unplug events. -The following command creates a Udev rule for the USRP1 +On Linux, udev handles USB plug and unplug events. +The following commands create a udev rule for the USRP1 so that non-root users may access the device: :: @@ -113,3 +136,9 @@ so that non-root users may access the device: sudo mv tmpfile /etc/udev/rules.d/10-usrp.rules sudo udevadm control --reload-rules +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Windows - install driver +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +On Windows, a driver must be installed the first time the USRP1 is attached to the host computer. +A download link for this driver can be found on the UHD wiki page. +Download and unpack the driver, and direct the Windows driver install wizard to the .inf file. diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst index 745361b77..70e5ea28b 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: @@ -201,7 +201,7 @@ Each parameter will accept a numeric value for the number of bytes. * recv_buff_size * send_buff_size -Example, set the args string to the following: +Example usage, set the device address markup string to the following: :: addr=192.168.10.2, recv_buff_size=100e6 @@ -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_control.hpp b/host/include/uhd/transport/usb_control.hpp index 6137ecf84..f9829c3ec 100644 --- a/host/include/uhd/transport/usb_control.hpp +++ b/host/include/uhd/transport/usb_control.hpp @@ -50,9 +50,9 @@ public: * \param index 2-byte (wIndex) * \param buff buffer to hold send or receive data * \param length 2-byte (wLength) - * \return number of bytes submitted + * \return number of bytes submitted or error code */ - virtual size_t submit(boost::uint8_t request_type, + virtual ssize_t submit(boost::uint8_t request_type, boost::uint8_t request, boost::uint16_t value, boost::uint16_t index, 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..61bf380ba 100644 --- a/host/include/uhd/transport/usb_zero_copy.hpp +++ b/host/include/uhd/transport/usb_zero_copy.hpp @@ -45,16 +45,22 @@ public: * The underlying implementation may be platform specific. * * \param handle a device handle that uniquely identifying the device - * \param rx_endpoint an integer specifiying an IN endpoint number - * \param tx_endpoint an integer specifiying an OUT endpoint number - * \param buff_size total number of bytes of buffer space to allocate - * \param block_size number of bytes allocated for each I/O transaction + * \param recv_endpoint an integer specifiying an IN endpoint number + * \param send_endpoint an integer specifiying an OUT endpoint number + * \param recv_xfer_size the number of bytes for each receive transfer + * \param recv_num_xfers the number of simultaneous receive transfers + * \param send_xfer_size the number of bytes for each send transfer + * \param send_num_xfers the number of simultaneous send transfers */ - static sptr make(usb_device_handle::sptr handle, - unsigned int rx_endpoint, - unsigned int tx_endpoint, - size_t buff_size = 0, - size_t block_size = 0); + static sptr make( + usb_device_handle::sptr handle, + unsigned int recv_endpoint, + unsigned int send_endpoint, + size_t recv_xfer_size = 0, + size_t recv_num_xfers = 0, + size_t send_xfer_size = 0, + size_t send_num_xfers = 0 + ); }; }} //namespace 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..49f524a32 100644 --- a/host/lib/transport/libusb1_base.cpp +++ b/host/lib/transport/libusb1_base.cpp @@ -16,111 +16,262 @@ // #include "libusb1_base.hpp" +#include <uhd/utils/thread_priority.hpp> #include <uhd/utils/assert.hpp> +#include <uhd/types/dict.hpp> +#include <boost/weak_ptr.hpp> +#include <boost/foreach.hpp> +#include <boost/thread.hpp> #include <iostream> +using namespace uhd; 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){ + set_thread_priority_safe(); + _running = true; + timeval tv; + while(_running){ + tv.tv_sec = 0; + tv.tv_usec = 100000; //100ms + libusb_handle_events_timeout(this->get_context(), &tv); } - - libusb_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..f903907d0 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, + ssize_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..f2dcff6b5 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -17,17 +17,22 @@ #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; +static const size_t DEFAULT_NUM_XFERS = 16; //num xfers +static const size_t DEFAULT_XFER_SIZE = 32*512; //bytes + /*********************************************************************** * Helper functions ***********************************************************************/ @@ -54,56 +59,60 @@ void pp_transfer(libusb_transfer *lut) * create a bidirectional interface. It is a zero copy implementation * with respect to libusb, however, each send and recv requires a copy * operation from kernel to userspace; this is due to the usbfs - * interface provided by the kernel. + * 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; - - // 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); + //! hold a bounded buffer of completed transfers + typedef bounded_buffer<libusb_transfer *> lut_buff_type; + lut_buff_type::sptr _completed_list; - ~usb_endpoint(); + //! a list of all transfer structs we allocated + std::vector<libusb_transfer *> _all_luts; - // Exposed interface for submitting / retrieving transfer buffers - bool submit(libusb_transfer *lut); - libusb_transfer *get_completed_transfer(); - libusb_transfer *get_free_transfer(); + //! a list of shared arrays for the transfer buffers + std::vector<boost::shared_array<boost::uint8_t> > _buffers; - //Callback use only - void callback_handle_transfer(libusb_transfer *lut); + // Calls for processing asynchronous I/O + libusb_transfer *allocate_transfer(int buff_len); + void print_transfer_status(libusb_transfer *lut); }; @@ -116,9 +125,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 +135,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); } @@ -142,21 +145,30 @@ void usb_endpoint::callback_handle_transfer(libusb_transfer *lut) * Constructor * Allocate libusb transfers and mark as free. For IN endpoints, * submit the transfers so that they're ready to return when - * data is available. + * 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); + + for (size_t i = 0; i < _num_transfers; i++){ + _all_luts.push_back(allocate_transfer(_transfer_size)); - if (_input) - submit(free_list_get()); + //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,47 +180,44 @@ 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); } } /* - * Allocate a libusb transfer + * Allocate a libusb transfer * The allocated transfer - and buffer it contains - is repeatedly * submitted, reaped, and reused and should not be freed until shutdown. * \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; @@ -219,97 +228,17 @@ libusb_transfer *usb_endpoint::allocate_transfer(int buff_len) * Asynchonous transfer submission * Submit a libusb transfer to libusb add pending status * \param lut pointer to libusb_transfer - * \return true on success or false on error + * \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,200 +274,47 @@ 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 *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 *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 (_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 + * Managed buffers **********************************************************************/ /* * Libusb managed receive buffer * Construct a recv buffer from a libusb transfer. The memory held by * the libusb transfer is exposed through the managed buffer interface. * Upon destruction, the transfer and buffer are resubmitted to the - * endpoint for further use. + * endpoint for further use. */ 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: const boost::asio::const_buffer &get() const { - return _buff; + return _buff; } libusb_transfer *_lut; - usb_endpoint *_endpoint; + usb_endpoint::sptr _endpoint; const boost::asio::const_buffer _buff; }; @@ -554,16 +330,14 @@ private: class libusb_managed_send_buffer_impl : public managed_send_buffer { public: libusb_managed_send_buffer_impl(libusb_transfer *lut, - usb_endpoint *endpoint, - size_t buff_size) - : _buff(lut->buffer, buff_size), _committed(false) + usb_endpoint::sptr endpoint) + : _buff(lut->buffer, lut->length), _committed(false) { _lut = lut; _endpoint = endpoint; } - ~libusb_managed_send_buffer_impl() - { + ~libusb_managed_send_buffer_impl(void){ if (!_committed) { _lut->length = 0; _lut->actual_length = 0; @@ -577,29 +351,31 @@ public: std::cerr << "UHD: send buffer already committed" << std::endl; return 0; } - + UHD_ASSERT_THROW(num_bytes <= boost::asio::buffer_size(_buff)); _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; } } private: const boost::asio::mutable_buffer &get() const { - return _buff; + return _buff; } libusb_transfer *_lut; - usb_endpoint *_endpoint; + usb_endpoint::sptr _endpoint; const boost::asio::mutable_buffer _buff; bool _committed; }; @@ -611,116 +387,89 @@ private: class libusb_zero_copy_impl : public usb_zero_copy { private: - usb_endpoint *_rx_ep; - usb_endpoint *_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; - - size_t _recv_buff_size; - size_t _send_buff_size; - size_t _num_frames; + libusb::device_handle::sptr _handle; + size_t _recv_num_frames, _send_num_frames; + usb_endpoint::sptr _recv_ep, _send_ep; public: typedef boost::shared_ptr<libusb_zero_copy_impl> sptr; - libusb_zero_copy_impl(usb_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(); + libusb_zero_copy_impl( + libusb::device_handle::sptr handle, + unsigned int recv_endpoint, unsigned int send_endpoint, + size_t recv_xfer_size, size_t recv_num_xfers, + size_t send_xfer_size, size_t send_num_xfers + ); managed_recv_buffer::sptr get_recv_buff(void); managed_send_buffer::sptr get_send_buff(void); - size_t get_num_recv_frames(void) const { return _num_frames; } - size_t get_num_send_frames(void) const { return _num_frames; } + size_t get_num_recv_frames(void) const { return _recv_num_frames; } + size_t get_num_send_frames(void) const { return _send_num_frames; } }; /* * Constructor * Initializes libusb, opens devices, and sets up interfaces for I/O. - * Finally, creates endpoints for asynchronous I/O. + * Finally, creates endpoints for asynchronous I/O. */ -libusb_zero_copy_impl::libusb_zero_copy_impl(usb_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), - _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 - rx_endpoint, // USB endpoint number +libusb_zero_copy_impl::libusb_zero_copy_impl( + libusb::device_handle::sptr handle, + unsigned int recv_endpoint, unsigned int send_endpoint, + size_t recv_xfer_size, size_t recv_num_xfers, + size_t send_xfer_size, size_t send_num_xfers +){ + _handle = handle; + + //if the sizes are left at 0 (automatic) -> use the defaults + if (recv_xfer_size == 0) recv_xfer_size = DEFAULT_XFER_SIZE; + if (recv_num_xfers == 0) recv_num_xfers = DEFAULT_NUM_XFERS; + if (send_xfer_size == 0) send_xfer_size = DEFAULT_XFER_SIZE; + if (send_num_xfers == 0) send_num_xfers = DEFAULT_NUM_XFERS; + + //sanity check the transfer sizes + UHD_ASSERT_THROW(recv_xfer_size % 512 == 0); + UHD_ASSERT_THROW(send_xfer_size % 512 == 0); + + //store the num xfers for the num frames count + _recv_num_frames = recv_num_xfers; + _send_num_frames = send_num_xfers; + + _handle->claim_interface(2 /*in interface*/); + _handle->claim_interface(1 /*out interface*/); + + _recv_ep = usb_endpoint::sptr(new usb_endpoint( + _handle, // libusb device_handle + recv_endpoint, // USB endpoint number true, // IN endpoint - _recv_buff_size, // buffer size per transfer - _num_frames); // number of libusb transfers + recv_xfer_size, // buffer size per transfer + recv_num_xfers // number of libusb transfers + )); - _tx_ep = new usb_endpoint(_tx_dev_handle, // libusb device_handle - _tx_ctx, // libusb context - tx_endpoint, // USB endpoint number + _send_ep = usb_endpoint::sptr(new usb_endpoint( + _handle, // libusb device_handle + send_endpoint, // USB endpoint number false, // OUT endpoint - _send_buff_size, // buffer size per transfer - _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); + send_xfer_size, // buffer size per transfer + send_num_xfers // number of libusb transfers + )); } - /* * 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 + * \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 = _recv_ep->get_lut_with_wait(/* TODO timeout API */); if (lut == NULL) { return managed_recv_buffer::sptr(); } else { return managed_recv_buffer::sptr( new libusb_managed_recv_buffer_impl(lut, - _rx_ep)); + _recv_ep)); } } @@ -729,39 +478,36 @@ managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff() * Construct a managed send buffer from a free libusb transfer (with * empty buffer). Return empty pointer of no transfer is available * (timeout or error). - * \return pointer to a managed send buffer + * \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 = _send_ep->get_lut_with_wait(/* TODO timeout API */); if (lut == NULL) { return managed_send_buffer::sptr(); } else { return managed_send_buffer::sptr( new libusb_managed_send_buffer_impl(lut, - _tx_ep, - _send_buff_size)); + _send_ep)); } } - /*********************************************************************** * USB zero_copy make functions **********************************************************************/ -usb_zero_copy::sptr usb_zero_copy::make(usb_device_handle::sptr handle, - unsigned int rx_endpoint, - unsigned int tx_endpoint, - size_t buff_size, - size_t block_size) - -{ - return sptr(new libusb_zero_copy_impl(handle, - rx_endpoint, - tx_endpoint, - buff_size, - block_size)); +usb_zero_copy::sptr usb_zero_copy::make( + usb_device_handle::sptr handle, + unsigned int recv_endpoint, unsigned int send_endpoint, + size_t recv_xfer_size, size_t recv_num_xfers, + size_t send_xfer_size, size_t send_num_xfers +){ + libusb::device_handle::sptr dev_handle(libusb::device_handle::get_cached_handle( + boost::static_pointer_cast<libusb::special_handle>(handle)->get_device() + )); + return sptr(new libusb_zero_copy_impl( + dev_handle, + recv_endpoint, send_endpoint, + recv_xfer_size, recv_num_xfers, + send_xfer_size, send_num_xfers + )); } - - - 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 08f2d2a8e..ad16f6b3a 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.cpp +++ b/host/lib/usrp/usrp1/codec_ctrl.cpp @@ -126,7 +126,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); } @@ -199,7 +199,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..5043aed7d 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); @@ -206,14 +209,14 @@ public: } //type 0x01 is end else if (type == 0x01) { + usrp_set_firmware_hash(hash); //set hash before reset usrp_control_write(FX2_FIRMWARE_LOAD, 0xe600, 0, &reset_n, 1); - usrp_set_firmware_hash(hash); file.close(); //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,49 @@ 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 (not file.eof()) { + file.read((char *)buf, sizeof(buf)); + size_t n = file.gcount(); ret = usrp_control_write(VRQ_FPGA_LOAD, 0, FL_XFER, buf, n); - if (ret != n) { + if (ret < 0 or size_t(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 +423,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..64ced2905 100644 --- a/host/lib/usrp/usrp1/usrp1_iface.cpp +++ b/host/lib/usrp/usrp1/usrp1_iface.cpp @@ -49,7 +49,7 @@ public: ******************************************************************/ void poke32(boost::uint32_t addr, boost::uint32_t value) { - boost::uint32_t swapped = byteswap(value); + boost::uint32_t swapped = uhd::htonx(value); if (iface_debug) { std::cout.fill('0'); @@ -72,15 +72,9 @@ public: std::cerr << "USRP: failed memory write: " << ret << std::endl; } - void poke16(boost::uint32_t, boost::uint16_t) - { - //fpga only handles 32 bit writes - std::cerr << "USRP: unsupported operation: poke16()" << std::endl; - } - 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; @@ -95,13 +89,7 @@ public: if (ret < 0) std::cerr << "USRP: failed memory read: " << ret << std::endl; - return byteswap(value_out); - } - - boost::uint16_t peek16(boost::uint32_t addr) - { - uint32_t val = peek32(addr); - return boost::uint16_t(val & 0xff); + return uhd::ntohx(value_out); } /******************************************************************* diff --git a/host/lib/usrp/usrp1/usrp1_iface.hpp b/host/lib/usrp/usrp1/usrp1_iface.hpp index 9a3fdd6bc..3f608584a 100644 --- a/host/lib/usrp/usrp1/usrp1_iface.hpp +++ b/host/lib/usrp/usrp1/usrp1_iface.hpp @@ -54,20 +54,6 @@ public: virtual boost::uint32_t peek32(boost::uint32_t addr) = 0; /*! - * Write a register (16 bits) - * \param addr the address - * \param data the 16bit data - */ - virtual void poke16(boost::uint32_t addr, boost::uint16_t data) = 0; - - /*! - * read a register (16 bits) - * \param addr the address - * \return the 16bit data - */ - virtual boost::uint16_t peek16(boost::uint32_t addr) = 0; - - /*! * Perform an spi transaction. * \param which_slave the slave device number * \param config spi config args diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index a6806dbc3..793e3027d 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -30,6 +30,7 @@ #include <boost/assign/list_of.hpp> #include <boost/filesystem.hpp> #include <boost/thread/thread.hpp> +#include <boost/lexical_cast.hpp> #include <iostream> using namespace uhd; @@ -62,7 +63,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" @@ -74,14 +75,14 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) boost::uint16_t vid = hint.has_key("uninit") ? FX2_VENDOR_ID : USRP1_VENDOR_ID; boost::uint16_t pid = hint.has_key("uninit") ? FX2_PRODUCT_ID : USRP1_PRODUCT_ID; - //see what we got on the USB bus - std::vector<usb_device_handle::sptr> device_list = - usb_device_handle::get_device_list(vid, pid); - - if(device_list.size() == 0) return usrp1_addrs; //return nothing if no USRPs found + // Important note: + // The get device list calls are nested inside the for loop. + // This allows the usb guts to decontruct when not in use, + // so that re-enumeration after fw load can occur successfully. + // This requirement is a courtesy of libusb1.0 on windows. //find the usrps and load firmware - BOOST_FOREACH(usb_device_handle::sptr handle, device_list) { + BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid, pid)) { usb_control::sptr ctrl_transport = usb_control::make(handle); usrp_ctrl::sptr usrp_ctrl = usrp_ctrl::make(ctrl_transport); usrp_ctrl->usrp_load_firmware(usrp1_fw_image); @@ -90,13 +91,15 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) //get descriptors again with serial number, but using the initialized VID/PID now since we have firmware vid = USRP1_VENDOR_ID; pid = USRP1_PRODUCT_ID; - device_list = usb_device_handle::get_device_list(vid, pid); - BOOST_FOREACH(usb_device_handle::sptr handle, device_list) { + BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid, pid)) { 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; @@ -105,6 +108,15 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) /*********************************************************************** * Make **********************************************************************/ +template<typename output_type> static output_type cast_from_dev_addr( + const device_addr_t &device_addr, + const std::string &key, + output_type def_val +){ + return (device_addr.has_key(key))? + boost::lexical_cast<output_type>(device_addr[key]) : def_val; +} + static device::sptr usrp1_make(const device_addr_t &device_addr) { //extract the FPGA path for the USRP1 @@ -128,11 +140,15 @@ static device::sptr usrp1_make(const device_addr_t &device_addr) usrp_ctrl = usrp_ctrl::make(ctrl_transport); usrp_ctrl->usrp_load_fpga(usrp1_fpga_image); - data_transport = usb_zero_copy::make(handle, // identifier - 6, // IN endpoint - 2, // OUT endpoint - 2 * (1 << 20), // buffer size - 16384); // transfer size + data_transport = usb_zero_copy::make( + handle, // identifier + 6, // IN endpoint + 2, // OUT endpoint + size_t(cast_from_dev_addr<double>(device_addr, "recv_xfer_size", 0)), + size_t(cast_from_dev_addr<double>(device_addr, "recv_num_xfers", 0)), + size_t(cast_from_dev_addr<double>(device_addr, "send_xfer_size", 0)), + size_t(cast_from_dev_addr<double>(device_addr, "send_num_xfers", 0)) + ); break; } } @@ -171,7 +187,7 @@ usrp1_impl::usrp1_impl(uhd::transport::usb_zero_copy::sptr data_transport, //initialize the mboard mboard_init(); - //initialize the dboards + //initialize the dboards dboard_init(); //initialize the dsps 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/clock_ctrl.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp index ef027c1df..72f92c081 100644 --- a/host/lib/usrp/usrp2/clock_ctrl.cpp +++ b/host/lib/usrp/usrp2/clock_ctrl.cpp @@ -21,6 +21,7 @@ #include "usrp2_clk_regs.hpp" #include <uhd/utils/assert.hpp> #include <boost/cstdint.hpp> +#include <iostream> using namespace uhd; @@ -70,12 +71,60 @@ public: this->enable_dac_clock(true); this->enable_adc_clock(true); + /* always driving the mimo reference */ + this->enable_mimo_clock_out(true); } ~usrp2_clock_ctrl_impl(void){ - /* private clock enables, must be set here */ + //power down clock outputs + this->enable_external_ref(false); + this->enable_rx_dboard_clock(false); + this->enable_tx_dboard_clock(false); this->enable_dac_clock(false); this->enable_adc_clock(false); + this->enable_mimo_clock_out(false); + } + + void enable_mimo_clock_out(bool enb){ + //FIXME TODO put this revision read in a common place + boost::uint8_t rev_hi = _iface->read_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_REV_MSB, 1).at(0); + + //calculate the low and high dividers + size_t divider = size_t(this->get_master_clock_rate()/10e6); + size_t high = divider/2; + size_t low = divider - high; + + switch(rev_hi){ + case 3: //clock 2 + _ad9510_regs.power_down_lvpecl_out2 = enb? + ad9510_regs_t::POWER_DOWN_LVPECL_OUT2_NORMAL : + ad9510_regs_t::POWER_DOWN_LVPECL_OUT2_SAFE_PD; + _ad9510_regs.output_level_lvpecl_out2 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT2_810MV; + //set the registers (divider - 1) + _ad9510_regs.divider_low_cycles_out2 = low - 1; + _ad9510_regs.divider_high_cycles_out2 = high - 1; + _ad9510_regs.bypass_divider_out2 = 0; + this->write_reg(0x3e); + this->write_reg(0x4c); + break; + + case 4: //clock 5 + _ad9510_regs.power_down_lvds_cmos_out5 = enb? 0 : 1; + _ad9510_regs.lvds_cmos_select_out5 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT5_LVDS; + _ad9510_regs.output_level_lvds_out5 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT5_1_75MA; + //set the registers (divider - 1) + _ad9510_regs.divider_low_cycles_out5 = low - 1; + _ad9510_regs.divider_high_cycles_out5 = high - 1; + _ad9510_regs.bypass_divider_out5 = 0; + this->write_reg(0x41); + this->write_reg(0x52); + break; + + //TODO FIXME do i want to throw, what about uninitialized boards? + //default: throw std::runtime_error("unknown rev hi in mboard eeprom"); + default: std::cerr << "unknown rev hi: " << rev_hi << std::endl; + } + this->update_regs(); } //uses output clock 7 (cmos) diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 97bda51fc..c8da03955 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 94ff5c2ce..b0603f951 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -150,7 +150,8 @@ 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 +190,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); } |