summaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
Diffstat (limited to 'host')
-rw-r--r--host/CMakeLists.txt6
-rw-r--r--host/docs/build.rst39
-rw-r--r--host/docs/coding.rst12
-rw-r--r--host/docs/dboards.rst10
-rw-r--r--host/docs/usrp2.rst16
-rw-r--r--host/examples/benchmark_rx_rate.cpp8
-rw-r--r--host/examples/rx_timed_samples.cpp6
-rw-r--r--host/examples/test_async_messages.cpp14
-rw-r--r--host/examples/test_pps_input.cpp16
-rw-r--r--host/examples/tx_timed_samples.cpp6
-rw-r--r--host/examples/tx_waveforms.cpp6
-rw-r--r--host/include/uhd/device.hpp13
-rw-r--r--host/include/uhd/device.ipp26
-rw-r--r--host/include/uhd/transport/usb_device_handle.hpp16
-rw-r--r--host/include/uhd/transport/usb_zero_copy.hpp2
-rw-r--r--host/include/uhd/usrp/CMakeLists.txt1
-rw-r--r--host/include/uhd/usrp/dsp_props.hpp11
-rw-r--r--host/include/uhd/usrp/simple_usrp.hpp5
-rw-r--r--host/include/uhd/usrp/single_usrp.hpp172
-rw-r--r--host/include/uhd/usrp/tune_helper.hpp18
-rw-r--r--host/lib/transport/CMakeLists.txt5
-rwxr-xr-xhost/lib/transport/gen_convert_types.py10
-rw-r--r--host/lib/transport/libusb1_base.cpp306
-rw-r--r--host/lib/transport/libusb1_base.hpp177
-rw-r--r--host/lib/transport/libusb1_control.cpp73
-rw-r--r--host/lib/transport/libusb1_device_handle.cpp117
-rw-r--r--host/lib/transport/libusb1_zero_copy.cpp526
-rw-r--r--host/lib/transport/msvc/stdint.h35
-rw-r--r--host/lib/transport/vrt_packet_handler.hpp58
-rw-r--r--host/lib/usrp/CMakeLists.txt1
-rw-r--r--host/lib/usrp/dboard/db_basic_and_lf.cpp1
-rw-r--r--host/lib/usrp/dboard/db_wbx.cpp2
-rw-r--r--host/lib/usrp/dboard_manager.cpp25
-rw-r--r--host/lib/usrp/mimo_usrp.cpp12
-rw-r--r--host/lib/usrp/simple_usrp.cpp163
-rw-r--r--host/lib/usrp/single_usrp.cpp307
-rw-r--r--host/lib/usrp/tune_helper.cpp38
-rw-r--r--host/lib/usrp/usrp1/codec_ctrl.cpp4
-rw-r--r--host/lib/usrp/usrp1/dsp_impl.cpp97
-rw-r--r--host/lib/usrp/usrp1/io_impl.cpp481
-rw-r--r--host/lib/usrp/usrp1/mboard_impl.cpp74
-rw-r--r--host/lib/usrp/usrp1/usrp1_ctrl.cpp28
-rw-r--r--host/lib/usrp/usrp1/usrp1_iface.cpp4
-rw-r--r--host/lib/usrp/usrp1/usrp1_impl.cpp7
-rw-r--r--host/lib/usrp/usrp1/usrp1_impl.hpp24
-rw-r--r--host/lib/usrp/usrp2/dsp_impl.cpp24
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp4
-rw-r--r--host/test/tune_helper_test.cpp22
48 files changed, 1690 insertions, 1338 deletions
diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt
index ceea5d024..566bfd538 100644
--- a/host/CMakeLists.txt
+++ b/host/CMakeLists.txt
@@ -30,7 +30,7 @@ INCLUDE(${CMAKE_SOURCE_DIR}/config/CPack.cmake)
# Install Dirs
########################################################################
SET(RUNTIME_DIR bin)
-SET(LIBRARY_DIR lib)
+SET(LIBRARY_DIR lib${LIB_SUFFIX})
SET(INCLUDE_DIR include)
SET(PKG_DATA_DIR share/uhd)
SET(PKG_DOC_DIR share/doc/uhd)
@@ -61,7 +61,9 @@ ENDIF(NOT CMAKE_BUILD_TYPE)
IF(CMAKE_COMPILER_IS_GNUCXX)
ADD_DEFINITIONS(-Wall)
ADD_DEFINITIONS(-Wextra)
- ADD_DEFINITIONS(-pedantic)
+ #causes trouble when compiling libusb1.0 on macintosh
+ #comment out until mac ports libusb gets its act together
+ #ADD_DEFINITIONS(-pedantic)
ADD_DEFINITIONS(-ansi)
#only export symbols that are declared to be part of the uhd api:
UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN)
diff --git a/host/docs/build.rst b/host/docs/build.rst
index d7dfd05e5..f37b5dce7 100644
--- a/host/docs/build.rst
+++ b/host/docs/build.rst
@@ -40,7 +40,7 @@ CMake
^^^^^^^^^^^^^^^^
* **Purpose:** generates project build files
* **Version:** at least 2.8
-* **Required for:** build time
+* **Usage:** build time (required)
* **Download URL:** http://www.cmake.org/cmake/resources/software.html
^^^^^^^^^^^^^^^^
@@ -48,16 +48,16 @@ Boost
^^^^^^^^^^^^^^^^
* **Purpose:** C++ library
* **Version:** at least 3.6 unix, at least 4.0 windows
-* **Required for:** build time + run time
+* **Usage:** build time + run time (required)
* **Download URL:** http://www.boost.org/users/download/
* **Download URL (windows installer):** http://www.boostpro.com/download
^^^^^^^^^^^^^^^^
LibUSB
^^^^^^^^^^^^^^^^
-* **Purpose:** USB userspace library
+* **Purpose:** USB-based hardware support
* **Version:** at least 1.0
-* **Required for:** build time + run time (optional)
+* **Usage:** build time + run time (optional)
* **Download URL:** http://www.libusb.org/
^^^^^^^^^^^^^^^^
@@ -65,7 +65,7 @@ Python
^^^^^^^^^^^^^^^^
* **Purpose:** used by Cheetah and utility scripts
* **Version:** at least 2.6
-* **Required for:** build time + run time utility scripts
+* **Usage:** build time + run time utility scripts (required)
* **Download URL:** http://www.python.org/download/
^^^^^^^^^^^^^^^^
@@ -73,7 +73,7 @@ Cheetah
^^^^^^^^^^^^^^^^
* **Purpose:** source code generation
* **Version:** at least 2.0
-* **Required for:** build time
+* **Usage:** build time (required)
* **Download URL:** http://www.cheetahtemplate.org/download.html
* **Download URL (windows installer):** http://feisley.com/python/cheetah/
@@ -81,14 +81,14 @@ Cheetah
Doxygen
^^^^^^^^^^^^^^^^
* **Purpose:** generates html api documentation
-* **Required for:** build time (optional)
+* **Usage:** build time (optional)
* **Download URL:** http://www.stack.nl/~dimitri/doxygen/download.html#latestsrc
^^^^^^^^^^^^^^^^
Docutils
^^^^^^^^^^^^^^^^
* **Purpose:** generates html user manual
-* **Required for:** build time (optional)
+* **Usage:** build time (optional)
* **Download URL:** http://docutils.sourceforge.net/
------------------------------------------------------------------------
@@ -105,9 +105,16 @@ Generate Makefiles with cmake
cd build
cmake ../
-**Notes:**
+Additionally, configuration variables can be passed into cmake via the command line.
+The following common-use configuration variables are listed below:
-* For a custom prefix, use: cmake -DCMAKE_INSTALL_PREFIX=<prefix> ../
+* For a custom install prefix: -DCMAKE_INSTALL_PREFIX=<prefix>
+* To install libs into lib64: cmake -DLIB_SUFFIX=64
+
+Example usage:
+::
+
+ cmake -DCMAKE_INSTALL_PREFIX=/opt/uhd ../
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Build and install
@@ -155,11 +162,15 @@ Build the project in MSVC
**Note:** you may not have permission to build the install target.
You need to be an administrator or to run MSVC as administrator.
-** alternative command line instructions **
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Build the project in MSVC (command line)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Open the Visual Studio Command Prompt Shorcut:
+::
-* Open the Visual Studio Command Prompt Shorcut
-* DevEnv <uhd-repo-path>\host\build\ALL_BUILD.vcproj /Build Release
-* DevEnv <uhd-repo-path>\host\build\INSTALL.vcproj /Build Release
+ cd <uhd-repo-path>\host\build
+ DevEnv ALL_BUILD.vcproj /Build Release
+ DevEnv INSTALL.vcproj /Build Release
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Setup the PATH environment variable
diff --git a/host/docs/coding.rst b/host/docs/coding.rst
index 23f350b0f..d6a19d250 100644
--- a/host/docs/coding.rst
+++ b/host/docs/coding.rst
@@ -23,11 +23,11 @@ The device API provides ways to:
See the documentation in *device.hpp* for reference.
^^^^^^^^^^^^^^^^^^^^^^^^^^^
-High-Level: The simple usrp
+High-Level: The single usrp
^^^^^^^^^^^^^^^^^^^^^^^^^^^
-The goal of the simple usrp API is to wrap high level functions around the device properties.
-The simple usrp provides a fat interface to access the most common properties.
-The simple usrp provides ways to:
+The goal of the single usrp API is to wrap high level functions around the device properties.
+The single usrp provides a fat interface to access the most common properties.
+The single usrp provides ways to:
* Set and get daughterboard gains.
* Set and get daughterboard antennas.
@@ -38,13 +38,13 @@ The simple usrp provides ways to:
* Set the usrp time registers.
* Get the underlying device (as discussed above).
-See the documentation in *usrp/simple_usrp.hpp* for reference.
+See the documentation in *usrp/single_usrp.hpp* for reference.
^^^^^^^^^^^^^^^^^^^^^^^^^^^
High-Level: The mimo usrp
^^^^^^^^^^^^^^^^^^^^^^^^^^^
The mimo usrp API provides a wrapper around a device that represents several motherboards.
-This API provides convenience calls just like the simple usrp,
+This API provides convenience calls just like the single usrp,
however the calls either work across all channels in the configuration,
or take a channel argument to specify which channel to configure.
The mimo usrp provides ways to:
diff --git a/host/docs/dboards.rst b/host/docs/dboards.rst
index 985fbc12b..738a0696d 100644
--- a/host/docs/dboards.rst
+++ b/host/docs/dboards.rst
@@ -15,11 +15,12 @@ properties of each board as well.
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Basic RX and and LFRX
^^^^^^^^^^^^^^^^^^^^^^^^^^^
-The Basic RX and LFRX boards have 3 subdevices:
+The Basic RX and LFRX boards have 4 subdevices:
* **Subdevice A:** real signal on antenna RXA
* **Subdevice B:** real signal on antenna RXB
-* **Subdevice AB:** quadrature subdevice using both antennas
+* **Subdevice AB:** quadrature subdevice using both antennas (IQ)
+* **Subdevice BA:** quadrature subdevice using both antennas (QI)
The boards have no tunable elements or programmable gains.
Though the magic of aliasing, you can down-convert signals
@@ -28,11 +29,12 @@ greater than the Nyquist rate of the ADC.
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Basic TX and and LFTX
^^^^^^^^^^^^^^^^^^^^^^^^^^^
-The Basic TX and LFTX boards have 3 subdevices:
+The Basic TX and LFTX boards have 4 subdevices:
* **Subdevice A:** real signal on antenna TXA
* **Subdevice B:** real signal on antenna TXB
-* **Subdevice AB:** quadrature subdevice using both antennas
+* **Subdevice AB:** quadrature subdevice using both antennas (IQ)
+* **Subdevice BA:** quadrature subdevice using both antennas (QI)
The boards have no tunable elements or programmable gains.
Though the magic of aliasing, you can up-convert signals
diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst
index 745361b77..72a919d1a 100644
--- a/host/docs/usrp2.rst
+++ b/host/docs/usrp2.rst
@@ -174,7 +174,7 @@ buffer incoming samples faster than they can be processed.
However, if you application cannot process samples fast enough,
no amount of buffering can save you.
-By default, the UHD will try to request a reasonably large buffer size for both send and receive.
+By default, the UHD will try to resize both the send and receive buffer for optimum performance.
A warning will be printed on instantiation if the actual buffer size is insufficient.
See the OS specific notes below:
@@ -211,6 +211,20 @@ Hardware setup notes
------------------------------------------------------------------------
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Front panel LEDs
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The LEDs on the front panel can be useful in debugging hardware and software issues.
+The LEDs reveal the following about the state of the device:
+
+* **LED A:** transmitting
+* **LED B:** undocumented
+* **LED C:** receiving
+* **LED D:** firmware loaded
+* **LED E:** undocumented
+* **LED F:** FPGA loaded
+
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Ref Clock - 10MHz
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Using an external 10MHz reference clock requires a signal level between
diff --git a/host/examples/benchmark_rx_rate.cpp b/host/examples/benchmark_rx_rate.cpp
index 8fae813cf..36611f97f 100644
--- a/host/examples/benchmark_rx_rate.cpp
+++ b/host/examples/benchmark_rx_rate.cpp
@@ -17,7 +17,7 @@
#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/safe_main.hpp>
-#include <uhd/usrp/simple_usrp.hpp>
+#include <uhd/usrp/single_usrp.hpp>
#include <boost/math/special_functions/round.hpp>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
@@ -27,7 +27,7 @@
namespace po = boost::program_options;
static inline void test_device(
- uhd::usrp::simple_usrp::sptr sdev,
+ uhd::usrp::single_usrp::sptr sdev,
double rx_rate_sps,
double duration_secs
){
@@ -118,7 +118,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
po::options_description desc("Allowed options");
desc.add_options()
("help", "help message")
- ("args", po::value<std::string>(&args)->default_value(""), "simple uhd device address args")
+ ("args", po::value<std::string>(&args)->default_value(""), "single uhd device address args")
("duration", po::value<double>(&duration)->default_value(10.0), "duration for each test in seconds")
("rate", po::value<double>(&only_rate), "specify to perform a single test as this rate (sps)")
;
@@ -135,7 +135,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//create a usrp device
std::cout << std::endl;
std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
- uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args);
+ uhd::usrp::single_usrp::sptr sdev = uhd::usrp::single_usrp::make(args);
std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl;
sdev->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); //stop if left running
diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp
index 4856f6779..441665900 100644
--- a/host/examples/rx_timed_samples.cpp
+++ b/host/examples/rx_timed_samples.cpp
@@ -17,7 +17,7 @@
#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/safe_main.hpp>
-#include <uhd/usrp/simple_usrp.hpp>
+#include <uhd/usrp/single_usrp.hpp>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
#include <iostream>
@@ -38,7 +38,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
po::options_description desc("Allowed options");
desc.add_options()
("help", "help message")
- ("args", po::value<std::string>(&args)->default_value(""), "simple uhd device address args")
+ ("args", po::value<std::string>(&args)->default_value(""), "single uhd device address args")
("secs", po::value<time_t>(&seconds_in_future)->default_value(3), "number of seconds in the future to receive")
("nsamps", po::value<size_t>(&total_num_samps)->default_value(1000), "total number of samples to receive")
("rxrate", po::value<double>(&rx_rate)->default_value(100e6/16), "rate of incoming samples")
@@ -60,7 +60,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//create a usrp device
std::cout << std::endl;
std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
- uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args);
+ uhd::usrp::single_usrp::sptr sdev = uhd::usrp::single_usrp::make(args);
uhd::device::sptr dev = sdev->get_device();
std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl;
diff --git a/host/examples/test_async_messages.cpp b/host/examples/test_async_messages.cpp
index e02bc5f40..0a5c076ea 100644
--- a/host/examples/test_async_messages.cpp
+++ b/host/examples/test_async_messages.cpp
@@ -18,7 +18,7 @@
#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/safe_main.hpp>
#include <uhd/utils/static.hpp>
-#include <uhd/usrp/simple_usrp.hpp>
+#include <uhd/usrp/single_usrp.hpp>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
#include <complex>
@@ -33,7 +33,7 @@ static const size_t async_to_ms = 100;
* Send a burst of many samples that will fragment internally.
* We expect to not get any async messages.
*/
-void test_no_async_message(uhd::usrp::simple_usrp::sptr sdev){
+void test_no_async_message(uhd::usrp::single_usrp::sptr sdev){
uhd::device::sptr dev = sdev->get_device();
std::cout << "Test no async message... " << std::flush;
@@ -58,7 +58,7 @@ void test_no_async_message(uhd::usrp::simple_usrp::sptr sdev){
" Got unexpected event code 0x%x.\n"
) % async_md.event_code << std::endl;
//clear the async messages
- while (dev->recv_async_msg(async_md, 0));
+ while (dev->recv_async_msg(async_md, 0)){};
}
else{
std::cout << boost::format(
@@ -73,7 +73,7 @@ void test_no_async_message(uhd::usrp::simple_usrp::sptr sdev){
* Send a start of burst packet with no following end of burst.
* We expect to get an underflow(within a burst) async message.
*/
-void test_underflow_message(uhd::usrp::simple_usrp::sptr sdev){
+void test_underflow_message(uhd::usrp::single_usrp::sptr sdev){
uhd::device::sptr dev = sdev->get_device();
std::cout << "Test underflow message... " << std::flush;
@@ -117,7 +117,7 @@ void test_underflow_message(uhd::usrp::simple_usrp::sptr sdev){
* Send a burst packet that occurs at a time in the past.
* We expect to get a time error async message.
*/
-void test_time_error_message(uhd::usrp::simple_usrp::sptr sdev){
+void test_time_error_message(uhd::usrp::single_usrp::sptr sdev){
uhd::device::sptr dev = sdev->get_device();
std::cout << "Test time error message... " << std::flush;
@@ -170,7 +170,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
po::options_description desc("Allowed options");
desc.add_options()
("help", "help message")
- ("args", po::value<std::string>(&args)->default_value(""), "simple uhd device address args")
+ ("args", po::value<std::string>(&args)->default_value(""), "single uhd device address args")
("rate", po::value<double>(&rate)->default_value(1.5e6), "rate of outgoing samples")
;
po::variables_map vm;
@@ -186,7 +186,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//create a usrp device
std::cout << std::endl;
std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
- uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args);
+ uhd::usrp::single_usrp::sptr sdev = uhd::usrp::single_usrp::make(args);
std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl;
//set the tx sample rate
diff --git a/host/examples/test_pps_input.cpp b/host/examples/test_pps_input.cpp
index e01d32910..4b2bb62a3 100644
--- a/host/examples/test_pps_input.cpp
+++ b/host/examples/test_pps_input.cpp
@@ -17,7 +17,7 @@
#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/safe_main.hpp>
-#include <uhd/usrp/simple_usrp.hpp>
+#include <uhd/usrp/single_usrp.hpp>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
#include <boost/thread.hpp>
@@ -31,13 +31,13 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//variables to be set by po
std::string args;
- float seconds;
+ double seconds;
//setup the program options
po::options_description desc("Allowed options");
desc.add_options()
("help", "help message")
- ("args", po::value<std::string>(&args)->default_value(""), "simple uhd device address args")
+ ("args", po::value<std::string>(&args)->default_value(""), "single uhd device address args")
;
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
@@ -52,7 +52,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//create a usrp device
std::cout << std::endl;
std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
- uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args);
+ uhd::usrp::single_usrp::sptr sdev = uhd::usrp::single_usrp::make(args);
uhd::device::sptr dev = sdev->get_device();
std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl;
@@ -60,20 +60,20 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::cout << "Set time to known value (100.0) without regard to pps:" << std::endl;
sdev->set_time_now(uhd::time_spec_t(100.0));
boost::this_thread::sleep(boost::posix_time::seconds(1));
- std::cout << boost::format("Reading time 1 second later: %f\n") % (sdev->get_time_now().get_full_secs()) << std::endl;
+ std::cout << boost::format("Reading time 1 second later: %f\n") % (sdev->get_time_now().get_real_secs()) << std::endl;
//store the time to see if PPS resets it
- seconds = sdev->get_time_now().get_full_secs();
+ seconds = sdev->get_time_now().get_real_secs();
//set a known time at next PPS, check that time increments
uhd::time_spec_t time_spec = uhd::time_spec_t(0.0);
std::cout << "Set time to known value (0.0) at next pps:" << std::endl;
sdev->set_time_next_pps(time_spec);
boost::this_thread::sleep(boost::posix_time::seconds(1));
- std::cout << boost::format("Reading time 1 second later: %f\n") % (sdev->get_time_now().get_full_secs()) << std::endl;
+ std::cout << boost::format("Reading time 1 second later: %f\n") % (sdev->get_time_now().get_real_secs()) << std::endl;
//finished
- if (seconds > sdev->get_time_now().get_full_secs()){
+ if (seconds > sdev->get_time_now().get_real_secs()){
std::cout << std::endl << "Success!" << std::endl << std::endl;
return 0;
} else {
diff --git a/host/examples/tx_timed_samples.cpp b/host/examples/tx_timed_samples.cpp
index 5b72bd72f..f34c121d5 100644
--- a/host/examples/tx_timed_samples.cpp
+++ b/host/examples/tx_timed_samples.cpp
@@ -17,7 +17,7 @@
#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/safe_main.hpp>
-#include <uhd/usrp/simple_usrp.hpp>
+#include <uhd/usrp/single_usrp.hpp>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
#include <iostream>
@@ -40,7 +40,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
po::options_description desc("Allowed options");
desc.add_options()
("help", "help message")
- ("args", po::value<std::string>(&args)->default_value(""), "simple uhd device address args")
+ ("args", po::value<std::string>(&args)->default_value(""), "single uhd device address args")
("secs", po::value<time_t>(&seconds_in_future)->default_value(3), "number of seconds in the future to transmit")
("nsamps", po::value<size_t>(&total_num_samps)->default_value(1000), "total number of samples to transmit")
("spp", po::value<size_t>(&samps_per_packet)->default_value(1000), "number of samples per packet")
@@ -64,7 +64,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//create a usrp device
std::cout << std::endl;
std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
- uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args);
+ uhd::usrp::single_usrp::sptr sdev = uhd::usrp::single_usrp::make(args);
uhd::device::sptr dev = sdev->get_device();
std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl;
diff --git a/host/examples/tx_waveforms.cpp b/host/examples/tx_waveforms.cpp
index 3f319cf68..50982cf88 100644
--- a/host/examples/tx_waveforms.cpp
+++ b/host/examples/tx_waveforms.cpp
@@ -18,7 +18,7 @@
#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/safe_main.hpp>
#include <uhd/utils/static.hpp>
-#include <uhd/usrp/simple_usrp.hpp>
+#include <uhd/usrp/single_usrp.hpp>
#include <boost/program_options.hpp>
#include <boost/thread/thread_time.hpp> //system time
#include <boost/math/special_functions/round.hpp>
@@ -70,7 +70,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
po::options_description desc("Allowed options");
desc.add_options()
("help", "help message")
- ("args", po::value<std::string>(&args)->default_value(""), "simple uhd device address args")
+ ("args", po::value<std::string>(&args)->default_value(""), "single uhd device address args")
("duration", po::value<size_t>(&total_duration)->default_value(3), "number of seconds to transmit")
("spb", po::value<size_t>(&spb)->default_value(10000), "samples per buffer")
("rate", po::value<double>(&rate)->default_value(1.5e6), "rate of outgoing samples")
@@ -93,7 +93,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//create a usrp device
std::cout << std::endl;
std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
- uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args);
+ uhd::usrp::single_usrp::sptr sdev = uhd::usrp::single_usrp::make(args);
uhd::device::sptr dev = sdev->get_device();
std::cout << boost::format("Using Device: %s") % sdev->get_pp_string() << std::endl;
diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp
index c48b3dfff..2077cae62 100644
--- a/host/include/uhd/device.hpp
+++ b/host/include/uhd/device.hpp
@@ -26,7 +26,6 @@
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
-#include <boost/asio/buffer.hpp>
#include <vector>
namespace uhd{
@@ -140,12 +139,6 @@ public:
send_mode_t send_mode
);
- //! Deprecated
- size_t send(
- const boost::asio::const_buffer &, const tx_metadata_t &,
- const io_type_t &, send_mode_t send_mode
- );
-
/*!
* Receive buffers containing IF data described by the metadata.
*
@@ -196,12 +189,6 @@ public:
size_t timeout_ms = default_recv_timeout_ms
);
- //! Deprecated
- size_t recv(
- const boost::asio::mutable_buffer &, rx_metadata_t &,
- const io_type_t &, recv_mode_t
- );
-
/*!
* Get the maximum number of samples per packet on send.
* \return the number of samples
diff --git a/host/include/uhd/device.ipp b/host/include/uhd/device.ipp
index 603c52859..60a3f535d 100644
--- a/host/include/uhd/device.ipp
+++ b/host/include/uhd/device.ipp
@@ -34,19 +34,6 @@ namespace uhd{
);
}
- UHD_DEPRECATED UHD_INLINE size_t device::send(
- const boost::asio::const_buffer &buff,
- const tx_metadata_t &metadata,
- const io_type_t &io_type,
- send_mode_t send_mode
- ){
- return this->send(
- boost::asio::buffer_cast<const void *>(buff),
- boost::asio::buffer_size(buff)/io_type.size,
- metadata, io_type, send_mode
- );
- }
-
UHD_INLINE size_t device::recv(
void *buff,
size_t nsamps_per_buff,
@@ -62,19 +49,6 @@ namespace uhd{
);
}
- UHD_DEPRECATED UHD_INLINE size_t device::recv(
- const boost::asio::mutable_buffer &buff,
- rx_metadata_t &metadata,
- const io_type_t &io_type,
- recv_mode_t recv_mode
- ){
- return this->recv(
- boost::asio::buffer_cast<void *>(buff),
- boost::asio::buffer_size(buff)/io_type.size,
- metadata, io_type, recv_mode
- );
- }
-
} //namespace uhd
#endif /* INCLUDED_UHD_DEVICE_IPP */
diff --git a/host/include/uhd/transport/usb_device_handle.hpp b/host/include/uhd/transport/usb_device_handle.hpp
index c3eb72b00..9bb7db9c4 100644
--- a/host/include/uhd/transport/usb_device_handle.hpp
+++ b/host/include/uhd/transport/usb_device_handle.hpp
@@ -38,7 +38,7 @@ namespace uhd { namespace transport {
* a true descriptor serial number string. This interface returns the
* actual string descriptor.
*/
-class UHD_API usb_device_handle : boost::noncopyable {
+class usb_device_handle : boost::noncopyable {
public:
typedef boost::shared_ptr<usb_device_handle> sptr;
@@ -46,31 +46,25 @@ public:
* Return the device's serial number
* \return a string describing the device's serial number
*/
- virtual UHD_API std::string get_serial() const = 0;
+ virtual std::string get_serial() const = 0;
/*!
* Return the device's Vendor ID (usually assigned by the USB-IF)
* \return a Vendor ID
*/
- virtual UHD_API boost::uint16_t get_vendor_id() const = 0;
+ virtual boost::uint16_t get_vendor_id() const = 0;
/*!
* Return the device's Product ID (usually assigned by manufacturer)
* \return a Product ID
*/
- virtual UHD_API boost::uint16_t get_product_id() const = 0;
-
- /*!
- * Return the device's USB address
- * \return a Product ID
- */
- virtual UHD_API boost::uint16_t get_device_addr() const = 0;
+ virtual boost::uint16_t get_product_id() const = 0;
/*!
* Return a vector of USB devices on this host
* \return a vector of USB device handles that match vid and pid
*/
- static UHD_API std::vector<usb_device_handle::sptr> get_device_list(boost::uint16_t vid, boost::uint16_t pid);
+ static std::vector<usb_device_handle::sptr> get_device_list(boost::uint16_t vid, boost::uint16_t pid);
}; //namespace usb
diff --git a/host/include/uhd/transport/usb_zero_copy.hpp b/host/include/uhd/transport/usb_zero_copy.hpp
index 2edd6d91d..75232c22a 100644
--- a/host/include/uhd/transport/usb_zero_copy.hpp
+++ b/host/include/uhd/transport/usb_zero_copy.hpp
@@ -53,7 +53,7 @@ public:
static sptr make(usb_device_handle::sptr handle,
unsigned int rx_endpoint,
unsigned int tx_endpoint,
- size_t buff_size = 0,
+ size_t buff_size = 0,
size_t block_size = 0);
};
diff --git a/host/include/uhd/usrp/CMakeLists.txt b/host/include/uhd/usrp/CMakeLists.txt
index 130956f8a..f973e401a 100644
--- a/host/include/uhd/usrp/CMakeLists.txt
+++ b/host/include/uhd/usrp/CMakeLists.txt
@@ -40,6 +40,7 @@ INSTALL(FILES
### interfaces ###
simple_usrp.hpp
+ single_usrp.hpp
mimo_usrp.hpp
DESTINATION ${INCLUDE_DIR}/uhd/usrp
diff --git a/host/include/uhd/usrp/dsp_props.hpp b/host/include/uhd/usrp/dsp_props.hpp
index 75d8c0a60..54ea5666b 100644
--- a/host/include/uhd/usrp/dsp_props.hpp
+++ b/host/include/uhd/usrp/dsp_props.hpp
@@ -37,11 +37,12 @@ namespace uhd{ namespace usrp{
* Set the shift property and read it back to get actual shift.
*/
enum dsp_prop_t{
- DSP_PROP_NAME = 'n', //ro, std::string
- DSP_PROP_OTHERS = 'o', //ro, prop_names_t
- DSP_PROP_FREQ_SHIFT = 'f', //rw, double Hz
- DSP_PROP_CODEC_RATE = 'c', //ro, double Sps
- DSP_PROP_HOST_RATE = 'h' //rw, double Sps
+ DSP_PROP_NAME = 'n', //ro, std::string
+ DSP_PROP_OTHERS = 'o', //ro, prop_names_t
+ DSP_PROP_FREQ_SHIFT = 'f', //rw, double Hz
+ DSP_PROP_FREQ_SHIFT_NAMES = 'F', //ro, prop_names_t
+ DSP_PROP_CODEC_RATE = 'c', //ro, double Sps
+ DSP_PROP_HOST_RATE = 'h' //rw, double Sps
};
}} //namespace
diff --git a/host/include/uhd/usrp/simple_usrp.hpp b/host/include/uhd/usrp/simple_usrp.hpp
index 08b9c01ea..6149f739c 100644
--- a/host/include/uhd/usrp/simple_usrp.hpp
+++ b/host/include/uhd/usrp/simple_usrp.hpp
@@ -33,12 +33,13 @@
namespace uhd{ namespace usrp{
/*!
- * The simple USRP device class:
+ * The simple USRP device class (DEPRECATED):
+ * This interface has been deprecated in favor of the single USRP interface.
* A simple usrp facilitates ease-of-use for most use-case scenarios.
* The wrapper provides convenience functions to tune the devices
* as well as to set the dboard gains, antennas, and other properties.
*/
-class UHD_API simple_usrp : boost::noncopyable{
+class UHD_API UHD_DEPRECATED simple_usrp : boost::noncopyable{
public:
typedef boost::shared_ptr<simple_usrp> sptr;
diff --git a/host/include/uhd/usrp/single_usrp.hpp b/host/include/uhd/usrp/single_usrp.hpp
new file mode 100644
index 000000000..1b89a3620
--- /dev/null
+++ b/host/include/uhd/usrp/single_usrp.hpp
@@ -0,0 +1,172 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_UHD_USRP_SINGLE_USRP_HPP
+#define INCLUDED_UHD_USRP_SINGLE_USRP_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/device.hpp>
+#include <uhd/types/ranges.hpp>
+#include <uhd/types/stream_cmd.hpp>
+#include <uhd/types/clock_config.hpp>
+#include <uhd/types/tune_result.hpp>
+#include <uhd/usrp/subdev_spec.hpp>
+#include <uhd/usrp/dboard_iface.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+#include <vector>
+
+namespace uhd{ namespace usrp{
+
+/*!
+ * The single USRP device class:
+ * A single usrp facilitates ease-of-use for most use-case scenarios.
+ * The wrapper provides convenience functions to tune the devices
+ * as well as to set the dboard gains, antennas, and other properties.
+ * This wrapper supports multi-channel configurations per motherboard.
+ */
+class UHD_API single_usrp : boost::noncopyable{
+public:
+ typedef boost::shared_ptr<single_usrp> sptr;
+
+ /*!
+ * Make a new single usrp from the device address.
+ * \param dev_addr the device address
+ * \return a new single usrp object
+ */
+ static sptr make(const device_addr_t &dev_addr);
+
+ /*!
+ * Get the underlying device object.
+ * This is needed to get access to the streaming API and properties.
+ * \return the device object within this single usrp
+ */
+ virtual device::sptr get_device(void) = 0;
+
+ /*!
+ * Get a printable name for this usrp.
+ * \return a printable string
+ */
+ virtual std::string get_pp_string(void) = 0;
+
+ /*******************************************************************
+ * Misc
+ ******************************************************************/
+ /*!
+ * Gets the current time in the usrp time registers.
+ * \return a timespec representing current usrp time
+ */
+ virtual time_spec_t get_time_now(void) = 0;
+
+ /*!
+ * Sets the time registers on the usrp immediately.
+ * \param time_spec the time to latch into the usrp device
+ */
+ virtual void set_time_now(const time_spec_t &time_spec) = 0;
+
+ /*!
+ * Set the time registers on the usrp at the next pps tick.
+ * The values will not be latched in until the pulse occurs.
+ * It is recommended that the user sleep(1) after calling to ensure
+ * that the time registers will be in a known state prior to use.
+ *
+ * Note: Because this call sets the time on the "next" pps,
+ * the seconds in the time spec should be current seconds + 1.
+ *
+ * \param time_spec the time to latch into the usrp device
+ */
+ virtual void set_time_next_pps(const time_spec_t &time_spec) = 0;
+
+ /*!
+ * Issue a stream command to the usrp device.
+ * This tells the usrp to send samples into the host.
+ * See the documentation for stream_cmd_t for more info.
+ * \param stream_cmd the stream command to issue
+ */
+ virtual void issue_stream_cmd(const stream_cmd_t &stream_cmd) = 0;
+
+ /*!
+ * Set the clock configuration for the usrp device.
+ * This tells the usrp how to get a 10Mhz reference and PPS clock.
+ * See the documentation for clock_config_t for more info.
+ * \param clock_config the clock configuration to set
+ */
+ virtual void set_clock_config(const clock_config_t &clock_config) = 0;
+
+ /*******************************************************************
+ * RX methods
+ ******************************************************************/
+ virtual void set_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec) = 0;
+ virtual uhd::usrp::subdev_spec_t get_rx_subdev_spec(void) = 0;
+
+ virtual void set_rx_rate(double rate) = 0;
+ virtual double get_rx_rate(void) = 0;
+
+ virtual tune_result_t set_rx_freq(double freq, size_t chan = 0) = 0;
+ virtual tune_result_t set_rx_freq(double freq, double lo_off, size_t chan = 0) = 0;
+ virtual double get_rx_freq(size_t chan = 0) = 0;
+ virtual freq_range_t get_rx_freq_range(size_t chan = 0) = 0;
+
+ virtual void set_rx_gain(float gain, size_t chan = 0) = 0;
+ virtual float get_rx_gain(size_t chan = 0) = 0;
+ virtual gain_range_t get_rx_gain_range(size_t chan = 0) = 0;
+
+ virtual void set_rx_antenna(const std::string &ant, size_t chan = 0) = 0;
+ virtual std::string get_rx_antenna(size_t chan = 0) = 0;
+ virtual std::vector<std::string> get_rx_antennas(size_t chan = 0) = 0;
+
+ virtual bool get_rx_lo_locked(size_t chan = 0) = 0;
+
+ /*!
+ * Read the RSSI value from a usrp device.
+ * Or throw if the dboard does not support an RSSI readback.
+ * \return the rssi in dB
+ */
+ virtual float read_rssi(size_t chan = 0) = 0;
+
+ virtual dboard_iface::sptr get_rx_dboard_iface(size_t chan = 0) = 0;
+
+ /*******************************************************************
+ * TX methods
+ ******************************************************************/
+ virtual void set_tx_subdev_spec(const uhd::usrp::subdev_spec_t &spec) = 0;
+ virtual uhd::usrp::subdev_spec_t get_tx_subdev_spec(void) = 0;
+
+ virtual void set_tx_rate(double rate) = 0;
+ virtual double get_tx_rate(void) = 0;
+
+ virtual tune_result_t set_tx_freq(double freq, size_t chan = 0) = 0;
+ virtual tune_result_t set_tx_freq(double freq, double lo_off, size_t chan = 0) = 0;
+ virtual double get_tx_freq(size_t chan = 0) = 0;
+ virtual freq_range_t get_tx_freq_range(size_t chan = 0) = 0;
+
+ virtual void set_tx_gain(float gain, size_t chan = 0) = 0;
+ virtual float get_tx_gain(size_t chan = 0) = 0;
+ virtual gain_range_t get_tx_gain_range(size_t chan = 0) = 0;
+
+ virtual void set_tx_antenna(const std::string &ant, size_t chan = 0) = 0;
+ virtual std::string get_tx_antenna(size_t chan = 0) = 0;
+ virtual std::vector<std::string> get_tx_antennas(size_t chan = 0) = 0;
+
+ virtual bool get_tx_lo_locked(size_t chan = 0) = 0;
+
+ virtual dboard_iface::sptr get_tx_dboard_iface(size_t chan = 0) = 0;
+};
+
+}}
+
+#endif /* INCLUDED_UHD_USRP_SINGLE_USRP_HPP */
diff --git a/host/include/uhd/usrp/tune_helper.hpp b/host/include/uhd/usrp/tune_helper.hpp
index df3907b3e..ec133fa08 100644
--- a/host/include/uhd/usrp/tune_helper.hpp
+++ b/host/include/uhd/usrp/tune_helper.hpp
@@ -31,12 +31,13 @@ namespace uhd{ namespace usrp{
* The ddc cordic is setup to bring the IF down to baseband.
* \param subdev the dboard subdevice object with properties
* \param ddc the mboard dsp object with properties
+ * \param chan the channel of the dsp to tune
* \param target_freq the desired center frequency
* \param lo_offset an offset for the subdevice IF from center
* \return a tune result struct
*/
UHD_API tune_result_t tune_rx_subdev_and_dsp(
- wax::obj subdev, wax::obj ddc,
+ wax::obj subdev, wax::obj ddc, size_t chan,
double target_freq, double lo_offset
);
@@ -46,17 +47,19 @@ namespace uhd{ namespace usrp{
* is calculated based on the subdevice and BW.
*/
UHD_API tune_result_t tune_rx_subdev_and_dsp(
- wax::obj subdev, wax::obj ddc, double target_freq
+ wax::obj subdev, wax::obj ddc,
+ size_t chan, double target_freq
);
/*!
* Calculate the overall frequency from the combination of dboard IF and DDC shift.
* \param subdev the dboard subdevice object with properties
* \param ddc the mboard dsp object with properties
+ * \param chan the channel of the dsp to tune
* \return the overall tune frequency of the system in Hz
*/
UHD_API double derive_freq_from_rx_subdev_and_dsp(
- wax::obj subdev, wax::obj ddc
+ wax::obj subdev, wax::obj ddc, size_t chan
);
/*!
@@ -66,12 +69,13 @@ namespace uhd{ namespace usrp{
* The duc cordic is setup to bring the baseband up to IF.
* \param subdev the dboard subdevice object with properties
* \param duc the mboard dsp object with properties
+ * \param chan the channel of the dsp to tune
* \param target_freq the desired center frequency
* \param lo_offset an offset for the subdevice IF from center
* \return a tune result struct
*/
UHD_API tune_result_t tune_tx_subdev_and_dsp(
- wax::obj subdev, wax::obj duc,
+ wax::obj subdev, wax::obj duc, size_t chan,
double target_freq, double lo_offset
);
@@ -81,17 +85,19 @@ namespace uhd{ namespace usrp{
* is calculated based on the subdevice and BW.
*/
UHD_API tune_result_t tune_tx_subdev_and_dsp(
- wax::obj subdev, wax::obj duc, double target_freq
+ wax::obj subdev, wax::obj duc,
+ size_t chan, double target_freq
);
/*!
* Calculate the overall frequency from the combination of dboard IF and DUC shift.
* \param subdev the dboard subdevice object with properties
* \param duc the mboard dsp object with properties
+ * \param chan the channel of the dsp to tune
* \return the overall tune frequency of the system in Hz
*/
UHD_API double derive_freq_from_tx_subdev_and_dsp(
- wax::obj subdev, wax::obj duc
+ wax::obj subdev, wax::obj duc, size_t chan
);
}}
diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt
index 71a3a1494..61616d077 100644
--- a/host/lib/transport/CMakeLists.txt
+++ b/host/lib/transport/CMakeLists.txt
@@ -30,8 +30,11 @@ IF(LIBUSB_FOUND)
${CMAKE_SOURCE_DIR}/lib/transport/libusb1_control.cpp
${CMAKE_SOURCE_DIR}/lib/transport/libusb1_zero_copy.cpp
${CMAKE_SOURCE_DIR}/lib/transport/libusb1_base.cpp
- ${CMAKE_SOURCE_DIR}/lib/transport/libusb1_device_handle.cpp
+ ${CMAKE_SOURCE_DIR}/lib/transport/libusb1_base.hpp
)
+ IF(MSVC) #include our custom stdint for libusb
+ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/transport/msvc)
+ ENDIF(MSVC)
SET(HAVE_USB_SUPPORT TRUE)
ENDIF(LIBUSB_FOUND)
diff --git a/host/lib/transport/gen_convert_types.py b/host/lib/transport/gen_convert_types.py
index adbd22868..f9509c81d 100755
--- a/host/lib/transport/gen_convert_types.py
+++ b/host/lib/transport/gen_convert_types.py
@@ -99,9 +99,9 @@ void transport::convert_io_type_to_otw_type(
nsamps_per_io_buff
);
#else
- for (size_t i = 0; i < nsamps_per_io_buff; i++){
+ for (size_t i = 0, j = 0; i < nsamps_per_io_buff; i++){
#for $j in range($num_chans)
- reinterpret_cast<$(out_type)_t *>(otw_buff)[i*$num_chans + $j] =
+ reinterpret_cast<$(out_type)_t *>(otw_buff)[j++] =
#if $ph.get_swap_type($pred) == 'bswap'
uhd::byteswap($(converter)(reinterpret_cast<const $(in_type)_t *>(io_buffs[$j])[i]));
#else
@@ -139,13 +139,13 @@ void transport::convert_otw_type_to_io_type(
nsamps_per_io_buff
);
#else
- for (size_t i = 0; i < nsamps_per_io_buff; i++){
+ for (size_t i = 0, j = 0; i < nsamps_per_io_buff; i++){
#for $j in range($num_chans)
reinterpret_cast<$(out_type)_t *>(io_buffs[$j])[i] =
#if $ph.get_swap_type($pred) == 'bswap'
- $(converter)(uhd::byteswap(reinterpret_cast<const $(in_type)_t *>(otw_buff)[i*$num_chans + $j]));
+ $(converter)(uhd::byteswap(reinterpret_cast<const $(in_type)_t *>(otw_buff)[j++]));
#else
- $(converter)(reinterpret_cast<const $(in_type)_t *>(otw_buff)[i*$num_chans + $j]);
+ $(converter)(reinterpret_cast<const $(in_type)_t *>(otw_buff)[j++]);
#end if
#end for
}
diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp
index e21c39aa3..26e864459 100644
--- a/host/lib/transport/libusb1_base.cpp
+++ b/host/lib/transport/libusb1_base.cpp
@@ -17,110 +17,258 @@
#include "libusb1_base.hpp"
#include <uhd/utils/assert.hpp>
+#include <uhd/types/dict.hpp>
+#include <boost/weak_ptr.hpp>
+#include <boost/foreach.hpp>
+#include <boost/thread.hpp>
#include <iostream>
using namespace uhd::transport;
-/**********************************************************
- * Helper Methods
- **********************************************************/
+/***********************************************************************
+ * libusb session
+ **********************************************************************/
+class libusb_session_impl : public libusb::session{
+public:
+ libusb_session_impl(void){
+ UHD_ASSERT_THROW(libusb_init(&_context) == 0);
+ libusb_set_debug(_context, debug_level);
+ _thread_group.create_thread(boost::bind(&libusb_session_impl::run_event_loop, this));
+ }
-/**********************************************************
- * libusb namespace
- **********************************************************/
-void libusb::init(libusb_context **ctx, int debug_level)
-{
- if (libusb_init(ctx) < 0)
- std::cerr << "error: libusb_init" << std::endl;
+ ~libusb_session_impl(void){
+ _running = false;
+ _thread_group.join_all();
+ libusb_exit(_context);
+ }
- libusb_set_debug(*ctx, debug_level);
-}
+ libusb_context *get_context(void) const{
+ return _context;
+ }
-libusb_device_handle *libusb::open_device(libusb_context *ctx,
- usb_device_handle::sptr handle)
-{
- libusb_device_handle *dev_handle = NULL;
- libusb_device **libusb_dev_list;
- size_t dev_cnt = libusb_get_device_list(ctx, &libusb_dev_list);
-
- //find and open the USB device
- for (size_t i = 0; i < dev_cnt; i++) {
- libusb_device *dev = libusb_dev_list[i];
-
- if (compare_device(dev, handle)) {
- libusb_open(dev, &dev_handle);
- libusb_unref_device(dev);
- break;
+private:
+ libusb_context *_context;
+ boost::thread_group _thread_group;
+ bool _running;
+
+ void run_event_loop(void){
+ _running = true;
+ timeval tv;
+ while(_running){
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000; //100ms
+ libusb_handle_events_timeout(this->get_context(), &tv);
}
-
- libusb_unref_device(dev);
}
+};
+
+libusb::session::sptr libusb::session::get_global_session(void){
+ static boost::weak_ptr<session> global_session;
+
+ //not expired -> get existing session
+ if (not global_session.expired()) return global_session.lock();
- return dev_handle;
+ //create a new global session
+ sptr new_global_session(new libusb_session_impl());
+ global_session = new_global_session;
+ return new_global_session;
}
-//note: changed order of checks so it only tries to get_serial and get_device_address if vid and pid match
-//doing this so it doesn't try to open the device if it's not ours
-bool libusb::compare_device(libusb_device *dev,
- usb_device_handle::sptr handle)
-{
- std::string serial = handle->get_serial();
- boost::uint16_t vendor_id = handle->get_vendor_id();
- boost::uint16_t product_id = handle->get_product_id();
- boost::uint8_t device_addr = handle->get_device_addr();
-
- libusb_device_descriptor libusb_desc;
- if (libusb_get_device_descriptor(dev, &libusb_desc) < 0)
- return false;
- if (vendor_id != libusb_desc.idVendor)
- return false;
- if (product_id != libusb_desc.idProduct)
- return false;
- if (serial != get_serial(dev))
- return false;
- if (device_addr != libusb_get_device_address(dev))
- return false;
-
- return true;
+/***********************************************************************
+ * libusb device
+ **********************************************************************/
+class libusb_device_impl : public libusb::device{
+public:
+ libusb_device_impl(libusb_device *dev){
+ _session = libusb::session::get_global_session();
+ _dev = dev;
+ }
+
+ ~libusb_device_impl(void){
+ libusb_unref_device(this->get());
+ }
+
+ libusb_device *get(void) const{
+ return _dev;
+ }
+
+private:
+ libusb::session::sptr _session; //always keep a reference to session
+ libusb_device *_dev;
+};
+
+/***********************************************************************
+ * libusb device list
+ **********************************************************************/
+class libusb_device_list_impl : public libusb::device_list{
+public:
+ libusb_device_list_impl(void){
+ libusb::session::sptr sess = libusb::session::get_global_session();
+
+ //allocate a new list of devices
+ libusb_device** dev_list;
+ ssize_t ret = libusb_get_device_list(sess->get_context(), &dev_list);
+ if (ret < 0) throw std::runtime_error("cannot enumerate usb devices");
+
+ //fill the vector of device references
+ for (size_t i = 0; i < size_t(ret); i++) _devs.push_back(
+ libusb::device::sptr(new libusb_device_impl(dev_list[i]))
+ );
+
+ //free the device list but dont unref (done in ~device)
+ libusb_free_device_list(dev_list, false/*dont unref*/);
+ }
+
+ size_t size(void) const{
+ return _devs.size();
+ }
+
+ libusb::device::sptr at(size_t i) const{
+ return _devs.at(i);
+ }
+
+private:
+ std::vector<libusb::device::sptr> _devs;
+};
+
+libusb::device_list::sptr libusb::device_list::make(void){
+ return sptr(new libusb_device_list_impl());
}
+/***********************************************************************
+ * libusb device descriptor
+ **********************************************************************/
+class libusb_device_descriptor_impl : public libusb::device_descriptor{
+public:
+ libusb_device_descriptor_impl(libusb::device::sptr dev){
+ _dev = dev;
+ UHD_ASSERT_THROW(libusb_get_device_descriptor(_dev->get(), &_desc) == 0);
+ }
-bool libusb::open_interface(libusb_device_handle *dev_handle,
- int interface)
-{
- int ret = libusb_claim_interface(dev_handle, interface);
- if (ret < 0) {
- std::cerr << "error: libusb_claim_interface() " << ret << std::endl;
- return false;
+ const libusb_device_descriptor &get(void) const{
+ return _desc;
}
- else {
- return true;
+
+ std::string get_ascii_serial(void) const{
+ if (this->get().iSerialNumber == 0) return "";
+
+ libusb::device_handle::sptr handle(
+ libusb::device_handle::get_cached_handle(_dev)
+ );
+
+ unsigned char buff[512];
+ ssize_t ret = libusb_get_string_descriptor_ascii(
+ handle->get(), this->get().iSerialNumber, buff, sizeof(buff)
+ );
+ if (ret < 0) return ""; //on error, just return empty string
+
+ return std::string((char *)buff, ret);
}
+
+private:
+ libusb::device::sptr _dev; //always keep a reference to device
+ libusb_device_descriptor _desc;
+};
+
+libusb::device_descriptor::sptr libusb::device_descriptor::make(device::sptr dev){
+ return sptr(new libusb_device_descriptor_impl(dev));
}
+/***********************************************************************
+ * libusb device handle
+ **********************************************************************/
+class libusb_device_handle_impl : public libusb::device_handle{
+public:
+ libusb_device_handle_impl(libusb::device::sptr dev){
+ _dev = dev;
+ UHD_ASSERT_THROW(libusb_open(_dev->get(), &_handle) == 0);
+ }
+
+ ~libusb_device_handle_impl(void){
+ //release all claimed interfaces
+ for (size_t i = 0; i < _claimed.size(); i++){
+ libusb_release_interface(this->get(), _claimed[i]);
+ }
+ libusb_close(_handle);
+ }
+
+ libusb_device_handle *get(void) const{
+ return _handle;
+ }
-std::string libusb::get_serial(libusb_device *dev)
-{
- unsigned char buff[32];
+ void claim_interface(int interface){
+ UHD_ASSERT_THROW(libusb_claim_interface(this->get(), interface) == 0);
+ _claimed.push_back(interface);
+ }
- libusb_device_descriptor desc;
- if (libusb_get_device_descriptor(dev, &desc) < 0)
- return "";
+private:
+ libusb::device::sptr _dev; //always keep a reference to device
+ libusb_device_handle *_handle;
+ std::vector<int> _claimed;
+};
- if (desc.iSerialNumber == 0)
- return "";
+libusb::device_handle::sptr libusb::device_handle::get_cached_handle(device::sptr dev){
+ static uhd::dict<libusb_device *, boost::weak_ptr<device_handle> > handles;
- //open the device because we have to
- libusb_device_handle *dev_handle;
- if (libusb_open(dev, &dev_handle) < 0)
- return "";
+ //not expired -> get existing session
+ if (handles.has_key(dev->get()) and not handles[dev->get()].expired()){
+ return handles[dev->get()].lock();
+ }
- if (libusb_get_string_descriptor_ascii(dev_handle, desc.iSerialNumber,
- buff, sizeof(buff)) < 0) {
- return "";
+ //create a new global session
+ sptr new_handle(new libusb_device_handle_impl(dev));
+ handles[dev->get()] = new_handle;
+ return new_handle;
+}
+
+/***********************************************************************
+ * libusb special handle
+ **********************************************************************/
+class libusb_special_handle_impl : public libusb::special_handle{
+public:
+ libusb_special_handle_impl(libusb::device::sptr dev){
+ _dev = dev;
}
- libusb_close(dev_handle);
+ libusb::device::sptr get_device(void) const{
+ return _dev;
+ }
+
+ std::string get_serial(void) const{
+ return libusb::device_descriptor::make(this->get_device())->get_ascii_serial();
+ }
+
+ boost::uint16_t get_vendor_id(void) const{
+ return libusb::device_descriptor::make(this->get_device())->get().idVendor;
+ }
+
+ boost::uint16_t get_product_id(void) const{
+ return libusb::device_descriptor::make(this->get_device())->get().idProduct;
+ }
+
+private:
+ libusb::device::sptr _dev; //always keep a reference to device
+};
+
+libusb::special_handle::sptr libusb::special_handle::make(device::sptr dev){
+ return sptr(new libusb_special_handle_impl(dev));
+}
+
+/***********************************************************************
+ * list device handles implementations
+ **********************************************************************/
+std::vector<usb_device_handle::sptr> usb_device_handle::get_device_list(
+ boost::uint16_t vid, boost::uint16_t pid
+){
+ std::vector<usb_device_handle::sptr> handles;
+
+ libusb::device_list::sptr dev_list = libusb::device_list::make();
+ for (size_t i = 0; i < dev_list->size(); i++){
+ usb_device_handle::sptr handle = libusb::special_handle::make(dev_list->at(i));
+ if (handle->get_vendor_id() == vid and handle->get_product_id() == pid){
+ handles.push_back(handle);
+ }
+ }
- return (char*) buff;
+ return handles;
}
diff --git a/host/lib/transport/libusb1_base.hpp b/host/lib/transport/libusb1_base.hpp
index abe5e22a2..04c1d6574 100644
--- a/host/lib/transport/libusb1_base.hpp
+++ b/host/lib/transport/libusb1_base.hpp
@@ -15,80 +15,135 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#ifndef INCLUDED_TRANSPORT_LIBUSB_HPP
-#define INCLUDED_TRANSPORT_LIBUSB_HPP
+#ifndef INCLUDED_LIBUHD_TRANSPORT_LIBUSB_HPP
+#define INCLUDED_LIBUHD_TRANSPORT_LIBUSB_HPP
#include <uhd/config.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
#include <uhd/transport/usb_device_handle.hpp>
-#include <libusb-1.0/libusb.h>
+#include <libusb.h>
+/***********************************************************************
+ * Libusb object oriented smart pointer wrappers:
+ * The following wrappers provide allocation and automatic deallocation
+ * for various libusb data types and handles. The construction routines
+ * also store tables of already allocated structures to avoid multiple
+ * occurrences of opened handles (for example).
+ **********************************************************************/
namespace uhd { namespace transport {
namespace libusb {
- /*
- * Initialize libusb and set debug level
- * Takes a pointer to context pointer because that's
- * how libusb rolls. Debug levels.
- *
- * Level 0: no messages ever printed by the library (default)
- * Level 1: error messages are printed to stderr
- * Level 2: warning and error messages are printed to stderr
- * Level 3: informational messages are printed to stdout, warning
- * and error messages are printed to stderr
- *
- * \param ctx pointer to context pointer
- * \param debug_level
+
+ /*!
+ * This session class holds a global libusb context for this process.
+ * The get global session call will create a new context if none exists.
+ * When all references to session are destroyed, the context will be freed.
*/
- void init(libusb_context **ctx, int debug_level);
-
- /*
- * Open the device specified by a generic handle
- * Find the libusb_device cooresponding to the generic handle
- * and open it for I/O, which returns a libusb_device_handle
- * ready for an interface
- * \param ctx the libusb context used for init
- * \return a libusb_device_handle ready for action
+ class session : boost::noncopyable {
+ public:
+ typedef boost::shared_ptr<session> sptr;
+
+ /*!
+ * Level 0: no messages ever printed by the library (default)
+ * Level 1: error messages are printed to stderr
+ * Level 2: warning and error messages are printed to stderr
+ * Level 3: informational messages are printed to stdout, warning
+ * and error messages are printed to stderr
+ */
+ static const int debug_level = 0;
+
+ //! get a shared pointer to the global session
+ static sptr get_global_session(void);
+
+ //! get the underlying libusb context pointer
+ virtual libusb_context *get_context(void) const = 0;
+ };
+
+ /*!
+ * Holds a device pointer with a reference to the session.
*/
- libusb_device_handle *open_device(libusb_context *ctx,
- usb_device_handle::sptr handle);
-
- /*
- * Compare a libusb device with a generic handle
- * Check the descriptors and open the device to check the
- * serial number string. Compare values against the given
- * handle. The libusb context is already implied in the
- * libusb_device.
- * \param dev a libusb_device pointer
- * \param handle a generic handle specifier
- * \return true if handle and device match, false otherwise
+ class device : boost::noncopyable {
+ public:
+ typedef boost::shared_ptr<device> sptr;
+
+ //! get the underlying device pointer
+ virtual libusb_device *get(void) const = 0;
+ };
+
+ /*!
+ * This device list class holds a device list that will be
+ * automatically freed when the last reference is destroyed.
*/
- bool compare_device(libusb_device *dev, usb_device_handle::sptr handle);
-
- /*
- * Open an interface to the device
- * This is a logical operation for operating system housekeeping as
- * nothing is sent over the bus. The interface much correspond
- * to the USB device descriptors.
- * \param dev_handle libusb handle to an opened device
- * \param interface integer of the interface to use
- * \return true on success, false on error
+ class device_list : boost::noncopyable {
+ public:
+ typedef boost::shared_ptr<device_list> sptr;
+
+ //! make a new device list
+ static sptr make(void);
+
+ //! the number of devices in this list
+ virtual size_t size() const = 0;
+
+ //! get the device pointer at a particular index
+ virtual device::sptr at(size_t index) const = 0;
+ };
+
+ /*!
+ * Holds a device descriptor and a reference to the device.
*/
- bool open_interface(libusb_device_handle *dev_handle, int interface);
-
- /*
- * Get serial number
- * The standard USB device descriptor contains an index to an
- * actual serial number string descriptor. The index is readily
- * readble, but the string descriptor requires probing the device.
- * Because this call attempts to open the device, it may not
- * succeed because not all USB devices are readily opened.
- * The default language is used for the request (English).
- * \param dev a libusb_device pointer
- * \return string serial number or 0 on error or unavailablity
+ class device_descriptor : boost::noncopyable {
+ public:
+ typedef boost::shared_ptr<device_descriptor> sptr;
+
+ //! make a new descriptor from a device reference
+ static sptr make(device::sptr);
+
+ //! get the underlying device descriptor
+ virtual const libusb_device_descriptor &get(void) const = 0;
+
+ virtual std::string get_ascii_serial(void) const = 0;
+ };
+
+ /*!
+ * Holds a device handle and a reference to the device.
*/
- std::string get_serial(libusb_device *dev);
+ class device_handle : boost::noncopyable {
+ public:
+ typedef boost::shared_ptr<device_handle> sptr;
+
+ //! get a cached handle or make a new one given the device
+ static sptr get_cached_handle(device::sptr);
+
+ //! get the underlying device handle
+ virtual libusb_device_handle *get(void) const = 0;
+
+ /*!
+ * Open USB interfaces for control using magic value
+ * IN interface: 2
+ * OUT interface: 1
+ * Control interface: 0
+ */
+ virtual void claim_interface(int) = 0;
+ };
+
+ /*!
+ * The special handle is our internal implementation of the
+ * usb device handle which is used publicly to identify a device.
+ */
+ class special_handle : public usb_device_handle {
+ public:
+ typedef boost::shared_ptr<special_handle> sptr;
+
+ //! make a new special handle from device
+ static sptr make(device::sptr);
+
+ //! get the underlying device reference
+ virtual device::sptr get_device(void) const = 0;
+ };
+
}
}} //namespace
-#endif /* INCLUDED_TRANSPORT_LIBUSB_HPP */
+#endif /* INCLUDED_LIBUHD_TRANSPORT_LIBUSB_HPP */
diff --git a/host/lib/transport/libusb1_control.cpp b/host/lib/transport/libusb1_control.cpp
index 3531128b2..c989a788c 100644
--- a/host/lib/transport/libusb1_control.cpp
+++ b/host/lib/transport/libusb1_control.cpp
@@ -20,7 +20,6 @@
using namespace uhd::transport;
-const int libusb_debug_level = 0;
const int libusb_timeout = 0;
/***********************************************************************
@@ -28,68 +27,38 @@ const int libusb_timeout = 0;
**********************************************************************/
class libusb_control_impl : public usb_control {
public:
- libusb_control_impl(usb_device_handle::sptr handle);
- ~libusb_control_impl();
+ libusb_control_impl(libusb::device_handle::sptr handle):
+ _handle(handle)
+ {
+ _handle->claim_interface(0 /* control interface */);
+ }
size_t submit(boost::uint8_t request_type,
boost::uint8_t request,
boost::uint16_t value,
boost::uint16_t index,
unsigned char *buff,
- boost::uint16_t length);
+ boost::uint16_t length
+ ){
+ return libusb_control_transfer(_handle->get(),
+ request_type,
+ request,
+ value,
+ index,
+ buff,
+ length,
+ libusb_timeout);
+ }
private:
- libusb_context *_ctx;
- libusb_device_handle *_dev_handle;
+ libusb::device_handle::sptr _handle;
};
-
-libusb_control_impl::libusb_control_impl(usb_device_handle::sptr handle)
-{
- libusb::init(&_ctx, libusb_debug_level);
-
- // Find and open the libusb_device corresponding to the
- // given handle and return the libusb_device_handle
- // that can be used for I/O purposes.
- _dev_handle = libusb::open_device(_ctx, handle);
-
- // Open USB interfaces for control using magic value
- // IN interface: 2
- // OUT interface: 1
- // Control interface: 0
- libusb::open_interface(_dev_handle, 0);
-}
-
-
-libusb_control_impl::~libusb_control_impl()
-{
- libusb_close(_dev_handle);
- libusb_exit(_ctx);
-}
-
-
-size_t libusb_control_impl::submit(boost::uint8_t request_type,
- boost::uint8_t request,
- boost::uint16_t value,
- boost::uint16_t index,
- unsigned char *buff,
- boost::uint16_t length)
-{
- return libusb_control_transfer(_dev_handle,
- request_type,
- request,
- value,
- index,
- buff,
- length,
- libusb_timeout);
-}
-
-
/***********************************************************************
* USB control public make functions
**********************************************************************/
-usb_control::sptr usb_control::make(usb_device_handle::sptr handle)
-{
- return sptr(new libusb_control_impl(handle));
+usb_control::sptr usb_control::make(usb_device_handle::sptr handle){
+ return sptr(new libusb_control_impl(libusb::device_handle::get_cached_handle(
+ boost::static_pointer_cast<libusb::special_handle>(handle)->get_device()
+ )));
}
diff --git a/host/lib/transport/libusb1_device_handle.cpp b/host/lib/transport/libusb1_device_handle.cpp
deleted file mode 100644
index 43d0f0e26..000000000
--- a/host/lib/transport/libusb1_device_handle.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-//
-// Copyright 2010 Ettus Research LLC
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-//
-
-#include "libusb1_base.hpp"
-#include <uhd/utils/assert.hpp>
-#include <iostream>
-
-using namespace uhd::transport;
-
-const int libusb_debug_level = 0;
-
-/****************************************************************
- * libusb USB device handle implementation class
- ***************************************************************/
-class libusb1_device_handle_impl : public usb_device_handle {
-public:
- libusb1_device_handle_impl(std::string serial,
- boost::uint32_t product_id,
- boost::uint32_t vendor_id,
- boost::uint32_t device_addr)
- : _serial(serial), _product_id(product_id),
- _vendor_id(vendor_id), _device_addr(device_addr)
- {
- /* NOP */
- }
-
- ~libusb1_device_handle_impl()
- {
- /* NOP */
- }
-
- std::string get_serial() const
- {
- return _serial;
- }
-
- boost::uint16_t get_vendor_id() const
- {
- return _vendor_id;
- }
-
-
- boost::uint16_t get_product_id() const
- {
- return _product_id;
- }
-
- boost::uint16_t get_device_addr() const
- {
- return _device_addr;
- }
-
-private:
- std::string _serial;
- boost::uint32_t _product_id;
- boost::uint32_t _vendor_id;
- boost::uint32_t _device_addr;
-};
-
-
-usb_device_handle::sptr make_usb_device_handle(libusb_device *dev)
-{
- libusb_device_descriptor desc;
-
- if (libusb_get_device_descriptor(dev, &desc) < 0) {
- UHD_ASSERT_THROW("USB: failed to get device descriptor");
- }
-
- std::string serial = libusb::get_serial(dev);
- boost::uint32_t product_id = desc.idProduct;
- boost::uint32_t vendor_id = desc.idVendor;
- boost::uint32_t device_addr = libusb_get_device_address(dev);
-
- return usb_device_handle::sptr(new libusb1_device_handle_impl(
- serial,
- product_id,
- vendor_id,
- device_addr));
-}
-
-std::vector<usb_device_handle::sptr> usb_device_handle::get_device_list(boost::uint16_t vid, boost::uint16_t pid)
-{
- libusb_context *ctx = NULL;
- libusb_device** libusb_device_list;
- std::vector<usb_device_handle::sptr> device_handle_list;
- libusb_device_descriptor desc;
-
- libusb::init(&ctx, libusb_debug_level);
-
- size_t dev_size = libusb_get_device_list(ctx, &libusb_device_list);
- for (size_t i = 0; i < dev_size; i++) {
- libusb_device *dev = libusb_device_list[i];
- if(libusb_get_device_descriptor(dev, &desc) < 0) {
- UHD_ASSERT_THROW("USB: failed to get device descriptor");
- }
- if(desc.idVendor == vid && desc.idProduct == pid) {
- device_handle_list.push_back(make_usb_device_handle(dev));
- }
- }
-
- libusb_exit(ctx);
- return device_handle_list;
-}
diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp
index b890a87f9..b089d11e0 100644
--- a/host/lib/transport/libusb1_zero_copy.cpp
+++ b/host/lib/transport/libusb1_zero_copy.cpp
@@ -17,15 +17,17 @@
#include "libusb1_base.hpp"
#include <uhd/transport/usb_zero_copy.hpp>
+#include <uhd/transport/bounded_buffer.hpp>
#include <uhd/utils/assert.hpp>
-#include <boost/asio.hpp>
-#include <boost/format.hpp>
+#include <boost/shared_array.hpp>
+#include <boost/foreach.hpp>
+#include <boost/thread.hpp>
+#include <vector>
#include <iostream>
#include <iomanip>
using namespace uhd::transport;
-const int libusb_debug_level = 0;
const int libusb_timeout = 0;
/***********************************************************************
@@ -57,53 +59,57 @@ void pp_transfer(libusb_transfer *lut)
* interface provided by the kernel.
**********************************************************************/
class usb_endpoint {
+public:
+ typedef boost::shared_ptr<usb_endpoint> sptr;
+
+ usb_endpoint(
+ libusb::device_handle::sptr handle,
+ int endpoint,
+ bool input,
+ size_t transfer_size,
+ size_t num_transfers
+ );
+
+ ~usb_endpoint(void);
+
+ // Exposed interface for submitting / retrieving transfer buffers
+
+ //! Submit a new transfer that was presumably just filled or emptied.
+ void submit(libusb_transfer *lut);
+
+ /*!
+ * Get an available transfer:
+ * For inputs, this is a just filled transfer.
+ * For outputs, this is a just emptied transfer.
+ * \param timeout_ms the timeout to wait for a lut
+ * \return the transfer pointer or NULL if timeout
+ */
+ libusb_transfer *get_lut_with_wait(size_t timeout_ms = 100);
+
+ //Callback use only
+ void callback_handle_transfer(libusb_transfer *lut);
+
private:
- libusb_device_handle *_dev_handle;
- libusb_context *_ctx;
+ libusb::device_handle::sptr _handle;
int _endpoint;
bool _input;
size_t _transfer_size;
size_t _num_transfers;
- // Transfer state lists (transfers are free, pending, or completed)
- std::list<libusb_transfer *> _free_list;
- std::list<libusb_transfer *> _pending_list;
- std::list<libusb_transfer *> _completed_list;
+ //! hold a bounded buffer of completed transfers
+ typedef bounded_buffer<libusb_transfer *> lut_buff_type;
+ lut_buff_type::sptr _completed_list;
+
+ //! a list of all transfer structs we allocated
+ std::vector<libusb_transfer *> _all_luts;
+
+ //! a list of shared arrays for the transfer buffers
+ std::vector<boost::shared_array<boost::uint8_t> > _buffers;
// Calls for processing asynchronous I/O
libusb_transfer *allocate_transfer(int buff_len);
- bool cancel(libusb_transfer *lut);
- bool cancel_all();
- bool reap_pending_list();
- bool reap_pending_list_timeout();
- bool reap_completed_list();
-
- // Transfer state manipulators
- void free_list_add(libusb_transfer *lut);
- void pending_list_add(libusb_transfer *lut);
- void completed_list_add(libusb_transfer *lut);
- libusb_transfer *free_list_get();
- libusb_transfer *completed_list_get();
- bool pending_list_remove(libusb_transfer *lut);
-
- // Debug use
void print_transfer_status(libusb_transfer *lut);
-
-public:
- usb_endpoint(libusb_device_handle *dev_handle,
- libusb_context *ctx, int endpoint, bool input,
- size_t transfer_size, size_t num_transfers);
-
- ~usb_endpoint();
-
- // Exposed interface for submitting / retrieving transfer buffers
- bool submit(libusb_transfer *lut);
- libusb_transfer *get_completed_transfer();
- libusb_transfer *get_free_transfer();
-
- //Callback use only
- void callback_handle_transfer(libusb_transfer *lut);
};
@@ -116,9 +122,8 @@ public:
* it from the pending to completed status list.
* \param lut pointer to libusb_transfer
*/
-static void callback(libusb_transfer *lut)
-{
- usb_endpoint *endpoint = (usb_endpoint *) lut->user_data;
+static void callback(libusb_transfer *lut){
+ usb_endpoint *endpoint = (usb_endpoint *) lut->user_data;
endpoint->callback_handle_transfer(lut);
}
@@ -127,14 +132,9 @@ static void callback(libusb_transfer *lut)
* Accessor call to allow list access from callback space
* \param pointer to libusb_transfer
*/
-void usb_endpoint::callback_handle_transfer(libusb_transfer *lut)
-{
- if (!pending_list_remove(lut)) {
- std::cerr << "USB: pending remove failed" << std::endl;
- return;
- }
-
- completed_list_add(lut);
+void usb_endpoint::callback_handle_transfer(libusb_transfer *lut){
+ boost::this_thread::disable_interruption di; //disable because the wait can throw
+ _completed_list->push_with_wait(lut);
}
@@ -144,19 +144,28 @@ void usb_endpoint::callback_handle_transfer(libusb_transfer *lut)
* submit the transfers so that they're ready to return when
* data is available.
*/
-usb_endpoint::usb_endpoint(libusb_device_handle *dev_handle,
- libusb_context *ctx, int endpoint, bool input,
- size_t transfer_size, size_t num_transfers)
- : _dev_handle(dev_handle),
- _ctx(ctx), _endpoint(endpoint), _input(input),
- _transfer_size(transfer_size), _num_transfers(num_transfers)
+usb_endpoint::usb_endpoint(
+ libusb::device_handle::sptr handle,
+ int endpoint,
+ bool input,
+ size_t transfer_size,
+ size_t num_transfers
+):
+ _handle(handle),
+ _endpoint(endpoint),
+ _input(input),
+ _transfer_size(transfer_size),
+ _num_transfers(num_transfers)
{
- unsigned int i;
- for (i = 0; i < _num_transfers; i++) {
- free_list_add(allocate_transfer(_transfer_size));
+ _completed_list = lut_buff_type::make(num_transfers);
- if (_input)
- submit(free_list_get());
+ for (size_t i = 0; i < _num_transfers; i++){
+ _all_luts.push_back(allocate_transfer(_transfer_size));
+
+ //input luts are immediately submitted to be filled
+ //output luts go into the completed list as free buffers
+ if (_input) this->submit(_all_luts.back());
+ else _completed_list->push_with_wait(_all_luts.back());
}
}
@@ -168,22 +177,18 @@ usb_endpoint::usb_endpoint(libusb_device_handle *dev_handle,
* the transfers. Libusb will deallocate the data buffer held by
* each transfer.
*/
-usb_endpoint::~usb_endpoint()
-{
- cancel_all();
-
- while (!_pending_list.empty()) {
- if (!reap_pending_list())
- std::cerr << "error: destructor failed to reap" << std::endl;
+usb_endpoint::~usb_endpoint(void){
+ //cancel all transfers
+ BOOST_FOREACH(libusb_transfer *lut, _all_luts){
+ libusb_cancel_transfer(lut);
}
- while (!_completed_list.empty()) {
- if (!reap_completed_list())
- std::cerr << "error: destructor failed to reap" << std::endl;
- }
+ //collect canceled transfers (drain the queue)
+ while (this->get_lut_with_wait() != NULL){};
- while (!_free_list.empty()) {
- libusb_free_transfer(free_list_get());
+ //free all transfers
+ BOOST_FOREACH(libusb_transfer *lut, _all_luts){
+ libusb_free_transfer(lut);
}
}
@@ -195,20 +200,21 @@ usb_endpoint::~usb_endpoint()
* \param buff_len size of the individual buffer held by each transfer
* \return pointer to an allocated libusb_transfer
*/
-libusb_transfer *usb_endpoint::allocate_transfer(int buff_len)
-{
+libusb_transfer *usb_endpoint::allocate_transfer(int buff_len){
libusb_transfer *lut = libusb_alloc_transfer(0);
- unsigned char *buff = new unsigned char[buff_len];
+ boost::shared_array<boost::uint8_t> buff(new boost::uint8_t[buff_len]);
+ _buffers.push_back(buff); //store a reference to this shared array
unsigned int endpoint = ((_endpoint & 0x7f) | (_input ? 0x80 : 0));
+ libusb_transfer_cb_fn lut_callback = libusb_transfer_cb_fn(&callback);
libusb_fill_bulk_transfer(lut, // transfer
- _dev_handle, // dev_handle
+ _handle->get(), // dev_handle
endpoint, // endpoint
- buff, // buffer
+ buff.get(), // buffer
buff_len, // length
- callback, // callback
+ lut_callback, // callback
this, // user_data
0); // timeout
return lut;
@@ -221,95 +227,15 @@ libusb_transfer *usb_endpoint::allocate_transfer(int buff_len)
* \param lut pointer to libusb_transfer
* \return true on success or false on error
*/
-bool usb_endpoint::submit(libusb_transfer *lut)
-{
- int retval;
- if ((retval = libusb_submit_transfer(lut)) < 0) {
- std::cerr << "error: libusb_submit_transfer: " << retval << std::endl;
- return false;
- }
-
- pending_list_add(lut);
- return true;
+void usb_endpoint::submit(libusb_transfer *lut){
+ UHD_ASSERT_THROW(libusb_submit_transfer(lut) == 0);
}
-
-/*
- * Cancel a pending transfer
- * Search the pending list for the transfer and cancel if found.
- * \param lut pointer to libusb_transfer to cancel
- * \return true on success or false if transfer is not found
- *
- * Note: success only indicates submission of cancelation request.
- * Sucessful cancelation is not known until the callback occurs.
- */
-bool usb_endpoint::cancel(libusb_transfer *lut)
-{
- std::list<libusb_transfer*>::iterator iter;
- for (iter = _pending_list.begin(); iter != _pending_list.end(); iter++) {
- if (*iter == lut) {
- libusb_cancel_transfer(lut);
- return true;
- }
- }
- return false;
-}
-
-
-/*
- * Cancel all pending transfers
- * \return bool true if cancelation request is submitted
- *
- * Note: success only indicates submission of cancelation request.
- * Sucessful cancelation is not known until the callback occurs.
- */
-bool usb_endpoint::cancel_all()
-{
- std::list<libusb_transfer*>::iterator iter;
-
- for (iter = _pending_list.begin(); iter != _pending_list.end(); iter++) {
- if (libusb_cancel_transfer(*iter) < 0) {
- std::cerr << "error: libusb_cancal_transfer() failed" << std::endl;
- return false;
- }
- }
-
- return true;
-}
-
-
-/*
- * Reap completed transfers
- * return true if at least one transfer was reaped, false otherwise.
- * Check completed transfers for errors and mark as free. This is a
- * blocking call.
- * \return bool true if a libusb transfer is reaped, false otherwise
- */
-bool usb_endpoint::reap_completed_list()
-{
- libusb_transfer *lut;
-
- if (_completed_list.empty()) {
- if (!reap_pending_list_timeout())
- return false;
- }
-
- while (!_completed_list.empty()) {
- lut = completed_list_get();
- print_transfer_status(lut);
- free_list_add(lut);
- }
-
- return true;
-}
-
-
/*
* Print status errors of a completed transfer
* \param lut pointer to an libusb_transfer
*/
-void usb_endpoint::print_transfer_status(libusb_transfer *lut)
-{
+void usb_endpoint::print_transfer_status(libusb_transfer *lut){
switch (lut->status) {
case LIBUSB_TRANSFER_COMPLETED:
if (lut->actual_length < lut->length) {
@@ -345,166 +271,15 @@ void usb_endpoint::print_transfer_status(libusb_transfer *lut)
}
}
-
-/*
- * Reap pending transfers without timeout
- * This is a blocking call. Reaping submitted transfers is
- * handled by libusb and the assigned callback function.
- * Block until at least one transfer is reaped.
- * \return true true if a transfer was reaped or false otherwise
- */
-bool usb_endpoint::reap_pending_list()
-{
- int retval;
-
- if ((retval = libusb_handle_events(_ctx)) < 0) {
- std::cerr << "error: libusb_handle_events: " << retval << std::endl;
- return false;
- }
-
- return true;
-}
-
-
-/*
- * Reap pending transfers with timeout
- * This call blocks until a transfer is reaped or timeout.
- * Reaping submitted transfers is handled by libusb and the
- * assigned callback function. Block until at least one
- * transfer is reaped or timeout occurs.
- * \return true if a transfer was reaped or false otherwise
- */
-bool usb_endpoint::reap_pending_list_timeout()
-{
- int retval;
- timeval tv;
-
- tv.tv_sec = 0;
- tv.tv_usec = 100000; //100ms
-
- size_t pending_list_size = _pending_list.size();
-
- if ((retval = libusb_handle_events_timeout(_ctx, &tv)) < 0) {
- std::cerr << "error: libusb_handle_events: " << retval << std::endl;
- return false;
- }
-
- if (_pending_list.size() < pending_list_size) {
- return true;
- }
- else {
- return false;
- }
-}
-
-
-/*
- * Get a free transfer
- * The transfer has an empty data bufer for OUT requests
- * \return pointer to a libusb_transfer
- */
-libusb_transfer *usb_endpoint::get_free_transfer()
-{
- if (_free_list.empty()) {
- if (!reap_completed_list())
- return NULL;
- }
-
- return free_list_get();
-}
-
-
-/*
- * Get a completed transfer
- * The transfer has a full data buffer for IN requests
- * \return pointer to libusb_transfer
- */
-libusb_transfer *usb_endpoint::get_completed_transfer()
-{
- if (_completed_list.empty()) {
- if (!reap_pending_list_timeout())
- return NULL;
- }
-
- return completed_list_get();
-}
-
-/*
- * List operations
- */
-void usb_endpoint::free_list_add(libusb_transfer *lut)
-{
- _free_list.push_back(lut);
-}
-
-void usb_endpoint::pending_list_add(libusb_transfer *lut)
-{
- _pending_list.push_back(lut);
-}
-
-void usb_endpoint::completed_list_add(libusb_transfer *lut)
-{
- _completed_list.push_back(lut);
-}
-
-
-/*
- * Free and completed lists don't have ordered content
- * Pop transfers from the front as needed
- */
-libusb_transfer *usb_endpoint::free_list_get()
-{
+libusb_transfer *usb_endpoint::get_lut_with_wait(size_t timeout_ms){
+ boost::this_thread::disable_interruption di; //disable because the wait can throw
libusb_transfer *lut;
-
- if (_free_list.size() == 0) {
- return NULL;
- }
- else {
- lut = _free_list.front();
- _free_list.pop_front();
- return lut;
- }
-}
-
-
-/*
- * Free and completed lists don't have ordered content
- * Pop transfers from the front as needed
- */
-libusb_transfer *usb_endpoint::completed_list_get()
-{
- libusb_transfer *lut;
-
- if (_completed_list.empty()) {
- return NULL;
- }
- else {
- lut = _completed_list.front();
- _completed_list.pop_front();
- return lut;
- }
+ if (_completed_list->pop_with_timed_wait(
+ lut, boost::posix_time::milliseconds(timeout_ms)
+ )) return lut;
+ return NULL;
}
-
-/*
- * Search and remove transfer from pending list
- * Assuming that the callbacks occur in order, the front element
- * should yield the correct transfer. If not, then something else
- * is going on. If no transfers match, then something went wrong.
- */
-bool usb_endpoint::pending_list_remove(libusb_transfer *lut)
-{
- std::list<libusb_transfer*>::iterator iter;
- for (iter = _pending_list.begin(); iter != _pending_list.end(); iter++) {
- if (*iter == lut) {
- _pending_list.erase(iter);
- return true;
- }
- }
- return false;
-}
-
-
/***********************************************************************
* Managed buffers
**********************************************************************/
@@ -518,17 +293,15 @@ bool usb_endpoint::pending_list_remove(libusb_transfer *lut)
class libusb_managed_recv_buffer_impl : public managed_recv_buffer {
public:
libusb_managed_recv_buffer_impl(libusb_transfer *lut,
- usb_endpoint *endpoint)
+ usb_endpoint::sptr endpoint)
: _buff(lut->buffer, lut->length)
{
_lut = lut;
_endpoint = endpoint;
}
- ~libusb_managed_recv_buffer_impl()
- {
- if (!_endpoint->submit(_lut))
- std::cerr << "USB: failed to submit IN transfer" << std::endl;
+ ~libusb_managed_recv_buffer_impl(void){
+ _endpoint->submit(_lut);
}
private:
@@ -538,7 +311,7 @@ private:
}
libusb_transfer *_lut;
- usb_endpoint *_endpoint;
+ usb_endpoint::sptr _endpoint;
const boost::asio::const_buffer _buff;
};
@@ -554,7 +327,7 @@ private:
class libusb_managed_send_buffer_impl : public managed_send_buffer {
public:
libusb_managed_send_buffer_impl(libusb_transfer *lut,
- usb_endpoint *endpoint,
+ usb_endpoint::sptr endpoint,
size_t buff_size)
: _buff(lut->buffer, buff_size), _committed(false)
{
@@ -562,8 +335,7 @@ public:
_endpoint = endpoint;
}
- ~libusb_managed_send_buffer_impl()
- {
+ ~libusb_managed_send_buffer_impl(void){
if (!_committed) {
_lut->length = 0;
_lut->actual_length = 0;
@@ -583,12 +355,14 @@ public:
_lut->length = num_bytes;
_lut->actual_length = 0;
- if (_endpoint->submit(_lut)) {
+ try{
+ _endpoint->submit(_lut);
_committed = true;
return num_bytes;
}
- else {
- return 0;
+ catch(const std::exception &e){
+ std::cerr << "Error in commit: " << e.what() << std::endl;
+ return -1;
}
}
@@ -599,7 +373,7 @@ private:
}
libusb_transfer *_lut;
- usb_endpoint *_endpoint;
+ usb_endpoint::sptr _endpoint;
const boost::asio::mutable_buffer _buff;
bool _committed;
};
@@ -611,14 +385,9 @@ private:
class libusb_zero_copy_impl : public usb_zero_copy
{
private:
- usb_endpoint *_rx_ep;
- usb_endpoint *_tx_ep;
+ usb_endpoint::sptr _rx_ep, _tx_ep;
- // Maintain libusb values
- libusb_context *_rx_ctx;
- libusb_context *_tx_ctx;
- libusb_device_handle *_rx_dev_handle;
- libusb_device_handle *_tx_dev_handle;
+ libusb::device_handle::sptr _handle;
size_t _recv_buff_size;
size_t _send_buff_size;
@@ -627,13 +396,11 @@ private:
public:
typedef boost::shared_ptr<libusb_zero_copy_impl> sptr;
- libusb_zero_copy_impl(usb_device_handle::sptr handle,
+ libusb_zero_copy_impl(libusb::device_handle::sptr handle,
unsigned int rx_endpoint,
unsigned int tx_endpoint,
size_t recv_buff_size,
size_t send_buff_size);
-
- ~libusb_zero_copy_impl();
managed_recv_buffer::sptr get_recv_buff(void);
managed_send_buffer::sptr get_send_buff(void);
@@ -647,73 +414,43 @@ public:
* Initializes libusb, opens devices, and sets up interfaces for I/O.
* Finally, creates endpoints for asynchronous I/O.
*/
-libusb_zero_copy_impl::libusb_zero_copy_impl(usb_device_handle::sptr handle,
+libusb_zero_copy_impl::libusb_zero_copy_impl(libusb::device_handle::sptr handle,
unsigned int rx_endpoint,
unsigned int tx_endpoint,
size_t buff_size,
size_t block_size)
- : _rx_ctx(NULL), _tx_ctx(NULL), _rx_dev_handle(NULL), _tx_dev_handle(NULL),
+ : _handle(handle),
_recv_buff_size(block_size), _send_buff_size(block_size),
_num_frames(buff_size / block_size)
{
- // Initialize libusb with separate contexts to allow
- // thread safe operation of transmit and receive
- libusb::init(&_rx_ctx, libusb_debug_level);
- libusb::init(&_tx_ctx, libusb_debug_level);
-
- UHD_ASSERT_THROW((_rx_ctx != NULL) && (_tx_ctx != NULL));
-
- // Find and open the libusb_device corresponding to the
- // given handle and return the libusb_device_handle
- // that can be used for I/O purposes.
- _rx_dev_handle = libusb::open_device(_rx_ctx, handle);
- _tx_dev_handle = libusb::open_device(_tx_ctx, handle);
-
- // Open USB interfaces for tx/rx using magic values.
- // IN interface: 2
- // OUT interface: 1
- // Control interface: 0
- libusb::open_interface(_rx_dev_handle, 2);
- libusb::open_interface(_tx_dev_handle, 1);
-
- _rx_ep = new usb_endpoint(_rx_dev_handle, // libusb device_handle
- _rx_ctx, // libusb context
+ _handle->claim_interface(2 /*in interface*/);
+ _handle->claim_interface(1 /*out interface*/);
+
+ _rx_ep = usb_endpoint::sptr(new usb_endpoint(
+ _handle, // libusb device_handle
rx_endpoint, // USB endpoint number
true, // IN endpoint
_recv_buff_size, // buffer size per transfer
- _num_frames); // number of libusb transfers
+ _num_frames // number of libusb transfers
+ ));
- _tx_ep = new usb_endpoint(_tx_dev_handle, // libusb device_handle
- _tx_ctx, // libusb context
+ _tx_ep = usb_endpoint::sptr(new usb_endpoint(
+ _handle, // libusb device_handle
tx_endpoint, // USB endpoint number
false, // OUT endpoint
_send_buff_size, // buffer size per transfer
- _num_frames); // number of libusb transfers
+ _num_frames // number of libusb transfers
+ ));
}
-
-libusb_zero_copy_impl::~libusb_zero_copy_impl()
-{
- delete _rx_ep;
- delete _tx_ep;
-
- libusb_close(_rx_dev_handle);
- libusb_close(_tx_dev_handle);
-
- libusb_exit(_rx_ctx);
- libusb_exit(_tx_ctx);
-}
-
-
/*
* Construct a managed receive buffer from a completed libusb transfer
* (happy with buffer full of data) obtained from the receive endpoint.
* Return empty pointer if no transfer is available (timeout or error).
* \return pointer to a managed receive buffer
*/
-managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff()
-{
- libusb_transfer *lut = _rx_ep->get_completed_transfer();
+managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff(void){
+ libusb_transfer *lut = _rx_ep->get_lut_with_wait(/* TODO timeout API */);
if (lut == NULL) {
return managed_recv_buffer::sptr();
}
@@ -731,9 +468,8 @@ managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff()
* (timeout or error).
* \return pointer to a managed send buffer
*/
-managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff()
-{
- libusb_transfer *lut = _tx_ep->get_free_transfer();
+managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff(void){
+ libusb_transfer *lut = _tx_ep->get_lut_with_wait(/* TODO timeout API */);
if (lut == NULL) {
return managed_send_buffer::sptr();
}
@@ -756,12 +492,12 @@ usb_zero_copy::sptr usb_zero_copy::make(usb_device_handle::sptr handle,
size_t block_size)
{
- return sptr(new libusb_zero_copy_impl(handle,
+ libusb::device_handle::sptr dev_handle(libusb::device_handle::get_cached_handle(
+ boost::static_pointer_cast<libusb::special_handle>(handle)->get_device()
+ ));
+ return sptr(new libusb_zero_copy_impl(dev_handle,
rx_endpoint,
tx_endpoint,
buff_size,
block_size));
}
-
-
-
diff --git a/host/lib/transport/msvc/stdint.h b/host/lib/transport/msvc/stdint.h
new file mode 100644
index 000000000..b3eb61aae
--- /dev/null
+++ b/host/lib/transport/msvc/stdint.h
@@ -0,0 +1,35 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_TRANSPORT_STDINT_H
+#define INCLUDED_LIBUHD_TRANSPORT_STDINT_H
+
+#include <boost/cstdint.hpp>
+
+//provide a stdint implementation for libusb
+
+typedef boost::uint64_t uint64_t;
+typedef boost::uint32_t uint32_t;
+typedef boost::uint16_t uint16_t;
+typedef boost::uint8_t uint8_t;
+
+typedef boost::int64_t int64_t;
+typedef boost::int32_t int32_t;
+typedef boost::int16_t int16_t;
+typedef boost::int8_t int8_t;
+
+#endif /* INCLUDED_LIBUHD_TRANSPORT_STDINT_H */
diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp
index 7e0588f03..b603f1371 100644
--- a/host/lib/transport/vrt_packet_handler.hpp
+++ b/host/lib/transport/vrt_packet_handler.hpp
@@ -150,7 +150,8 @@ template <typename T> UHD_INLINE T get_context_code(
const vrt_unpacker_t &vrt_unpacker,
const get_recv_buffs_t &get_recv_buffs,
const handle_overflow_t &handle_overflow,
- size_t vrt_header_offset_words32
+ size_t vrt_header_offset_words32,
+ size_t chans_per_otw_buff
){
metadata.error_code = uhd::rx_metadata_t::ERROR_CODE_NONE;
@@ -184,15 +185,21 @@ template <typename T> UHD_INLINE T get_context_code(
//extract the number of samples available to copy
size_t bytes_per_item = otw_type.get_sample_size();
size_t nsamps_available = state.size_of_copy_buffs/bytes_per_item;
- size_t nsamps_to_copy = std::min(total_samps, nsamps_available);
+ size_t nsamps_to_copy = std::min(total_samps*chans_per_otw_buff, nsamps_available);
size_t bytes_to_copy = nsamps_to_copy*bytes_per_item;
+ size_t nsamps_to_copy_per_io_buff = nsamps_to_copy/chans_per_otw_buff;
+
+ std::vector<void *> io_buffs(chans_per_otw_buff);
+ for (size_t i = 0; i < state.width; i+=chans_per_otw_buff){
+
+ //fill a vector with pointers to the io buffers
+ for (size_t j = 0; j < chans_per_otw_buff; j++){
+ io_buffs[j] = reinterpret_cast<boost::uint8_t *>(buffs[i+j]) + offset_bytes;
+ }
- for (size_t i = 0; i < state.width; i++){
//copy-convert the samples from the recv buffer
uhd::transport::convert_otw_type_to_io_type(
- state.copy_buffs[i], otw_type,
- reinterpret_cast<boost::uint8_t *>(buffs[i]) + offset_bytes,
- io_type, nsamps_to_copy
+ state.copy_buffs[i], otw_type, io_buffs, io_type, nsamps_to_copy_per_io_buff
);
//update the rx copy buffer to reflect the bytes copied
@@ -206,7 +213,7 @@ template <typename T> UHD_INLINE T get_context_code(
metadata.fragment_offset = state.fragment_offset_in_samps;
state.fragment_offset_in_samps += nsamps_to_copy; //set for next call
- return nsamps_to_copy;
+ return nsamps_to_copy_per_io_buff;
}
/*******************************************************************
@@ -224,7 +231,8 @@ template <typename T> UHD_INLINE T get_context_code(
const vrt_unpacker_t &vrt_unpacker,
const get_recv_buffs_t &get_recv_buffs,
const handle_overflow_t &handle_overflow = &handle_overflow_nop,
- size_t vrt_header_offset_words32 = 0
+ size_t vrt_header_offset_words32 = 0,
+ size_t chans_per_otw_buff = 1
){
switch(recv_mode){
@@ -241,7 +249,8 @@ template <typename T> UHD_INLINE T get_context_code(
vrt_unpacker,
get_recv_buffs,
handle_overflow,
- vrt_header_offset_words32
+ vrt_header_offset_words32,
+ chans_per_otw_buff
);
}
@@ -261,7 +270,8 @@ template <typename T> UHD_INLINE T get_context_code(
vrt_unpacker,
get_recv_buffs,
handle_overflow,
- vrt_header_offset_words32
+ vrt_header_offset_words32,
+ chans_per_otw_buff
);
if (num_samps == 0) break; //had a recv timeout or error, break loop
accum_num_samps += num_samps;
@@ -303,29 +313,32 @@ template <typename T> UHD_INLINE T get_context_code(
const uhd::otw_type_t &otw_type,
const vrt_packer_t &vrt_packer,
const get_send_buffs_t &get_send_buffs,
- size_t vrt_header_offset_words32
+ size_t vrt_header_offset_words32,
+ size_t chans_per_otw_buff
){
//load the rest of the if_packet_info in here
- if_packet_info.num_payload_words32 = (num_samps*otw_type.get_sample_size())/sizeof(boost::uint32_t);
+ if_packet_info.num_payload_words32 = (num_samps*chans_per_otw_buff*otw_type.get_sample_size())/sizeof(boost::uint32_t);
if_packet_info.packet_count = state.next_packet_seq++;
//get send buffers for each channel
- managed_send_buffs_t send_buffs(buffs.size());
+ managed_send_buffs_t send_buffs(buffs.size()/chans_per_otw_buff);
UHD_ASSERT_THROW(get_send_buffs(send_buffs));
- for (size_t i = 0; i < buffs.size(); i++){
+ std::vector<const void *> io_buffs(chans_per_otw_buff);
+ for (size_t i = 0; i < buffs.size(); i+=chans_per_otw_buff){
//calculate pointers with offsets to io and otw memory
- const boost::uint8_t *io_mem = reinterpret_cast<const boost::uint8_t *>(buffs[i]) + offset_bytes;
+ for (size_t j = 0; j < chans_per_otw_buff; j++){
+ io_buffs[j] = reinterpret_cast<const boost::uint8_t *>(buffs[i+j]) + offset_bytes;
+ }
boost::uint32_t *otw_mem = send_buffs[i]->cast<boost::uint32_t *>() + vrt_header_offset_words32;
//pack metadata into a vrt header
vrt_packer(otw_mem, if_packet_info);
+ otw_mem += if_packet_info.num_header_words32;
//copy-convert the samples into the send buffer
uhd::transport::convert_io_type_to_otw_type(
- io_mem, io_type,
- otw_mem + if_packet_info.num_header_words32, otw_type,
- num_samps
+ io_buffs, io_type, otw_mem, otw_type, num_samps
);
//commit the samples to the zero-copy interface
@@ -351,7 +364,8 @@ template <typename T> UHD_INLINE T get_context_code(
const vrt_packer_t &vrt_packer,
const get_send_buffs_t &get_send_buffs,
size_t max_samples_per_packet,
- size_t vrt_header_offset_words32 = 0
+ size_t vrt_header_offset_words32 = 0,
+ size_t chans_per_otw_buff = 1
){
//translate the metadata to vrt if packet info
uhd::transport::vrt::if_packet_info_t if_packet_info;
@@ -383,7 +397,8 @@ template <typename T> UHD_INLINE T get_context_code(
io_type, otw_type,
vrt_packer,
get_send_buffs,
- vrt_header_offset_words32
+ vrt_header_offset_words32,
+ chans_per_otw_buff
);
return num_samps;
}
@@ -414,7 +429,8 @@ template <typename T> UHD_INLINE T get_context_code(
io_type, otw_type,
vrt_packer,
get_send_buffs,
- vrt_header_offset_words32
+ vrt_header_offset_words32,
+ chans_per_otw_buff
);
}
return total_num_samps;
diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt
index b5c545988..69a190bfa 100644
--- a/host/lib/usrp/CMakeLists.txt
+++ b/host/lib/usrp/CMakeLists.txt
@@ -26,6 +26,7 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_SOURCE_DIR}/lib/usrp/mimo_usrp.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/misc_utils.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/simple_usrp.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/single_usrp.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/subdev_spec.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/tune_helper.cpp
)
diff --git a/host/lib/usrp/dboard/db_basic_and_lf.cpp b/host/lib/usrp/dboard/db_basic_and_lf.cpp
index 2a9bf2ca5..4b0d8bf27 100644
--- a/host/lib/usrp/dboard/db_basic_and_lf.cpp
+++ b/host/lib/usrp/dboard/db_basic_and_lf.cpp
@@ -59,6 +59,7 @@ private:
static const uhd::dict<std::string, subdev_conn_t> sd_name_to_conn = map_list_of
("AB", SUBDEV_CONN_COMPLEX_IQ)
+ ("BA", SUBDEV_CONN_COMPLEX_QI)
("A", SUBDEV_CONN_REAL_I)
("B", SUBDEV_CONN_REAL_Q)
;
diff --git a/host/lib/usrp/dboard/db_wbx.cpp b/host/lib/usrp/dboard/db_wbx.cpp
index ccd897674..e473ce41e 100644
--- a/host/lib/usrp/dboard/db_wbx.cpp
+++ b/host/lib/usrp/dboard/db_wbx.cpp
@@ -154,7 +154,7 @@ static dboard_base::sptr make_wbx(dboard_base::ctor_args_t args){
}
UHD_STATIC_BLOCK(reg_wbx_dboards){
- dboard_manager::register_dboard(0x0052, 0x0053, &make_wbx, "WBX");
+ dboard_manager::register_dboard(0x0053, 0x0052, &make_wbx, "WBX");
}
/***********************************************************************
diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp
index ab80875f5..181f843a0 100644
--- a/host/lib/usrp/dboard_manager.cpp
+++ b/host/lib/usrp/dboard_manager.cpp
@@ -18,6 +18,7 @@
#include "dboard_ctor_args.hpp"
#include <uhd/usrp/dboard_manager.hpp>
#include <uhd/usrp/subdev_props.hpp>
+#include <uhd/utils/warning.hpp>
#include <uhd/utils/static.hpp>
#include <uhd/utils/assert.hpp>
#include <uhd/types/dict.hpp>
@@ -176,10 +177,6 @@ static args_t get_dboard_args(
){
//special case, the none id was provided, use the following ids
if (dboard_id == dboard_id_t::none() or force_to_unknown){
- std::cerr << boost::format(
- "Warning: unknown dboard-id or dboard-id combination: %s\n"
- " -> defaulting to the unknown board type"
- ) % dboard_id.to_pp_string() << std::endl;
UHD_ASSERT_THROW(get_id_to_args_map().has_key(0xfff1));
UHD_ASSERT_THROW(get_id_to_args_map().has_key(0xfff0));
switch(unit){
@@ -191,6 +188,9 @@ static args_t get_dboard_args(
//verify that there is a registered constructor for this id
if (not get_id_to_args_map().has_key(dboard_id)){
+ uhd::print_warning(str(boost::format(
+ "Unknown dboard ID: %s.\n"
+ ) % dboard_id.to_pp_string()));
return get_dboard_args(unit, dboard_id, true);
}
@@ -214,12 +214,25 @@ dboard_manager_impl::dboard_manager_impl(
(get_xcvr_id_to_id_map()[tx_dboard_id] == rx_dboard_id)
);
+ //warn for invalid dboard id xcvr combinations
+ if (rx_dboard_is_xcvr != this_dboard_is_xcvr or tx_dboard_is_xcvr != this_dboard_is_xcvr){
+ uhd::print_warning(str(boost::format(
+ "Unknown transceiver board ID combination...\n"
+ "RX dboard ID: %s\n"
+ "TX dboard ID: %s\n"
+ ) % rx_dboard_id.to_pp_string() % tx_dboard_id.to_pp_string()));
+ }
+
//extract dboard constructor and settings (force to unknown for messed up xcvr status)
dboard_ctor_t rx_dboard_ctor; std::string rx_name; prop_names_t rx_subdevs;
- boost::tie(rx_dboard_ctor, rx_name, rx_subdevs) = get_dboard_args(dboard_iface::UNIT_RX, rx_dboard_id, rx_dboard_is_xcvr != this_dboard_is_xcvr);
+ boost::tie(rx_dboard_ctor, rx_name, rx_subdevs) = get_dboard_args(
+ dboard_iface::UNIT_RX, rx_dboard_id, rx_dboard_is_xcvr != this_dboard_is_xcvr
+ );
dboard_ctor_t tx_dboard_ctor; std::string tx_name; prop_names_t tx_subdevs;
- boost::tie(tx_dboard_ctor, tx_name, tx_subdevs) = get_dboard_args(dboard_iface::UNIT_TX, tx_dboard_id, tx_dboard_is_xcvr != this_dboard_is_xcvr);
+ boost::tie(tx_dboard_ctor, tx_name, tx_subdevs) = get_dboard_args(
+ dboard_iface::UNIT_TX, tx_dboard_id, tx_dboard_is_xcvr != this_dboard_is_xcvr
+ );
//initialize the gpio pins before creating subdevs
set_nice_dboard_if();
diff --git a/host/lib/usrp/mimo_usrp.cpp b/host/lib/usrp/mimo_usrp.cpp
index e78d38fc0..9331c7fbb 100644
--- a/host/lib/usrp/mimo_usrp.cpp
+++ b/host/lib/usrp/mimo_usrp.cpp
@@ -179,15 +179,15 @@ public:
}
tune_result_t set_rx_freq(size_t chan, double target_freq){
- return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), target_freq);
+ return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), 0, target_freq);
}
tune_result_t set_rx_freq(size_t chan, double target_freq, double lo_off){
- return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), target_freq, lo_off);
+ return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), 0, target_freq, lo_off);
}
double get_rx_freq(size_t chan){
- return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan));
+ return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), 0);
}
freq_range_t get_rx_freq_range(size_t chan){
@@ -255,15 +255,15 @@ public:
}
tune_result_t set_tx_freq(size_t chan, double target_freq){
- return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), target_freq);
+ return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), 0, target_freq);
}
tune_result_t set_tx_freq(size_t chan, double target_freq, double lo_off){
- return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), target_freq, lo_off);
+ return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), 0, target_freq, lo_off);
}
double get_tx_freq(size_t chan){
- return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan));
+ return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), 0);
}
freq_range_t get_tx_freq_range(size_t chan){
diff --git a/host/lib/usrp/simple_usrp.cpp b/host/lib/usrp/simple_usrp.cpp
index e573d0fc0..b89b76eed 100644
--- a/host/lib/usrp/simple_usrp.cpp
+++ b/host/lib/usrp/simple_usrp.cpp
@@ -15,35 +15,20 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
+#include <uhd/usrp/single_usrp.hpp>
#include <uhd/usrp/simple_usrp.hpp>
-#include <uhd/usrp/tune_helper.hpp>
-#include <uhd/utils/assert.hpp>
-#include <uhd/utils/gain_group.hpp>
-#include <uhd/usrp/subdev_props.hpp>
-#include <uhd/usrp/mboard_props.hpp>
-#include <uhd/usrp/device_props.hpp>
-#include <uhd/usrp/dboard_props.hpp>
-#include <uhd/usrp/dsp_props.hpp>
-#include <boost/foreach.hpp>
-#include <boost/format.hpp>
-#include <stdexcept>
-#include <iostream>
+#include <uhd/utils/warning.hpp>
using namespace uhd;
using namespace uhd::usrp;
-static inline freq_range_t add_dsp_shift(const freq_range_t &range, wax::obj dsp){
- double codec_rate = dsp[DSP_PROP_CODEC_RATE].as<double>();
- return freq_range_t(range.min - codec_rate/2.0, range.max + codec_rate/2.0);
-}
-
/***********************************************************************
* Simple USRP Implementation
**********************************************************************/
class simple_usrp_impl : public simple_usrp{
public:
simple_usrp_impl(const device_addr_t &addr){
- _dev = device::make(addr);
+ _sdev = single_usrp::make(addr);
}
~simple_usrp_impl(void){
@@ -51,235 +36,187 @@ public:
}
device::sptr get_device(void){
- return _dev;
+ return _sdev->get_device();
}
std::string get_pp_string(void){
- return str(boost::format(
- "Simple USRP:\n"
- " Device: %s\n"
- " Mboard: %s\n"
- " RX DSP: %s\n"
- " RX Dboard: %s\n"
- " RX Subdev: %s\n"
- " TX DSP: %s\n"
- " TX Dboard: %s\n"
- " TX Subdev: %s\n"
- )
- % (*_dev)[DEVICE_PROP_NAME].as<std::string>()
- % _mboard()[MBOARD_PROP_NAME].as<std::string>()
- % _rx_dsp()[DSP_PROP_NAME].as<std::string>()
- % _rx_dboard()[DBOARD_PROP_NAME].as<std::string>()
- % _rx_subdev()[SUBDEV_PROP_NAME].as<std::string>()
- % _tx_dsp()[DSP_PROP_NAME].as<std::string>()
- % _tx_dboard()[DBOARD_PROP_NAME].as<std::string>()
- % _tx_subdev()[SUBDEV_PROP_NAME].as<std::string>()
- );
+ return _sdev->get_pp_string();
}
/*******************************************************************
* Misc
******************************************************************/
time_spec_t get_time_now(void){
- return _mboard()[MBOARD_PROP_TIME_NOW].as<time_spec_t>();
+ return _sdev->get_time_now();
}
void set_time_now(const time_spec_t &time_spec){
- _mboard()[MBOARD_PROP_TIME_NOW] = time_spec;
+ return _sdev->set_time_now(time_spec);
}
void set_time_next_pps(const time_spec_t &time_spec){
- _mboard()[MBOARD_PROP_TIME_NEXT_PPS] = time_spec;
+ return _sdev->set_time_next_pps(time_spec);
}
void issue_stream_cmd(const stream_cmd_t &stream_cmd){
- _mboard()[MBOARD_PROP_STREAM_CMD] = stream_cmd;
+ return _sdev->issue_stream_cmd(stream_cmd);
}
void set_clock_config(const clock_config_t &clock_config){
- _mboard()[MBOARD_PROP_CLOCK_CONFIG] = clock_config;
+ return _sdev->set_clock_config(clock_config);
}
/*******************************************************************
* RX methods
******************************************************************/
void set_rx_subdev_spec(const subdev_spec_t &spec){
- _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC] = spec;
- std::cout << "RX " << _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().to_pp_string() << std::endl;
+ return _sdev->set_rx_subdev_spec(spec);
}
subdev_spec_t get_rx_subdev_spec(void){
- return _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>();
+ return _sdev->get_rx_subdev_spec();
}
void set_rx_rate(double rate){
- _rx_dsp()[DSP_PROP_HOST_RATE] = rate;
+ return _sdev->set_rx_rate(rate);
}
double get_rx_rate(void){
- return _rx_dsp()[DSP_PROP_HOST_RATE].as<double>();
+ return _sdev->get_rx_rate();
}
tune_result_t set_rx_freq(double target_freq){
- return tune_rx_subdev_and_dsp(_rx_subdev(), _rx_dsp(), target_freq);
+ return _sdev->set_rx_freq(target_freq);
}
tune_result_t set_rx_freq(double target_freq, double lo_off){
- return tune_rx_subdev_and_dsp(_rx_subdev(), _rx_dsp(), target_freq, lo_off);
+ return _sdev->set_rx_freq(target_freq, lo_off);
}
double get_rx_freq(void){
- return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(), _rx_dsp());
+ return _sdev->get_rx_freq();
}
freq_range_t get_rx_freq_range(void){
- return add_dsp_shift(_rx_subdev()[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _rx_dsp());
+ return _sdev->get_rx_freq_range();
}
void set_rx_gain(float gain){
- return _rx_gain_group()->set_value(gain);
+ return _sdev->set_rx_gain(gain);
}
float get_rx_gain(void){
- return _rx_gain_group()->get_value();
+ return _sdev->get_rx_gain();
}
gain_range_t get_rx_gain_range(void){
- return _rx_gain_group()->get_range();
+ return _sdev->get_rx_gain_range();
}
void set_rx_antenna(const std::string &ant){
- _rx_subdev()[SUBDEV_PROP_ANTENNA] = ant;
+ return _sdev->set_rx_antenna(ant);
}
std::string get_rx_antenna(void){
- return _rx_subdev()[SUBDEV_PROP_ANTENNA].as<std::string>();
+ return _sdev->get_rx_antenna();
}
std::vector<std::string> get_rx_antennas(void){
- return _rx_subdev()[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>();
+ return _sdev->get_rx_antennas();
}
bool get_rx_lo_locked(void){
- return _rx_subdev()[SUBDEV_PROP_LO_LOCKED].as<bool>();
+ return _sdev->get_rx_lo_locked();
}
float read_rssi(void){
- return _rx_subdev()[SUBDEV_PROP_RSSI].as<float>();
+ return _sdev->read_rssi();
}
dboard_iface::sptr get_rx_dboard_iface(void){
- return _rx_dboard()[DBOARD_PROP_DBOARD_IFACE].as<dboard_iface::sptr>();
+ return _sdev->get_rx_dboard_iface();
}
/*******************************************************************
* TX methods
******************************************************************/
void set_tx_subdev_spec(const subdev_spec_t &spec){
- _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC] = spec;
- std::cout << "TX " << _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().to_pp_string() << std::endl;
+ return _sdev->set_tx_subdev_spec(spec);
}
subdev_spec_t get_tx_subdev_spec(void){
- return _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>();
+ return _sdev->get_tx_subdev_spec();
}
void set_tx_rate(double rate){
- _tx_dsp()[DSP_PROP_HOST_RATE] = rate;
+ return _sdev->set_tx_rate(rate);
}
double get_tx_rate(void){
- return _tx_dsp()[DSP_PROP_HOST_RATE].as<double>();
+ return _sdev->get_tx_rate();
}
tune_result_t set_tx_freq(double target_freq){
- return tune_tx_subdev_and_dsp(_tx_subdev(), _tx_dsp(), target_freq);
+ return _sdev->set_tx_freq(target_freq);
}
tune_result_t set_tx_freq(double target_freq, double lo_off){
- return tune_tx_subdev_and_dsp(_tx_subdev(), _tx_dsp(), target_freq, lo_off);
+ return _sdev->set_tx_freq(target_freq, lo_off);
}
double get_tx_freq(void){
- return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(), _tx_dsp());
+ return _sdev->get_tx_freq();
}
freq_range_t get_tx_freq_range(void){
- return add_dsp_shift(_tx_subdev()[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _tx_dsp());
+ return _sdev->get_tx_freq_range();
}
void set_tx_gain(float gain){
- return _tx_gain_group()->set_value(gain);
+ return _sdev->set_tx_gain(gain);
}
float get_tx_gain(void){
- return _tx_gain_group()->get_value();
+ return _sdev->get_tx_gain();
}
gain_range_t get_tx_gain_range(void){
- return _tx_gain_group()->get_range();
+ return _sdev->get_tx_gain_range();
}
void set_tx_antenna(const std::string &ant){
- _tx_subdev()[SUBDEV_PROP_ANTENNA] = ant;
+ return _sdev->set_tx_antenna(ant);
}
std::string get_tx_antenna(void){
- return _tx_subdev()[SUBDEV_PROP_ANTENNA].as<std::string>();
+ return _sdev->get_tx_antenna();
}
std::vector<std::string> get_tx_antennas(void){
- return _tx_subdev()[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>();
+ return _sdev->get_tx_antennas();
}
bool get_tx_lo_locked(void){
- return _tx_subdev()[SUBDEV_PROP_LO_LOCKED].as<bool>();
+ return _sdev->get_tx_lo_locked();
}
dboard_iface::sptr get_tx_dboard_iface(void){
- return _tx_dboard()[DBOARD_PROP_DBOARD_IFACE].as<dboard_iface::sptr>();
+ return _sdev->get_tx_dboard_iface();
}
private:
- device::sptr _dev;
- wax::obj _mboard(void){
- return (*_dev)[DEVICE_PROP_MBOARD];
- }
- wax::obj _rx_dsp(void){
- return _mboard()[MBOARD_PROP_RX_DSP];
- }
- wax::obj _tx_dsp(void){
- return _mboard()[MBOARD_PROP_TX_DSP];
- }
- wax::obj _rx_dboard(void){
- std::string db_name = _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().front().db_name;
- return _mboard()[named_prop_t(MBOARD_PROP_RX_DBOARD, db_name)];
- }
- wax::obj _tx_dboard(void){
- std::string db_name = _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().front().db_name;
- return _mboard()[named_prop_t(MBOARD_PROP_TX_DBOARD, db_name)];
- }
- wax::obj _rx_subdev(void){
- std::string sd_name = _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name;
- return _rx_dboard()[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)];
- }
- wax::obj _tx_subdev(void){
- std::string sd_name = _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name;
- return _tx_dboard()[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)];
- }
- gain_group::sptr _rx_gain_group(void){
- std::string sd_name = _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name;
- return _rx_dboard()[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>();
- }
- gain_group::sptr _tx_gain_group(void){
- std::string sd_name = _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name;
- return _tx_dboard()[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>();
- }
+ single_usrp::sptr _sdev;
};
/***********************************************************************
* The Make Function
**********************************************************************/
simple_usrp::sptr simple_usrp::make(const device_addr_t &dev_addr){
+ uhd::print_warning(
+ "The simple USRP interface has been deprecated.\n"
+ "Please switch to the single USRP interface.\n"
+ "#include <uhd/usrp/single_usrp.hpp>\n"
+ "single_usrp::sptr sdev = single_usrp::make(args);\n"
+ );
return sptr(new simple_usrp_impl(dev_addr));
}
diff --git a/host/lib/usrp/single_usrp.cpp b/host/lib/usrp/single_usrp.cpp
new file mode 100644
index 000000000..bb4af44b8
--- /dev/null
+++ b/host/lib/usrp/single_usrp.cpp
@@ -0,0 +1,307 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/usrp/single_usrp.hpp>
+#include <uhd/usrp/tune_helper.hpp>
+#include <uhd/utils/assert.hpp>
+#include <uhd/utils/gain_group.hpp>
+#include <uhd/usrp/subdev_props.hpp>
+#include <uhd/usrp/mboard_props.hpp>
+#include <uhd/usrp/device_props.hpp>
+#include <uhd/usrp/dboard_props.hpp>
+#include <uhd/usrp/dsp_props.hpp>
+#include <boost/foreach.hpp>
+#include <boost/format.hpp>
+#include <stdexcept>
+#include <iostream>
+
+using namespace uhd;
+using namespace uhd::usrp;
+
+static inline freq_range_t add_dsp_shift(const freq_range_t &range, wax::obj dsp){
+ double codec_rate = dsp[DSP_PROP_CODEC_RATE].as<double>();
+ return freq_range_t(range.min - codec_rate/2.0, range.max + codec_rate/2.0);
+}
+
+/***********************************************************************
+ * Simple USRP Implementation
+ **********************************************************************/
+class single_usrp_impl : public single_usrp{
+public:
+ single_usrp_impl(const device_addr_t &addr){
+ _dev = device::make(addr);
+ }
+
+ ~single_usrp_impl(void){
+ /* NOP */
+ }
+
+ device::sptr get_device(void){
+ return _dev;
+ }
+
+ std::string get_pp_string(void){
+ std::string buff = str(boost::format(
+ "Single USRP:\n"
+ " Device: %s\n"
+ " Mboard: %s\n"
+ )
+ % (*_dev)[DEVICE_PROP_NAME].as<std::string>()
+ % _mboard()[MBOARD_PROP_NAME].as<std::string>()
+ );
+
+ //----------- rx side of life ----------------------------------
+ buff += str(boost::format(
+ " RX DSP: %s\n"
+ )
+ % _rx_dsp()[DSP_PROP_NAME].as<std::string>()
+ );
+ for (size_t chan = 0; chan < this->get_rx_subdev_spec().size(); chan++){
+ buff += str(boost::format(
+ " RX Channel: %u\n"
+ " RX Dboard: %s\n"
+ " RX Subdev: %s\n"
+ ) % chan
+ % _rx_dboard(chan)[DBOARD_PROP_NAME].as<std::string>()
+ % _rx_subdev(chan)[SUBDEV_PROP_NAME].as<std::string>()
+ );
+ }
+
+ //----------- tx side of life ----------------------------------
+ buff += str(boost::format(
+ " TX DSP: %s\n"
+ )
+ % _tx_dsp()[DSP_PROP_NAME].as<std::string>()
+ );
+ for (size_t chan = 0; chan < this->get_tx_subdev_spec().size(); chan++){
+ buff += str(boost::format(
+ " TX Channel: %u\n"
+ " TX Dboard: %s\n"
+ " TX Subdev: %s\n"
+ ) % chan
+ % _tx_dboard(chan)[DBOARD_PROP_NAME].as<std::string>()
+ % _tx_subdev(chan)[SUBDEV_PROP_NAME].as<std::string>()
+ );
+ }
+
+ return buff;
+ }
+
+ /*******************************************************************
+ * Misc
+ ******************************************************************/
+ time_spec_t get_time_now(void){
+ return _mboard()[MBOARD_PROP_TIME_NOW].as<time_spec_t>();
+ }
+
+ void set_time_now(const time_spec_t &time_spec){
+ _mboard()[MBOARD_PROP_TIME_NOW] = time_spec;
+ }
+
+ void set_time_next_pps(const time_spec_t &time_spec){
+ _mboard()[MBOARD_PROP_TIME_NEXT_PPS] = time_spec;
+ }
+
+ void issue_stream_cmd(const stream_cmd_t &stream_cmd){
+ _mboard()[MBOARD_PROP_STREAM_CMD] = stream_cmd;
+ }
+
+ void set_clock_config(const clock_config_t &clock_config){
+ _mboard()[MBOARD_PROP_CLOCK_CONFIG] = clock_config;
+ }
+
+ /*******************************************************************
+ * RX methods
+ ******************************************************************/
+ void set_rx_subdev_spec(const subdev_spec_t &spec){
+ _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC] = spec;
+ }
+
+ subdev_spec_t get_rx_subdev_spec(void){
+ return _mboard()[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>();
+ }
+
+ void set_rx_rate(double rate){
+ _rx_dsp()[DSP_PROP_HOST_RATE] = rate;
+ }
+
+ double get_rx_rate(void){
+ return _rx_dsp()[DSP_PROP_HOST_RATE].as<double>();
+ }
+
+ tune_result_t set_rx_freq(double target_freq, size_t chan){
+ return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(), chan, target_freq);
+ }
+
+ tune_result_t set_rx_freq(double target_freq, double lo_off, size_t chan){
+ return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(), chan, target_freq, lo_off);
+ }
+
+ double get_rx_freq(size_t chan){
+ return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(), chan);
+ }
+
+ freq_range_t get_rx_freq_range(size_t chan){
+ return add_dsp_shift(_rx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _rx_dsp());
+ }
+
+ void set_rx_gain(float gain, size_t chan){
+ return _rx_gain_group(chan)->set_value(gain);
+ }
+
+ float get_rx_gain(size_t chan){
+ return _rx_gain_group(chan)->get_value();
+ }
+
+ gain_range_t get_rx_gain_range(size_t chan){
+ return _rx_gain_group(chan)->get_range();
+ }
+
+ void set_rx_antenna(const std::string &ant, size_t chan){
+ _rx_subdev(chan)[SUBDEV_PROP_ANTENNA] = ant;
+ }
+
+ std::string get_rx_antenna(size_t chan){
+ return _rx_subdev(chan)[SUBDEV_PROP_ANTENNA].as<std::string>();
+ }
+
+ std::vector<std::string> get_rx_antennas(size_t chan){
+ return _rx_subdev(chan)[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>();
+ }
+
+ bool get_rx_lo_locked(size_t chan){
+ return _rx_subdev(chan)[SUBDEV_PROP_LO_LOCKED].as<bool>();
+ }
+
+ float read_rssi(size_t chan){
+ return _rx_subdev(chan)[SUBDEV_PROP_RSSI].as<float>();
+ }
+
+ dboard_iface::sptr get_rx_dboard_iface(size_t chan){
+ return _rx_dboard(chan)[DBOARD_PROP_DBOARD_IFACE].as<dboard_iface::sptr>();
+ }
+
+ /*******************************************************************
+ * TX methods
+ ******************************************************************/
+ void set_tx_subdev_spec(const subdev_spec_t &spec){
+ _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC] = spec;
+ }
+
+ subdev_spec_t get_tx_subdev_spec(void){
+ return _mboard()[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>();
+ }
+
+ void set_tx_rate(double rate){
+ _tx_dsp()[DSP_PROP_HOST_RATE] = rate;
+ }
+
+ double get_tx_rate(void){
+ return _tx_dsp()[DSP_PROP_HOST_RATE].as<double>();
+ }
+
+ tune_result_t set_tx_freq(double target_freq, size_t chan){
+ return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(), chan, target_freq);
+ }
+
+ tune_result_t set_tx_freq(double target_freq, double lo_off, size_t chan){
+ return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(), chan, target_freq, lo_off);
+ }
+
+ double get_tx_freq(size_t chan){
+ return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(), chan);
+ }
+
+ freq_range_t get_tx_freq_range(size_t chan){
+ return add_dsp_shift(_tx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _tx_dsp());
+ }
+
+ void set_tx_gain(float gain, size_t chan){
+ return _tx_gain_group(chan)->set_value(gain);
+ }
+
+ float get_tx_gain(size_t chan){
+ return _tx_gain_group(chan)->get_value();
+ }
+
+ gain_range_t get_tx_gain_range(size_t chan){
+ return _tx_gain_group(chan)->get_range();
+ }
+
+ void set_tx_antenna(const std::string &ant, size_t chan){
+ _tx_subdev(chan)[SUBDEV_PROP_ANTENNA] = ant;
+ }
+
+ std::string get_tx_antenna(size_t chan){
+ return _tx_subdev(chan)[SUBDEV_PROP_ANTENNA].as<std::string>();
+ }
+
+ std::vector<std::string> get_tx_antennas(size_t chan){
+ return _tx_subdev(chan)[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>();
+ }
+
+ bool get_tx_lo_locked(size_t chan){
+ return _tx_subdev(chan)[SUBDEV_PROP_LO_LOCKED].as<bool>();
+ }
+
+ dboard_iface::sptr get_tx_dboard_iface(size_t chan){
+ return _tx_dboard(chan)[DBOARD_PROP_DBOARD_IFACE].as<dboard_iface::sptr>();
+ }
+
+private:
+ device::sptr _dev;
+ wax::obj _mboard(void){
+ return (*_dev)[DEVICE_PROP_MBOARD];
+ }
+ wax::obj _rx_dsp(void){
+ return _mboard()[MBOARD_PROP_RX_DSP];
+ }
+ wax::obj _tx_dsp(void){
+ return _mboard()[MBOARD_PROP_TX_DSP];
+ }
+ wax::obj _rx_dboard(size_t chan){
+ std::string db_name = this->get_rx_subdev_spec().at(chan).db_name;
+ return _mboard()[named_prop_t(MBOARD_PROP_RX_DBOARD, db_name)];
+ }
+ wax::obj _tx_dboard(size_t chan){
+ std::string db_name = this->get_tx_subdev_spec().at(chan).db_name;
+ return _mboard()[named_prop_t(MBOARD_PROP_TX_DBOARD, db_name)];
+ }
+ wax::obj _rx_subdev(size_t chan){
+ std::string sd_name = this->get_rx_subdev_spec().at(chan).sd_name;
+ return _rx_dboard(chan)[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)];
+ }
+ wax::obj _tx_subdev(size_t chan){
+ std::string sd_name = this->get_tx_subdev_spec().at(chan).sd_name;
+ return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)];
+ }
+ gain_group::sptr _rx_gain_group(size_t chan){
+ std::string sd_name = this->get_rx_subdev_spec().at(chan).sd_name;
+ return _rx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>();
+ }
+ gain_group::sptr _tx_gain_group(size_t chan){
+ std::string sd_name = this->get_tx_subdev_spec().at(chan).sd_name;
+ return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>();
+ }
+};
+
+/***********************************************************************
+ * The Make Function
+ **********************************************************************/
+single_usrp::sptr single_usrp::make(const device_addr_t &dev_addr){
+ return sptr(new single_usrp_impl(dev_addr));
+}
diff --git a/host/lib/usrp/tune_helper.cpp b/host/lib/usrp/tune_helper.cpp
index e516477d3..7633c67f2 100644
--- a/host/lib/usrp/tune_helper.cpp
+++ b/host/lib/usrp/tune_helper.cpp
@@ -30,11 +30,12 @@ using namespace uhd::usrp;
**********************************************************************/
static tune_result_t tune_xx_subdev_and_dxc(
dboard_iface::unit_t unit,
- wax::obj subdev, wax::obj dxc,
+ wax::obj subdev, wax::obj dxc, size_t chan,
double target_freq, double lo_offset
){
wax::obj subdev_freq_proxy = subdev[SUBDEV_PROP_FREQ];
- wax::obj dxc_freq_proxy = dxc[DSP_PROP_FREQ_SHIFT];
+ std::string freq_name = dxc[DSP_PROP_FREQ_SHIFT_NAMES].as<prop_names_t>().at(chan);
+ wax::obj dxc_freq_proxy = dxc[named_prop_t(DSP_PROP_FREQ_SHIFT, freq_name)];
double dxc_sample_rate = dxc[DSP_PROP_CODEC_RATE].as<double>();
// Ask the d'board to tune as closely as it can to target_freq+lo_offset
@@ -65,11 +66,12 @@ static tune_result_t tune_xx_subdev_and_dxc(
static double derive_freq_from_xx_subdev_and_dxc(
dboard_iface::unit_t unit,
- wax::obj subdev, wax::obj dxc
+ wax::obj subdev, wax::obj dxc, size_t chan
){
//extract actual dsp and IF frequencies
double actual_inter_freq = subdev[SUBDEV_PROP_FREQ].as<double>();
- double actual_dxc_freq = dxc[DSP_PROP_FREQ_SHIFT].as<double>();
+ std::string freq_name = dxc[DSP_PROP_FREQ_SHIFT_NAMES].as<prop_names_t>().at(chan);
+ double actual_dxc_freq = dxc[named_prop_t(DSP_PROP_FREQ_SHIFT, freq_name)].as<double>();
//invert the sign on the dxc freq given the following conditions
if (unit == dboard_iface::UNIT_TX) actual_dxc_freq *= -1.0;
@@ -81,50 +83,54 @@ static double derive_freq_from_xx_subdev_and_dxc(
* RX Tune
**********************************************************************/
tune_result_t usrp::tune_rx_subdev_and_dsp(
- wax::obj subdev, wax::obj ddc,
+ wax::obj subdev, wax::obj ddc, size_t chan,
double target_freq, double lo_offset
){
- return tune_xx_subdev_and_dxc(dboard_iface::UNIT_RX, subdev, ddc, target_freq, lo_offset);
+ return tune_xx_subdev_and_dxc(dboard_iface::UNIT_RX, subdev, ddc, chan, target_freq, lo_offset);
}
tune_result_t usrp::tune_rx_subdev_and_dsp(
wax::obj subdev, wax::obj ddc,
- double target_freq
+ size_t chan, double target_freq
){
double lo_offset = 0.0;
//if the local oscillator will be in the passband, use an offset
if (subdev[SUBDEV_PROP_USE_LO_OFFSET].as<bool>()){
lo_offset = 2.0*ddc[DSP_PROP_HOST_RATE].as<double>();
}
- return tune_rx_subdev_and_dsp(subdev, ddc, target_freq, lo_offset);
+ return tune_rx_subdev_and_dsp(subdev, ddc, chan, target_freq, lo_offset);
}
-double usrp::derive_freq_from_rx_subdev_and_dsp(wax::obj subdev, wax::obj ddc){
- return derive_freq_from_xx_subdev_and_dxc(dboard_iface::UNIT_RX, subdev, ddc);
+double usrp::derive_freq_from_rx_subdev_and_dsp(
+ wax::obj subdev, wax::obj ddc, size_t chan
+){
+ return derive_freq_from_xx_subdev_and_dxc(dboard_iface::UNIT_RX, subdev, ddc, chan);
}
/***********************************************************************
* TX Tune
**********************************************************************/
tune_result_t usrp::tune_tx_subdev_and_dsp(
- wax::obj subdev, wax::obj duc,
+ wax::obj subdev, wax::obj duc, size_t chan,
double target_freq, double lo_offset
){
- return tune_xx_subdev_and_dxc(dboard_iface::UNIT_TX, subdev, duc, target_freq, lo_offset);
+ return tune_xx_subdev_and_dxc(dboard_iface::UNIT_TX, subdev, duc, chan, target_freq, lo_offset);
}
tune_result_t usrp::tune_tx_subdev_and_dsp(
wax::obj subdev, wax::obj duc,
- double target_freq
+ size_t chan, double target_freq
){
double lo_offset = 0.0;
//if the local oscillator will be in the passband, use an offset
if (subdev[SUBDEV_PROP_USE_LO_OFFSET].as<bool>()){
lo_offset = 2.0*duc[DSP_PROP_HOST_RATE].as<double>();
}
- return tune_tx_subdev_and_dsp(subdev, duc, target_freq, lo_offset);
+ return tune_tx_subdev_and_dsp(subdev, duc, chan, target_freq, lo_offset);
}
-double usrp::derive_freq_from_tx_subdev_and_dsp(wax::obj subdev, wax::obj duc){
- return derive_freq_from_xx_subdev_and_dxc(dboard_iface::UNIT_TX, subdev, duc);
+double usrp::derive_freq_from_tx_subdev_and_dsp(
+ wax::obj subdev, wax::obj duc, size_t chan
+){
+ return derive_freq_from_xx_subdev_and_dxc(dboard_iface::UNIT_TX, subdev, duc, chan);
}
diff --git a/host/lib/usrp/usrp1/codec_ctrl.cpp b/host/lib/usrp/usrp1/codec_ctrl.cpp
index 3ab02eeeb..33b18b196 100644
--- a/host/lib/usrp/usrp1/codec_ctrl.cpp
+++ b/host/lib/usrp/usrp1/codec_ctrl.cpp
@@ -129,7 +129,7 @@ usrp1_codec_ctrl_impl::usrp1_codec_ctrl_impl(usrp1_iface::sptr iface,
_ad9862_regs.clkout2_div_factor = ad9862_regs_t::CLKOUT2_DIV_FACTOR_2;
//write the register settings to the codec
- for (uint8_t addr = 0; addr <= 25; addr++) {
+ for (boost::uint8_t addr = 0; addr <= 25; addr++) {
this->send_reg(addr);
}
@@ -202,7 +202,7 @@ float usrp1_codec_ctrl_impl::get_rx_pga_gain(char which){
**********************************************************************/
static float aux_adc_to_volts(boost::uint8_t high, boost::uint8_t low)
{
- return float((boost::uint16_t(high) << 2) | low)*3.3/0x3ff;
+ return float(((boost::uint16_t(high) << 2) | low)*3.3)/0x3ff;
}
float usrp1_codec_ctrl_impl::read_aux_adc(aux_adc_t which)
diff --git a/host/lib/usrp/usrp1/dsp_impl.cpp b/host/lib/usrp/usrp1/dsp_impl.cpp
index d5a88fa2d..e9a5e60a6 100644
--- a/host/lib/usrp/usrp1/dsp_impl.cpp
+++ b/host/lib/usrp/usrp1/dsp_impl.cpp
@@ -21,6 +21,8 @@
#include <uhd/usrp/dsp_props.hpp>
#include <boost/bind.hpp>
#include <boost/format.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/assign/list_of.hpp>
#include <iostream>
#include <cmath>
@@ -42,11 +44,15 @@ void usrp1_impl::rx_dsp_init(void)
/***********************************************************************
* RX DDC Get
**********************************************************************/
-void usrp1_impl::rx_dsp_get(const wax::obj &key, wax::obj &val)
-{
+void usrp1_impl::rx_dsp_get(const wax::obj &key_, wax::obj &val){
+ named_prop_t key = named_prop_t::extract(key_);
+
switch(key.as<dsp_prop_t>()){
case DSP_PROP_NAME:
- val = std::string("usrp1 ddc0");
+ val = str(boost::format("usrp1 ddc %uX %s")
+ % this->get_num_ddcs()
+ % (this->has_rx_halfband()? "+ hb" : "")
+ );
return;
case DSP_PROP_OTHERS:
@@ -54,7 +60,16 @@ void usrp1_impl::rx_dsp_get(const wax::obj &key, wax::obj &val)
return;
case DSP_PROP_FREQ_SHIFT:
- val = _rx_dsp_freq;
+ val = _rx_dsp_freqs[key.name];
+ return;
+
+ case DSP_PROP_FREQ_SHIFT_NAMES:{
+ prop_names_t names;
+ for(size_t i = 0; i < this->get_num_ddcs(); i++){
+ names.push_back(boost::lexical_cast<std::string>(i));
+ }
+ val = names;
+ }
return;
case DSP_PROP_CODEC_RATE:
@@ -73,30 +88,26 @@ void usrp1_impl::rx_dsp_get(const wax::obj &key, wax::obj &val)
/***********************************************************************
* RX DDC Set
**********************************************************************/
-void usrp1_impl::rx_dsp_set(const wax::obj &key, const wax::obj &val)
-{
+void usrp1_impl::rx_dsp_set(const wax::obj &key_, const wax::obj &val){
+ named_prop_t key = named_prop_t::extract(key_);
+
switch(key.as<dsp_prop_t>()) {
case DSP_PROP_FREQ_SHIFT: {
double new_freq = val.as<double>();
boost::uint32_t reg_word = dsp_type1::calc_cordic_word_and_update(
new_freq, _clock_ctrl->get_master_clock_freq());
- //TODO TODO TODO TODO TODO TODO TODO TODO TODO
- //
- // Handle multiple receive channels / DDC's
- //
- //TODO TODO TODO TODO TODO TODO TODO TODO TODO
- _iface->poke32(FR_RX_FREQ_0, reg_word);
- _iface->poke32(FR_RX_FREQ_1, reg_word);
- _iface->poke32(FR_RX_FREQ_2, reg_word);
- _iface->poke32(FR_RX_FREQ_3, reg_word);
-
- _rx_dsp_freq = new_freq;
+ static const uhd::dict<std::string, boost::uint32_t>
+ freq_name_to_reg_val = boost::assign::map_list_of
+ ("0", FR_RX_FREQ_0) ("1", FR_RX_FREQ_1)
+ ("2", FR_RX_FREQ_2) ("3", FR_RX_FREQ_3)
+ ;
+ _iface->poke32(freq_name_to_reg_val[key.name], reg_word);
+ _rx_dsp_freqs[key.name] = new_freq;
return;
}
case DSP_PROP_HOST_RATE: {
- unsigned int rate =
- _clock_ctrl->get_master_clock_freq() / val.as<double>();
+ size_t rate = size_t(_clock_ctrl->get_master_clock_freq() / val.as<double>());
if ((rate & 0x01) || (rate < 4) || (rate > 256)) {
std::cerr << "Decimation must be even and between 4 and 256"
@@ -106,7 +117,7 @@ void usrp1_impl::rx_dsp_set(const wax::obj &key, const wax::obj &val)
_rx_dsp_decim = rate;
//TODO Poll every 100ms. Make it selectable?
- _rx_samps_per_poll_interval = 0.1 * _clock_ctrl->get_master_clock_freq() / rate;
+ _rx_samps_per_poll_interval = size_t(0.1 * _clock_ctrl->get_master_clock_freq() / rate);
_iface->poke32(FR_DECIM_RATE, _rx_dsp_decim/2 - 1);
}
@@ -133,11 +144,15 @@ void usrp1_impl::tx_dsp_init(void)
/***********************************************************************
* TX DUC Get
**********************************************************************/
-void usrp1_impl::tx_dsp_get(const wax::obj &key, wax::obj &val)
-{
+void usrp1_impl::tx_dsp_get(const wax::obj &key_, wax::obj &val){
+ named_prop_t key = named_prop_t::extract(key_);
+
switch(key.as<dsp_prop_t>()) {
case DSP_PROP_NAME:
- val = std::string("usrp1 duc0");
+ val = str(boost::format("usrp1 duc %uX %s")
+ % this->get_num_ducs()
+ % (this->has_tx_halfband()? "+ hb" : "")
+ );
return;
case DSP_PROP_OTHERS:
@@ -145,7 +160,16 @@ void usrp1_impl::tx_dsp_get(const wax::obj &key, wax::obj &val)
return;
case DSP_PROP_FREQ_SHIFT:
- val = _tx_dsp_freq;
+ val = _tx_dsp_freqs[key.name];
+ return;
+
+ case DSP_PROP_FREQ_SHIFT_NAMES:{
+ prop_names_t names;
+ for(size_t i = 0; i < this->get_num_ducs(); i++){
+ names.push_back(boost::lexical_cast<std::string>(i));
+ }
+ val = names;
+ }
return;
case DSP_PROP_CODEC_RATE:
@@ -164,26 +188,25 @@ void usrp1_impl::tx_dsp_get(const wax::obj &key, wax::obj &val)
/***********************************************************************
* TX DUC Set
**********************************************************************/
-void usrp1_impl::tx_dsp_set(const wax::obj &key, const wax::obj &val)
-{
+void usrp1_impl::tx_dsp_set(const wax::obj &key_, const wax::obj &val){
+ named_prop_t key = named_prop_t::extract(key_);
+
switch(key.as<dsp_prop_t>()) {
- //TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO
- //
- // Set both codec frequencies until we have duality properties
- //
- //TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO
case DSP_PROP_FREQ_SHIFT: {
double new_freq = val.as<double>();
- _codec_ctrls[DBOARD_SLOT_A]->set_duc_freq(new_freq);
- _codec_ctrls[DBOARD_SLOT_B]->set_duc_freq(new_freq);
- _tx_dsp_freq = new_freq;
+
+ //map the freq shift key to a subdev spec to a particular codec chip
+ std::string db_name = _tx_subdev_spec.at(boost::lexical_cast<size_t>(key.name)).db_name;
+ if (db_name == "A") _codec_ctrls[DBOARD_SLOT_A]->set_duc_freq(new_freq);
+ if (db_name == "B") _codec_ctrls[DBOARD_SLOT_B]->set_duc_freq(new_freq);
+
+ _tx_dsp_freqs[key.name] = new_freq;
return;
}
case DSP_PROP_HOST_RATE: {
- unsigned int rate =
- _clock_ctrl->get_master_clock_freq() * 2 / val.as<double>();
+ size_t rate = size_t(_clock_ctrl->get_master_clock_freq() * 2 / val.as<double>());
if ((rate & 0x01) || (rate < 8) || (rate > 512)) {
std::cerr << "Interpolation rate must be even and between 8 and 512"
@@ -194,7 +217,7 @@ void usrp1_impl::tx_dsp_set(const wax::obj &key, const wax::obj &val)
_tx_dsp_interp = rate;
//TODO Poll every 100ms. Make it selectable?
- _tx_samps_per_poll_interval = 0.1 * _clock_ctrl->get_master_clock_freq() * 2 / rate;
+ _tx_samps_per_poll_interval = size_t(0.1 * _clock_ctrl->get_master_clock_freq() * 2 / rate);
_iface->poke32(FR_INTERP_RATE, _tx_dsp_interp / 4 - 1);
return;
diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp
index 92e8bc20a..73974f2d6 100644
--- a/host/lib/usrp/usrp1/io_impl.cpp
+++ b/host/lib/usrp/usrp1/io_impl.cpp
@@ -33,294 +33,283 @@ using namespace uhd::usrp;
using namespace uhd::transport;
namespace asio = boost::asio;
-struct usrp1_send_state {
- uhd::transport::managed_send_buffer::sptr send_buff;
- size_t bytes_written;
- size_t underrun_poll_samp_count;
-
- size_t bytes_free()
+/***********************************************************************
+ * Pseudo send buffer implementation
+ **********************************************************************/
+class pseudo_managed_send_buffer : public managed_send_buffer{
+public:
+
+ pseudo_managed_send_buffer(
+ const boost::asio::mutable_buffer &buff,
+ const boost::function<ssize_t(size_t)> &commit
+ ):
+ _buff(buff),
+ _commit(commit)
{
- if (send_buff != NULL)
- return send_buff->size() - bytes_written;
- else
- return 0;
+ /* NOP */
}
-};
-struct usrp1_recv_state {
- uhd::transport::managed_recv_buffer::sptr recv_buff;
- size_t bytes_read;
- size_t overrun_poll_samp_count;
+ ssize_t commit(size_t num_bytes){
+ return _commit(num_bytes);
+ }
- size_t bytes_avail()
- {
- if (recv_buff != NULL)
- return recv_buff->size() - bytes_read;
- else
- return 0;
+private:
+ const boost::asio::mutable_buffer &get(void) const{
+ return _buff;
}
-};
-/***********************************************************************
- * IO Implementation Details
- **********************************************************************/
-struct usrp1_impl::io_impl {
- io_impl();
- ~io_impl(void);
-
- //state handling for buffer management
- usrp1_recv_state recv_state;
- usrp1_send_state send_state;
-
- //send transport management
- bool get_send_buffer(zero_copy_if::sptr zc_if);
- size_t copy_convert_send_samps(const void *buff, size_t num_samps,
- size_t sample_offset, const io_type_t io_type,
- otw_type_t otw_type);
- bool conditional_buff_commit(bool force);
- bool check_underrun(usrp_ctrl::sptr ctrl_if,
- size_t poll_interval, bool force);
-
- //recv transport management
- bool get_recv_buffer(zero_copy_if::sptr zc_if);
- size_t copy_convert_recv_samps(void *buff, size_t num_samps,
- size_t sample_offset, const io_type_t io_type,
- otw_type_t otw_type);
- bool check_overrun(usrp_ctrl::sptr ctrl_if,
- size_t poll_interval, bool force);
+ const boost::asio::mutable_buffer _buff;
+ const boost::function<ssize_t(size_t)> _commit;
};
-usrp1_impl::io_impl::io_impl()
-{
- send_state.send_buff = uhd::transport::managed_send_buffer::sptr();
- recv_state.recv_buff = uhd::transport::managed_recv_buffer::sptr();
-}
-
-usrp1_impl::io_impl::~io_impl(void)
-{
- /* NOP */
-}
-
-void usrp1_impl::io_init(void)
-{
- _rx_otw_type.width = 16;
- _rx_otw_type.shift = 0;
- _rx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN;
-
- _tx_otw_type.width = 16;
- _tx_otw_type.shift = 0;
- _tx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN;
-
- _io_impl = UHD_PIMPL_MAKE(io_impl, ());
-}
-
/***********************************************************************
- * Data Send
+ * IO Implementation Details
**********************************************************************/
-bool usrp1_impl::io_impl::get_send_buffer(zero_copy_if::sptr zc_if)
-{
- if (send_state.send_buff == NULL) {
+struct usrp1_impl::io_impl{
+ io_impl(zero_copy_if::sptr data_transport):
+ data_transport(data_transport),
+ underflow_poll_samp_count(0),
+ overflow_poll_samp_count(0),
+ send_buff(data_transport->get_send_buff()),
+ num_bytes_committed(0)
+ {
+ /* NOP */
+ }
- send_state.send_buff = zc_if->get_send_buff();
- if (send_state.send_buff == NULL)
- return false;
+ ~io_impl(void){
+ flush_send_buff();
+ }
- send_state.bytes_written = 0;
+ zero_copy_if::sptr data_transport;
+
+ //state management for the vrt packet handler code
+ vrt_packet_handler::recv_state packet_handler_recv_state;
+ vrt_packet_handler::send_state packet_handler_send_state;
+
+ //state management for overflow and underflow
+ size_t underflow_poll_samp_count;
+ size_t overflow_poll_samp_count;
+
+ //wrapper around the actual send buffer interface
+ //all of this to ensure only full buffers are committed
+ managed_send_buffer::sptr send_buff;
+ size_t num_bytes_committed;
+ boost::uint8_t pseudo_buff[BYTES_PER_PACKET];
+ ssize_t phony_commit_pseudo_buff(size_t num_bytes);
+ ssize_t phony_commit_send_buff(size_t num_bytes);
+ ssize_t commit_send_buff(void);
+ void flush_send_buff(void);
+ bool get_send_buffs(vrt_packet_handler::managed_send_buffs_t &);
+
+ //helpers to get at the send buffer + offset
+ inline void *get_send_mem_ptr(void){
+ return send_buff->cast<boost::uint8_t *>() + num_bytes_committed;
+ }
+ inline size_t get_send_mem_size(void){
+ return send_buff->size() - num_bytes_committed;
}
+};
- return true;
+/*!
+ * Accept a commit of num bytes to the pseudo buffer.
+ * Memcpy the entire contents of pseudo buffer into send buffers.
+ *
+ * Under most conditions:
+ * The first loop iteration will fill the remainder of the send buffer.
+ * The second loop iteration will empty the pseudo buffer remainder.
+ */
+ssize_t usrp1_impl::io_impl::phony_commit_pseudo_buff(size_t num_bytes){
+ size_t bytes_to_copy = num_bytes, bytes_copied = 0;
+ while(bytes_to_copy){
+ size_t bytes_copied_here = std::min(bytes_to_copy, get_send_mem_size());
+ std::memcpy(get_send_mem_ptr(), pseudo_buff + bytes_copied, bytes_copied_here);
+ ssize_t ret = phony_commit_send_buff(bytes_copied_here);
+ if (ret < 0) return ret;
+ bytes_to_copy -= ret;
+ bytes_copied += ret;
+ }
+ return bytes_copied;
}
-size_t usrp1_impl::io_impl::copy_convert_send_samps(const void *buff,
- size_t num_samps,
- size_t sample_offset,
- const io_type_t io_type,
- otw_type_t otw_type)
-{
- UHD_ASSERT_THROW(send_state.bytes_free() % otw_type.get_sample_size() == 0);
-
- size_t samps_free = send_state.bytes_free() / otw_type.get_sample_size();
- size_t copy_samps = std::min(num_samps - sample_offset, samps_free);
-
- const boost::uint8_t *io_mem =
- reinterpret_cast<const boost::uint8_t *>(buff);
-
- boost::uint8_t *otw_mem = send_state.send_buff->cast<boost::uint8_t *>();
-
- convert_io_type_to_otw_type(io_mem + sample_offset * io_type.size,
- io_type,
- otw_mem + send_state.bytes_written,
- otw_type,
- copy_samps);
-
- send_state.bytes_written += copy_samps * otw_type.get_sample_size();
- send_state.underrun_poll_samp_count += copy_samps;
-
- return copy_samps;
+/*!
+ * Accept a commit of num bytes to the send buffer.
+ * Conditionally commit the send buffer if full.
+ */
+ssize_t usrp1_impl::io_impl::phony_commit_send_buff(size_t num_bytes){
+ num_bytes_committed += num_bytes;
+ if (num_bytes_committed != send_buff->size()) return num_bytes;
+ ssize_t ret = commit_send_buff();
+ return (ret < 0)? ret : num_bytes;
}
-bool usrp1_impl::io_impl::conditional_buff_commit(bool force)
-{
- if (send_state.bytes_written % 512)
- return false;
-
- if (force || send_state.bytes_free() == 0) {
- send_state.send_buff->commit(send_state.bytes_written);
- send_state.send_buff = uhd::transport::managed_send_buffer::sptr();
- return true;
- }
-
- return false;
+/*!
+ * Flush the send buffer:
+ * Zero-pad the send buffer to the nearest 512 byte boundary and commit.
+ */
+void usrp1_impl::io_impl::flush_send_buff(void){
+ size_t bytes_to_pad = (-1*num_bytes_committed)%512;
+ std::memset(get_send_mem_ptr(), 0, bytes_to_pad);
+ num_bytes_committed += bytes_to_pad;
+ commit_send_buff();
}
-bool usrp1_impl::io_impl::check_underrun(usrp_ctrl::sptr ctrl_if,
- size_t poll_interval,
- bool force)
-{
- unsigned char underrun = 0;
-
- bool ready_to_poll = send_state.underrun_poll_samp_count > poll_interval;
-
- if (force || ready_to_poll) {
- int ret = ctrl_if->usrp_control_read(VRQ_GET_STATUS,
- 0,
- GS_TX_UNDERRUN,
- &underrun, sizeof(char));
- if (ret < 0)
- std::cerr << "USRP: underrun check failed" << std::endl;
- if (underrun)
- std::cerr << "U" << std::flush;
-
- send_state.underrun_poll_samp_count = 0;
- }
-
- return (bool) underrun;
+/*!
+ * Perform an actual commit on the send buffer:
+ * Commit the contents of the send buffer and request a new buffer.
+ */
+ssize_t usrp1_impl::io_impl::commit_send_buff(void){
+ ssize_t ret = send_buff->commit(num_bytes_committed);
+ send_buff = data_transport->get_send_buff();
+ num_bytes_committed = 0;
+ return ret;
}
-size_t usrp1_impl::send(const std::vector<const void *> &buffs,
- size_t num_samps,
- const tx_metadata_t &,
- const io_type_t &io_type,
- send_mode_t)
-{
+bool usrp1_impl::io_impl::get_send_buffs(
+ vrt_packet_handler::managed_send_buffs_t &buffs
+){
UHD_ASSERT_THROW(buffs.size() == 1);
- size_t total_samps_sent = 0;
-
- while (total_samps_sent < num_samps) {
- if (!_io_impl->get_send_buffer(_data_transport))
- return 0;
-
- total_samps_sent += _io_impl->copy_convert_send_samps(buffs[0],
- num_samps,
- total_samps_sent,
- io_type,
- _tx_otw_type);
- if (total_samps_sent == num_samps)
- _io_impl->conditional_buff_commit(true);
- else
- _io_impl->conditional_buff_commit(false);
-
- _io_impl->check_underrun(_ctrl_transport,
- _tx_samps_per_poll_interval, false);
+ //not enough bytes free -> use the pseudo buffer
+ if (get_send_mem_size() < BYTES_PER_PACKET){
+ buffs[0] = managed_send_buffer::sptr(new pseudo_managed_send_buffer(
+ boost::asio::buffer(pseudo_buff),
+ boost::bind(&usrp1_impl::io_impl::phony_commit_pseudo_buff, this, _1)
+ ));
+ }
+ //otherwise use the send buffer offset by the bytes written
+ else{
+ buffs[0] = managed_send_buffer::sptr(new pseudo_managed_send_buffer(
+ boost::asio::buffer(get_send_mem_ptr(), get_send_mem_size()),
+ boost::bind(&usrp1_impl::io_impl::phony_commit_send_buff, this, _1)
+ ));
}
- return total_samps_sent;
+ return buffs[0].get() != NULL;
}
/***********************************************************************
- * Data Recv
+ * Initialize internals within this file
**********************************************************************/
-bool usrp1_impl::io_impl::get_recv_buffer(zero_copy_if::sptr zc_if)
-{
- if ((recv_state.recv_buff == NULL) || (recv_state.bytes_avail() == 0)) {
-
- recv_state.recv_buff = zc_if->get_recv_buff();
- if (recv_state.recv_buff == NULL)
- return false;
+void usrp1_impl::io_init(void){
+ _rx_otw_type.width = 16;
+ _rx_otw_type.shift = 0;
+ _rx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN;
- recv_state.bytes_read = 0;
- }
+ _tx_otw_type.width = 16;
+ _tx_otw_type.shift = 0;
+ _tx_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN;
- return true;
+ _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transport));
}
-size_t usrp1_impl::io_impl::copy_convert_recv_samps(void *buff,
- size_t num_samps,
- size_t sample_offset,
- const io_type_t io_type,
- otw_type_t otw_type)
-{
- UHD_ASSERT_THROW(recv_state.bytes_avail() % otw_type.get_sample_size() == 0);
-
- size_t samps_avail = recv_state.bytes_avail() / otw_type.get_sample_size();
- size_t copy_samps = std::min(num_samps - sample_offset, samps_avail);
-
- const boost::uint8_t *otw_mem =
- recv_state.recv_buff->cast<const boost::uint8_t *>();
-
- boost::uint8_t *io_mem = reinterpret_cast<boost::uint8_t *>(buff);
-
- convert_otw_type_to_io_type(otw_mem + recv_state.bytes_read,
- otw_type,
- io_mem + sample_offset * io_type.size,
- io_type,
- copy_samps);
-
- recv_state.bytes_read += copy_samps * otw_type.get_sample_size();
- recv_state.overrun_poll_samp_count += copy_samps;
-
- return copy_samps;
+/***********************************************************************
+ * Data send + helper functions
+ **********************************************************************/
+static void usrp1_bs_vrt_packer(
+ boost::uint32_t *,
+ vrt::if_packet_info_t &if_packet_info
+){
+ if_packet_info.num_header_words32 = 0;
+ if_packet_info.num_packet_words32 = if_packet_info.num_payload_words32;
}
-bool usrp1_impl::io_impl::check_overrun(usrp_ctrl::sptr ctrl_if,
- size_t poll_interval,
- bool force)
-{
- unsigned char overrun = 0;
-
- bool ready_to_poll = recv_state.overrun_poll_samp_count > poll_interval;
-
- if (force || ready_to_poll) {
- int ret = ctrl_if->usrp_control_read(VRQ_GET_STATUS,
- 0,
- GS_RX_OVERRUN,
- &overrun, sizeof(char));
- if (ret < 0)
- std::cerr << "USRP: overrrun check failed" << std::endl;
- if (overrun)
- std::cerr << "O" << std::flush;
-
- recv_state.overrun_poll_samp_count = 0;
+size_t usrp1_impl::send(
+ const std::vector<const void *> &buffs, size_t num_samps,
+ const tx_metadata_t &metadata, const io_type_t &io_type,
+ send_mode_t send_mode
+){
+ size_t num_samps_sent = vrt_packet_handler::send(
+ _io_impl->packet_handler_send_state, //last state of the send handler
+ buffs, num_samps, //buffer to fill
+ metadata, send_mode, //samples metadata
+ io_type, _tx_otw_type, //input and output types to convert
+ _clock_ctrl->get_master_clock_freq(), //master clock tick rate
+ &usrp1_bs_vrt_packer,
+ boost::bind(&usrp1_impl::io_impl::get_send_buffs, _io_impl.get(), _1),
+ get_max_send_samps_per_packet(),
+ 0, //vrt header offset
+ _tx_subdev_spec.size() //num channels
+ );
+
+ //Don't honor sob because it is normal to be always bursting...
+ //handle eob flag (commit the buffer)
+ if (metadata.end_of_burst) _io_impl->flush_send_buff();
+
+ //handle the polling for underflow conditions
+ _io_impl->underflow_poll_samp_count += num_samps_sent;
+ if (_io_impl->underflow_poll_samp_count >= _tx_samps_per_poll_interval){
+ _io_impl->underflow_poll_samp_count = 0; //reset count
+ boost::uint8_t underflow = 0;
+ ssize_t ret = _ctrl_transport->usrp_control_read(
+ VRQ_GET_STATUS, 0, GS_TX_UNDERRUN,
+ &underflow, sizeof(underflow)
+ );
+ if (ret < 0) std::cerr << "USRP: underflow check failed" << std::endl;
+ else if (underflow) std::cerr << "U" << std::flush;
}
- return (bool) overrun;
+ return num_samps_sent;
}
-size_t usrp1_impl::recv(const std::vector<void *> &buffs,
- size_t num_samps,
- rx_metadata_t &,
- const io_type_t &io_type,
- recv_mode_t,
- size_t)
-{
- UHD_ASSERT_THROW(buffs.size() == 1);
-
- size_t total_samps_recv = 0;
-
- while (total_samps_recv < num_samps) {
+/***********************************************************************
+ * Data recv + helper functions
+ **********************************************************************/
+static void usrp1_bs_vrt_unpacker(
+ const boost::uint32_t *,
+ vrt::if_packet_info_t &if_packet_info
+){
+ if_packet_info.packet_type = vrt::if_packet_info_t::PACKET_TYPE_DATA;
+ if_packet_info.num_payload_words32 = if_packet_info.num_packet_words32;
+ if_packet_info.num_header_words32 = 0;
+ if_packet_info.packet_count = 0;
+ if_packet_info.sob = false;
+ if_packet_info.eob = false;
+ if_packet_info.has_sid = false;
+ if_packet_info.has_cid = false;
+ if_packet_info.has_tsi = false;
+ if_packet_info.has_tsf = false;
+ if_packet_info.has_tlr = false;
+}
- if (!_io_impl->get_recv_buffer(_data_transport))
- return 0;
+static bool get_recv_buffs(
+ zero_copy_if::sptr zc_if,
+ vrt_packet_handler::managed_recv_buffs_t &buffs
+){
+ UHD_ASSERT_THROW(buffs.size() == 1);
+ buffs[0] = zc_if->get_recv_buff();
+ return buffs[0].get() != NULL;
+}
- total_samps_recv += _io_impl->copy_convert_recv_samps(buffs[0],
- num_samps,
- total_samps_recv,
- io_type,
- _rx_otw_type);
- _io_impl->check_overrun(_ctrl_transport,
- _rx_samps_per_poll_interval, false);
+size_t usrp1_impl::recv(
+ const std::vector<void *> &buffs, size_t num_samps,
+ rx_metadata_t &metadata, const io_type_t &io_type,
+ recv_mode_t recv_mode, size_t /*timeout_ms TODO*/
+){
+ size_t num_samps_recvd = vrt_packet_handler::recv(
+ _io_impl->packet_handler_recv_state, //last state of the recv handler
+ buffs, num_samps, //buffer to fill
+ metadata, recv_mode, //samples metadata
+ io_type, _rx_otw_type, //input and output types to convert
+ _clock_ctrl->get_master_clock_freq(), //master clock tick rate
+ &usrp1_bs_vrt_unpacker,
+ boost::bind(&get_recv_buffs, _data_transport, _1),
+ &vrt_packet_handler::handle_overflow_nop,
+ 0, //vrt header offset
+ _rx_subdev_spec.size() //num channels
+ );
+
+ //handle the polling for overflow conditions
+ _io_impl->overflow_poll_samp_count += num_samps_recvd;
+ if (_io_impl->overflow_poll_samp_count >= _rx_samps_per_poll_interval){
+ _io_impl->overflow_poll_samp_count = 0; //reset count
+ boost::uint8_t overflow = 0;
+ ssize_t ret = _ctrl_transport->usrp_control_read(
+ VRQ_GET_STATUS, 0, GS_RX_OVERRUN,
+ &overflow, sizeof(overflow)
+ );
+ if (ret < 0) std::cerr << "USRP: overflow check failed" << std::endl;
+ else if (overflow) std::cerr << "O" << std::flush;
}
- return total_samps_recv;
+ return num_samps_recvd;
}
diff --git a/host/lib/usrp/usrp1/mboard_impl.cpp b/host/lib/usrp/usrp1/mboard_impl.cpp
index a90532cb8..fe3774eb4 100644
--- a/host/lib/usrp/usrp1/mboard_impl.cpp
+++ b/host/lib/usrp/usrp1/mboard_impl.cpp
@@ -36,6 +36,8 @@
using namespace uhd;
using namespace uhd::usrp;
+static const bool usrp1_mboard_verbose = false;
+
/***********************************************************************
* Calculate the RX mux value:
* The I and Q mux values are intentionally reversed to flip I and Q
@@ -146,6 +148,7 @@ static boost::uint32_t calc_tx_mux(
//calculate the channel flags
int channel_flags = 0, chan = 0;
+ uhd::dict<std::string, int> slot_to_chan_count = boost::assign::map_list_of("A", 0)("B", 0);
BOOST_FOREACH(const subdev_spec_pair_t &pair, subdev_spec){
wax::obj dboard = mboard[named_prop_t(MBOARD_PROP_TX_DBOARD, pair.db_name)];
wax::obj subdev = dboard[named_prop_t(DBOARD_PROP_SUBDEV, pair.sd_name)];
@@ -155,6 +158,14 @@ static boost::uint32_t calc_tx_mux(
if (pair.db_name == "A") channel_flags |= chan_to_conn_to_flag[chan][conn] << 0;
if (pair.db_name == "B") channel_flags |= chan_to_conn_to_flag[chan][conn] << 8;
+ //sanity check, only 1 channel per slot
+ slot_to_chan_count[pair.db_name]++;
+ if (slot_to_chan_count[pair.db_name] > 1){
+ throw std::runtime_error(str(boost::format(
+ "dboard slot %s assigned to multiple channels in subdev spec %s"
+ ) % pair.db_name % subdev_spec.to_string()));
+ }
+
//increment for the next channel
chan++;
}
@@ -172,23 +183,23 @@ static boost::uint32_t calc_tx_mux(
* | Reserved |T|DUCs |R|DDCs |
* +-----------------------------------------------+-+-----+-+-----+
*/
-static int num_ddcs(boost::uint32_t regval)
-{
+size_t usrp1_impl::get_num_ddcs(void){
+ boost::uint32_t regval = _iface->peek32(FR_RB_CAPS);
return (regval >> 0) & 0x0007;
}
-static int num_ducs(boost::uint32_t regval)
-{
+size_t usrp1_impl::get_num_ducs(void){
+ boost::uint32_t regval = _iface->peek32(FR_RB_CAPS);
return (regval >> 4) & 0x0007;
}
-static bool has_rx_halfband(boost::uint32_t regval)
-{
+bool usrp1_impl::has_rx_halfband(void){
+ boost::uint32_t regval = _iface->peek32(FR_RB_CAPS);
return (regval >> 3) & 0x0001;
}
-static bool has_tx_halfband(boost::uint32_t regval)
-{
+bool usrp1_impl::has_tx_halfband(void){
+ boost::uint32_t regval = _iface->peek32(FR_RB_CAPS);
return (regval >> 7) & 0x0001;
}
@@ -220,26 +231,25 @@ void usrp1_impl::mboard_init(void)
// Set default for TX format to 16-bit I&Q
_iface->poke32(FR_TX_FORMAT, 0x00000000);
- // TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO
- //
- // Do something useful with the capabilities register
- //
- boost::uint32_t regval = _iface->peek32(FR_RB_CAPS);
- std::cout << "USRP1 Capabilities" << std::endl;
- std::cout << " number of duc's: " << num_ddcs(regval) << std::endl;
- std::cout << " number of ddc's: " << num_ducs(regval) << std::endl;
- std::cout << " rx halfband: " << has_rx_halfband(regval) << std::endl;
- std::cout << " tx halfband: " << has_tx_halfband(regval) << std::endl;
+ if (usrp1_mboard_verbose){
+ std::cout << "USRP1 Capabilities" << std::endl;
+ std::cout << " number of duc's: " << get_num_ddcs() << std::endl;
+ std::cout << " number of ddc's: " << get_num_ducs() << std::endl;
+ std::cout << " rx halfband: " << has_rx_halfband() << std::endl;
+ std::cout << " tx halfband: " << has_tx_halfband() << std::endl;
+ }
}
void usrp1_impl::issue_stream_cmd(const stream_cmd_t &stream_cmd)
{
- if (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS) {
- _iface->write_firmware_cmd(VRQ_FPGA_SET_RX_ENABLE, true, 0, 0, 0);
- }
+ switch(stream_cmd.stream_mode){
+ case stream_cmd_t::STREAM_MODE_START_CONTINUOUS:
+ return _iface->write_firmware_cmd(VRQ_FPGA_SET_RX_ENABLE, true, 0, 0, 0);
+
+ case stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS:
+ return _iface->write_firmware_cmd(VRQ_FPGA_SET_RX_ENABLE, false, 0, 0, 0);
- if (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS) {
- _iface->write_firmware_cmd(VRQ_FPGA_SET_RX_ENABLE, false, 0, 0, 0);
+ default: throw std::runtime_error("unsupported stream command type for USRP1");
}
}
@@ -269,7 +279,7 @@ void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val)
//handle the get request conditioned on the key
switch(key.as<mboard_prop_t>()){
case MBOARD_PROP_NAME:
- val = std::string("usrp1 mboard");
+ val = std::string("usrp1 mboard - " + (*_mboard_proxy)[std::string("serial")].as<std::string>());
return;
case MBOARD_PROP_OTHERS:
@@ -361,18 +371,26 @@ void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val)
case MBOARD_PROP_RX_SUBDEV_SPEC:
_rx_subdev_spec = val.as<subdev_spec_t>();
+ if (_rx_subdev_spec.size() > this->get_num_ddcs()){
+ throw std::runtime_error(str(boost::format(
+ "USRP1 suports up to %u RX channels.\n"
+ "However, this RX subdev spec requires %u channels\n"
+ ) % this->get_num_ddcs() % _rx_subdev_spec.size()));
+ }
verify_rx_subdev_spec(_rx_subdev_spec, _mboard_proxy->get_link());
- //sanity check
- UHD_ASSERT_THROW(_rx_subdev_spec.size() <= 2);
//set the mux and set the number of rx channels
_iface->poke32(FR_RX_MUX, calc_rx_mux(_rx_subdev_spec, _mboard_proxy->get_link()));
return;
case MBOARD_PROP_TX_SUBDEV_SPEC:
_tx_subdev_spec = val.as<subdev_spec_t>();
+ if (_tx_subdev_spec.size() > this->get_num_ducs()){
+ throw std::runtime_error(str(boost::format(
+ "USRP1 suports up to %u TX channels.\n"
+ "However, this TX subdev spec requires %u channels\n"
+ ) % this->get_num_ducs() % _tx_subdev_spec.size()));
+ }
verify_tx_subdev_spec(_tx_subdev_spec, _mboard_proxy->get_link());
- //sanity check
- UHD_ASSERT_THROW(_tx_subdev_spec.size() <= 2);
//set the mux and set the number of tx channels
_iface->poke32(FR_TX_MUX, calc_tx_mux(_tx_subdev_spec, _mboard_proxy->get_link()));
return;
diff --git a/host/lib/usrp/usrp1/usrp1_ctrl.cpp b/host/lib/usrp/usrp1/usrp1_ctrl.cpp
index 451129ef5..76e8ce368 100644
--- a/host/lib/usrp/usrp1/usrp1_ctrl.cpp
+++ b/host/lib/usrp/usrp1/usrp1_ctrl.cpp
@@ -38,6 +38,8 @@ enum firmware_code {
#define FX2_FIRMWARE_LOAD 0xa0
+static const bool load_img_msg = true;
+
/***********************************************************************
* Helper Functions
**********************************************************************/
@@ -178,6 +180,7 @@ public:
unsigned char reset_n = 0;
//hit the reset line
+ if (load_img_msg) std::cout << "Loading firmware image " << filestring << "..." << std::flush;
usrp_control_write(FX2_FIRMWARE_LOAD, 0xe600, 0,
&reset_y, 1);
@@ -213,7 +216,7 @@ public:
//wait for things to settle
boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
-
+ if (load_img_msg) std::cout << " done" << std::endl;
return USRP_FIRMWARE_LOAD_SUCCESS;
}
//type anything else is unhandled
@@ -249,45 +252,48 @@ public:
unsigned char buf[ep0_size];
int ret;
- FILE *fp;
- if ((fp = fopen(filename, "rb")) == NULL) {
+ if (load_img_msg) std::cout << "Loading FPGA image: " << filestring << "..." << std::flush;
+ std::ifstream file;
+ file.open(filename, std::ios::in | std::ios::binary);
+ if (not file.good()) {
std::cerr << "cannot open fpga input file" << std::endl;
- fclose(fp);
+ file.close();
return -1;
}
if (usrp_control_write_cmd(VRQ_FPGA_LOAD, 0, FL_BEGIN) < 0) {
std::cerr << "fpga load error" << std::endl;
- fclose(fp);
+ file.close();
return -1;
}
ssize_t n;
- while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) {
+ while ((n = file.readsome((char *)buf, sizeof(buf))) > 0) {
ret = usrp_control_write(VRQ_FPGA_LOAD, 0, FL_XFER,
buf, n);
if (ret != n) {
std::cerr << "fpga load error " << ret << std::endl;
- fclose(fp);
+ file.close();
return -1;
}
}
if (usrp_control_write_cmd(VRQ_FPGA_LOAD, 0, FL_END) < 0) {
std::cerr << "fpga load error" << std::endl;
- fclose(fp);
+ file.close();
return -1;
}
usrp_set_fpga_hash(hash);
- fclose(fp);
+ file.close();
+ if (load_img_msg) std::cout << " done" << std::endl;
return 0;
}
int usrp_load_eeprom(std::string filestring)
{
const char *filename = filestring.c_str();
- const uint16_t i2c_addr = 0x50;
+ const boost::uint16_t i2c_addr = 0x50;
//FIXME: verify types
int len;
@@ -416,7 +422,7 @@ public:
}
- int usrp_control_write_cmd(uint8_t request, uint16_t value, uint16_t index)
+ int usrp_control_write_cmd(boost::uint8_t request, boost::uint16_t value, boost::uint16_t index)
{
return usrp_control_write(request, value, index, 0, 0);
}
diff --git a/host/lib/usrp/usrp1/usrp1_iface.cpp b/host/lib/usrp/usrp1/usrp1_iface.cpp
index 4bc18dd16..5fd3987d5 100644
--- a/host/lib/usrp/usrp1/usrp1_iface.cpp
+++ b/host/lib/usrp/usrp1/usrp1_iface.cpp
@@ -80,7 +80,7 @@ public:
boost::uint32_t peek32(boost::uint32_t addr)
{
- uint32_t value_out;
+ boost::uint32_t value_out;
boost::uint8_t w_index_h = SPI_ENABLE_FPGA & 0xff;
boost::uint8_t w_index_l = (SPI_FMT_MSB | SPI_FMT_HDR_1) & 0xff;
@@ -100,7 +100,7 @@ public:
boost::uint16_t peek16(boost::uint32_t addr)
{
- uint32_t val = peek32(addr);
+ boost::uint32_t val = peek32(addr);
return boost::uint16_t(val & 0xff);
}
diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp
index a6806dbc3..80ea49e9d 100644
--- a/host/lib/usrp/usrp1/usrp1_impl.cpp
+++ b/host/lib/usrp/usrp1/usrp1_impl.cpp
@@ -62,7 +62,7 @@ static device_addrs_t usrp1_find(const device_addr_t &hint)
hint.has_key("fw")? hint["fw"] : "usrp1_fw.ihx"
);
}
- catch(const std::exception &e){
+ catch(...){
uhd::print_warning(
"Could not locate USRP1 firmware.\n"
"Please install the images package.\n"
@@ -96,7 +96,10 @@ static device_addrs_t usrp1_find(const device_addr_t &hint)
device_addr_t new_addr;
new_addr["type"] = "usrp1";
new_addr["serial"] = handle->get_serial();
- usrp1_addrs.push_back(new_addr);
+ //this is a found usrp1 when a hint serial is not specified or it matches
+ if (not hint.has_key("serial") or hint["serial"] == new_addr["serial"]){
+ usrp1_addrs.push_back(new_addr);
+ }
}
return usrp1_addrs;
diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp
index c2f693eeb..20ae3c02a 100644
--- a/host/lib/usrp/usrp1/usrp1_impl.hpp
+++ b/host/lib/usrp/usrp1/usrp1_impl.hpp
@@ -91,8 +91,16 @@ public:
recv_mode_t,
size_t timeout);
- size_t get_max_send_samps_per_packet(void) const { return 0; }
- size_t get_max_recv_samps_per_packet(void) const { return 0; }
+ static const size_t BYTES_PER_PACKET = 512*4; //under the transfer size
+
+ size_t get_max_send_samps_per_packet(void) const {
+ return BYTES_PER_PACKET/_tx_otw_type.get_sample_size()/_tx_subdev_spec.size();
+ }
+
+ size_t get_max_recv_samps_per_packet(void) const {
+ return BYTES_PER_PACKET/_rx_otw_type.get_sample_size()/_rx_subdev_spec.size();
+ }
+
bool recv_async_msg(uhd::async_metadata_t &, size_t);
private:
@@ -179,19 +187,27 @@ private:
void rx_dsp_init(void);
void rx_dsp_get(const wax::obj &, wax::obj &);
void rx_dsp_set(const wax::obj &, const wax::obj &);
- double _rx_dsp_freq; size_t _rx_dsp_decim;
+ uhd::dict<std::string, double> _rx_dsp_freqs;
+ size_t _rx_dsp_decim;
wax_obj_proxy::sptr _rx_dsp_proxy;
//tx dsp functions and settings
void tx_dsp_init(void);
void tx_dsp_get(const wax::obj &, wax::obj &);
void tx_dsp_set(const wax::obj &, const wax::obj &);
- double _tx_dsp_freq; size_t _tx_dsp_interp;
+ uhd::dict<std::string, double> _tx_dsp_freqs;
+ size_t _tx_dsp_interp;
wax_obj_proxy::sptr _tx_dsp_proxy;
//transports
uhd::transport::usb_zero_copy::sptr _data_transport;
usrp_ctrl::sptr _ctrl_transport;
+
+ //capabilities
+ size_t get_num_ducs(void);
+ size_t get_num_ddcs(void);
+ bool has_rx_halfband(void);
+ bool has_tx_halfband(void);
};
#endif /* INCLUDED_USRP1_IMPL_HPP */
diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp
index 6422142ce..0c85e643f 100644
--- a/host/lib/usrp/usrp2/dsp_impl.cpp
+++ b/host/lib/usrp/usrp2/dsp_impl.cpp
@@ -56,7 +56,9 @@ void usrp2_mboard_impl::init_ddc_config(void){
/***********************************************************************
* DDC Properties
**********************************************************************/
-void usrp2_mboard_impl::ddc_get(const wax::obj &key, wax::obj &val){
+void usrp2_mboard_impl::ddc_get(const wax::obj &key_, wax::obj &val){
+ named_prop_t key = named_prop_t::extract(key_);
+
switch(key.as<dsp_prop_t>()){
case DSP_PROP_NAME:
val = std::string("usrp2 ddc0");
@@ -70,6 +72,10 @@ void usrp2_mboard_impl::ddc_get(const wax::obj &key, wax::obj &val){
val = _ddc_freq;
return;
+ case DSP_PROP_FREQ_SHIFT_NAMES:
+ val = prop_names_t(1, "");
+ return;
+
case DSP_PROP_CODEC_RATE:
val = get_master_clock_freq();
return;
@@ -82,7 +88,9 @@ void usrp2_mboard_impl::ddc_get(const wax::obj &key, wax::obj &val){
}
}
-void usrp2_mboard_impl::ddc_set(const wax::obj &key, const wax::obj &val){
+void usrp2_mboard_impl::ddc_set(const wax::obj &key_, const wax::obj &val){
+ named_prop_t key = named_prop_t::extract(key_);
+
switch(key.as<dsp_prop_t>()){
case DSP_PROP_FREQ_SHIFT:{
@@ -131,7 +139,9 @@ void usrp2_mboard_impl::init_duc_config(void){
/***********************************************************************
* DUC Properties
**********************************************************************/
-void usrp2_mboard_impl::duc_get(const wax::obj &key, wax::obj &val){
+void usrp2_mboard_impl::duc_get(const wax::obj &key_, wax::obj &val){
+ named_prop_t key = named_prop_t::extract(key_);
+
switch(key.as<dsp_prop_t>()){
case DSP_PROP_NAME:
val = std::string("usrp2 duc0");
@@ -145,6 +155,10 @@ void usrp2_mboard_impl::duc_get(const wax::obj &key, wax::obj &val){
val = _duc_freq;
return;
+ case DSP_PROP_FREQ_SHIFT_NAMES:
+ val = prop_names_t(1, "");
+ return;
+
case DSP_PROP_CODEC_RATE:
val = get_master_clock_freq();
return;
@@ -157,7 +171,9 @@ void usrp2_mboard_impl::duc_get(const wax::obj &key, wax::obj &val){
}
}
-void usrp2_mboard_impl::duc_set(const wax::obj &key, const wax::obj &val){
+void usrp2_mboard_impl::duc_set(const wax::obj &key_, const wax::obj &val){
+ named_prop_t key = named_prop_t::extract(key_);
+
switch(key.as<dsp_prop_t>()){
case DSP_PROP_FREQ_SHIFT:{
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index 4e883cf81..65411801d 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -150,7 +150,7 @@ void usrp2_impl::io_init(void){
std::memcpy(send_buff->cast<void*>(), &data, sizeof(data));
send_buff->commit(sizeof(data));
//drain the recv buffers (may have junk)
- while (data_transport->get_recv_buff().get());
+ while (data_transport->get_recv_buff().get()){};
}
//the number of recv frames is the number for the first transport
@@ -189,7 +189,7 @@ bool usrp2_impl::recv_async_msg(
/***********************************************************************
* Send Data
**********************************************************************/
-bool get_send_buffs(
+static bool get_send_buffs(
const std::vector<udp_zero_copy::sptr> &trans,
vrt_packet_handler::managed_send_buffs_t &buffs
){
diff --git a/host/test/tune_helper_test.cpp b/host/test/tune_helper_test.cpp
index 570f47293..1ef4af330 100644
--- a/host/test/tune_helper_test.cpp
+++ b/host/test/tune_helper_test.cpp
@@ -99,7 +99,8 @@ public:
/* NOP */
}
private:
- void get(const wax::obj &key, wax::obj &val){
+ void get(const wax::obj &key_, wax::obj &val){
+ named_prop_t key = named_prop_t::extract(key_);
switch(key.as<dsp_prop_t>()){
case DSP_PROP_CODEC_RATE:
val = _codec_rate;
@@ -109,11 +110,16 @@ private:
val = _freq_shift;
return;
+ case DSP_PROP_FREQ_SHIFT_NAMES:
+ val = prop_names_t(1, "");
+ return;
+
default: UHD_THROW_PROP_GET_ERROR();
}
}
- void set(const wax::obj &key, const wax::obj &val){
+ void set(const wax::obj &key_, const wax::obj &val){
+ named_prop_t key = named_prop_t::extract(key_);
switch(key.as<dsp_prop_t>()){
case DSP_PROP_FREQ_SHIFT:
_freq_shift = val.as<double>();
@@ -136,12 +142,12 @@ BOOST_AUTO_TEST_CASE(test_tune_helper_rx){
dummy_dsp dsp(100e6);
std::cout << "Testing tune helper RX automatic LO offset" << std::endl;
- tune_result_t tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.3451e9);
+ tune_result_t tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0, 2.3451e9);
std::cout << tr.to_pp_string() << std::endl;
BOOST_CHECK_CLOSE(tr.actual_inter_freq, 2.345e9, tolerance);
BOOST_CHECK_CLOSE(tr.actual_dsp_freq, -100e3, tolerance);
- double freq_derived = derive_freq_from_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link());
+ double freq_derived = derive_freq_from_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0);
BOOST_CHECK_CLOSE(freq_derived, 2.3451e9, tolerance);
}
@@ -150,12 +156,12 @@ BOOST_AUTO_TEST_CASE(test_tune_helper_tx){
dummy_dsp dsp(100e6);
std::cout << "Testing tune helper TX automatic LO offset" << std::endl;
- tune_result_t tr = tune_tx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.3451e9);
+ tune_result_t tr = tune_tx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0, 2.3451e9);
std::cout << tr.to_pp_string() << std::endl;
BOOST_CHECK_CLOSE(tr.actual_inter_freq, 2.345e9, tolerance);
BOOST_CHECK_CLOSE(tr.actual_dsp_freq, 100e3, tolerance);
- double freq_derived = derive_freq_from_tx_subdev_and_dsp(subdev.get_link(), dsp.get_link());
+ double freq_derived = derive_freq_from_tx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0);
BOOST_CHECK_CLOSE(freq_derived, 2.3451e9, tolerance);
}
@@ -164,11 +170,11 @@ BOOST_AUTO_TEST_CASE(test_tune_helper_rx_nyquist){
dummy_dsp dsp(100e6);
std::cout << "Testing tune helper RX dummy basic board" << std::endl;
- tune_result_t tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 55e6);
+ tune_result_t tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0, 55e6);
std::cout << tr.to_pp_string() << std::endl;
BOOST_CHECK_CLOSE(tr.actual_inter_freq, 0.0, tolerance);
BOOST_CHECK_CLOSE(tr.actual_dsp_freq, 45e6, tolerance);
- double freq_derived = derive_freq_from_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link());
+ double freq_derived = derive_freq_from_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 0);
BOOST_CHECK_CLOSE(freq_derived, -45e6, tolerance);
}