aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--firmware/microblaze/apps/txrx_uhd.c12
-rw-r--r--host/CMakeLists.txt16
-rw-r--r--host/docs/build.rst6
-rw-r--r--host/docs/general.rst8
-rw-r--r--host/docs/usrp2.rst30
-rw-r--r--host/examples/CMakeLists.txt12
-rw-r--r--host/examples/benchmark_rx_rate.cpp141
-rw-r--r--host/examples/rx_timed_samples.cpp17
-rw-r--r--host/examples/tx_timed_samples.cpp9
-rw-r--r--host/include/uhd/types/time_spec.hpp86
-rw-r--r--host/include/uhd/usrp/dboard_id.hpp2
-rw-r--r--host/include/uhd/usrp/dboard_iface.hpp39
-rw-r--r--host/include/uhd/usrp/dboard_manager.hpp21
-rw-r--r--host/include/uhd/utils/CMakeLists.txt1
-rw-r--r--host/include/uhd/utils/thread_priority.hpp58
-rw-r--r--host/lib/CMakeLists.txt41
-rw-r--r--host/lib/ic_reg_maps/common.py4
-rwxr-xr-xhost/lib/ic_reg_maps/gen_ad9522_regs.py2
-rw-r--r--host/lib/load_modules.cpp4
-rw-r--r--host/lib/sched.cpp45
-rw-r--r--host/lib/thread_priority.cpp98
-rw-r--r--host/lib/transport/CMakeLists.txt20
-rw-r--r--host/lib/transport/convert_types_impl.hpp201
-rwxr-xr-xhost/lib/transport/gen_convert_types.py122
-rwxr-xr-xhost/lib/transport/gen_vrt.py23
-rw-r--r--host/lib/transport/if_addrs.cpp6
-rw-r--r--host/lib/transport/udp_zero_copy_asio.cpp9
-rw-r--r--host/lib/types.cpp58
-rw-r--r--host/lib/usrp/dboard/CMakeLists.txt1
-rw-r--r--host/lib/usrp/dboard/db_rfx.cpp26
-rw-r--r--host/lib/usrp/dboard/db_unknown.cpp265
-rw-r--r--host/lib/usrp/dboard/db_wbx.cpp5
-rw-r--r--host/lib/usrp/dboard/db_xcvr2450.cpp5
-rw-r--r--host/lib/usrp/dboard_manager.cpp58
-rw-r--r--host/lib/usrp/usrp2/clock_ctrl.cpp45
-rw-r--r--host/lib/usrp/usrp2/clock_ctrl.hpp27
-rw-r--r--host/lib/usrp/usrp2/dboard_iface.cpp66
-rw-r--r--host/lib/usrp/usrp2/fw_common.h8
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp2
-rw-r--r--host/lib/usrp/usrp2/mboard_impl.cpp8
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.cpp4
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp4
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp6
-rw-r--r--host/test/vrt_test.cpp10
-rw-r--r--host/utils/uhd_burn_db_eeprom.cpp12
45 files changed, 1316 insertions, 327 deletions
diff --git a/firmware/microblaze/apps/txrx_uhd.c b/firmware/microblaze/apps/txrx_uhd.c
index 7ad4ab110..21803b199 100644
--- a/firmware/microblaze/apps/txrx_uhd.c
+++ b/firmware/microblaze/apps/txrx_uhd.c
@@ -100,7 +100,7 @@ typedef struct{
#define MK_RX_CTRL_WORD(num_words) (((num_words)*sizeof(uint32_t)) | (1 << 16))
// DSP Rx writes ethernet header words
-#define DSP_RX_FIRST_LINE 1 //1 = number of control words (see above)
+#define DSP_RX_FIRST_LINE ((offsetof(rx_dsp_buff_t, vrt_header))/sizeof(uint32_t))
// receive from DSP
buf_cmd_args_t dsp_rx_recv_args = {
@@ -177,7 +177,7 @@ void handle_udp_ctrl_packet(
unsigned char *payload, int payload_len
){
//printf("Got ctrl packet #words: %d\n", (int)payload_len);
- usrp2_ctrl_data_t *ctrl_data_in = (usrp2_ctrl_data_t *)payload;
+ const usrp2_ctrl_data_t *ctrl_data_in = (usrp2_ctrl_data_t *)payload;
uint32_t ctrl_data_in_id = ctrl_data_in->id;
//ensure that the protocol versions match
@@ -288,15 +288,15 @@ void handle_udp_ctrl_packet(
case USRP2_CTRL_ID_PEEK_AT_THIS_REGISTER_FOR_ME_BRO:
switch(ctrl_data_in->data.poke_args.num_bytes){
case sizeof(uint32_t):
- ctrl_data_in->data.poke_args.data = *((uint32_t *) ctrl_data_in->data.poke_args.addr);
+ ctrl_data_out.data.poke_args.data = *((uint32_t *) ctrl_data_in->data.poke_args.addr);
break;
case sizeof(uint16_t):
- ctrl_data_in->data.poke_args.data = *((uint16_t *) ctrl_data_in->data.poke_args.addr);
+ ctrl_data_out.data.poke_args.data = *((uint16_t *) ctrl_data_in->data.poke_args.addr);
break;
case sizeof(uint8_t):
- ctrl_data_in->data.poke_args.data = *((uint8_t *) ctrl_data_in->data.poke_args.addr);
+ ctrl_data_out.data.poke_args.data = *((uint8_t *) ctrl_data_in->data.poke_args.addr);
break;
}
@@ -423,7 +423,7 @@ fw_sets_seqno_inspector(dbsm_t *sm, int buf_this) // returns false
{
// insert the correct length into the control word and vrt header
rx_dsp_buff_t *buff = (rx_dsp_buff_t*)buffer_ram(buf_this);
- size_t vrt_len = buffer_pool_status->last_line[buf_this]-1;
+ size_t vrt_len = buffer_pool_status->last_line[buf_this]-DSP_RX_FIRST_LINE;
buff->control_word = MK_RX_CTRL_WORD(vrt_len);
buff->vrt_header[0] = (buff->vrt_header[0] & ~VRTH_PKT_SIZE_MASK) | (vrt_len & VRTH_PKT_SIZE_MASK);
diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt
index a8b89d6c5..c60372fb9 100644
--- a/host/CMakeLists.txt
+++ b/host/CMakeLists.txt
@@ -55,22 +55,28 @@ MACRO(UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG flag have)
ENDIF(${have})
ENDMACRO(UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG)
-IF(UNIX)
+#select the release build type by default to get optimization flags
+IF(NOT CMAKE_BUILD_TYPE)
+ SET(CMAKE_BUILD_TYPE "Release")
+ MESSAGE(STATUS "Build type not specified: defaulting to release.")
+ENDIF(NOT CMAKE_BUILD_TYPE)
+
+IF(CMAKE_COMPILER_IS_GNUCXX)
UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-Wall HAVE_WALL)
UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-Wextra HAVE_WEXTRA)
UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-pedantic HAVE_PEDANTIC)
UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-ansi HAVE_ANSI)
#only export symbols that are declared to be part of the uhd api:
UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN)
- UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-O3 HAVE_O3) #have some optimizations
-ENDIF(UNIX)
+ENDIF(CMAKE_COMPILER_IS_GNUCXX)
-IF(WIN32)
+IF(MSVC)
ADD_DEFINITIONS(-D_WIN32_WINNT=0x0501) #minimum version required is windows xp
ADD_DEFINITIONS(-DNOMINMAX) #disables stupidity and enables std::min and std::max
ADD_DEFINITIONS(-D_SCL_SECURE_NO_WARNINGS) #avoid warnings from boost::split
ADD_DEFINITIONS(-DBOOST_ALL_DYN_LINK) #setup boost auto-linking in msvc
-ENDIF(WIN32)
+ ADD_DEFINITIONS(/arch:SSE2 /G7) #processor optimization flags
+ENDIF(MSVC)
########################################################################
# Setup Boost
diff --git a/host/docs/build.rst b/host/docs/build.rst
index f5a8dac8d..108d8dc8b 100644
--- a/host/docs/build.rst
+++ b/host/docs/build.rst
@@ -97,7 +97,10 @@ Generate Makefiles with cmake
cd build
cmake ../
-For a custom prefix, use: cmake -DCMAKE_INSTALL_PREFIX=<prefix> ../
+**Notes:**
+
+* For a custom prefix, use: cmake -DCMAKE_INSTALL_PREFIX=<prefix> ../
+* On some Fedora 64-bit systems, cmake has trouble finding boost, use: cmake -DBOOST_LIBRARYDIR=/usr/lib64 ../
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Build and install
@@ -138,6 +141,7 @@ Generate the project with cmake
Build the project in MSVC
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* Open the generated project file in MSVC.
+* Change the build type from "Debug" to "Release".
* Select the build all target, right click, and choose build.
* Select the install target, right click, and choose build.
diff --git a/host/docs/general.rst b/host/docs/general.rst
index 7d1f467a0..6b309cba0 100644
--- a/host/docs/general.rst
+++ b/host/docs/general.rst
@@ -58,14 +58,12 @@ Misc notes
------------------------------------------------------------------------
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Process scheduling
+Thread priority scheduling
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-The UHD will try to automatically boost the process's scheduling priority.
-Currently, this is only supported on platforms with *sched.h*.
-
+When the UHD spawns a new thread it may try to boost the thread's scheduling priority.
When setting the priority fails, the UHD prints out an error.
-This error is harmless, it simply means that your process will have a normal scheduling priority.
+This error is harmless, it simply means that the thread will have a normal scheduling priority.
**Linux Notes:**
diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst
index 1bd95cefa..aff0d0454 100644
--- a/host/docs/usrp2.rst
+++ b/host/docs/usrp2.rst
@@ -20,7 +20,7 @@ Run the following commands:
::
cd <uhd-repo-path>/fpga/usrp2/top/u2_rev3
- make bin
+ make -f Makefile.udp bin
*The image file will be ./build/u2_rev3.bin*
@@ -158,10 +158,25 @@ 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.
+A warning will be printed on instantiation if the actual buffer size is insufficient.
+See the OS specific notes below:
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+OS specific notes
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+On linux, the maximum buffer sizes are capped by the sysctl values
+**net.core.rmem_max** and **net.core.wmem_max**.
+To change the maximum values, run the following commands:
+::
+
+ sudo sysctl -w net.core.rmem_max=<new value>
+ sudo sysctl -w net.core.wmem_max=<new value>
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Device address params
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-To set the size of the buffers,
+To manually set the size of the buffers,
the usrp2 will accept two optional parameters in the device address.
Each parameter will accept a numeric value for the number of bytes.
@@ -172,14 +187,3 @@ Example, set the args string to the following:
::
addr=192.168.10.2, recv_buff_size=100e6
-
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-OS specific notes
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-On linux, the maximum buffer sizes are capped by the sysctl values
-**net.core.rmem_max** and **net.core.wmem_max**.
-To change the maximum values, run the following commands:
-::
-
- sudo sysctl -w net.core.rmem_max=<new value>
- sudo sysctl -w net.core.wmem_max=<new value>
diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt
index a537c0901..5071b114f 100644
--- a/host/examples/CMakeLists.txt
+++ b/host/examples/CMakeLists.txt
@@ -15,10 +15,18 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
+ADD_EXECUTABLE(benchmark_rx_rate benchmark_rx_rate.cpp)
+TARGET_LINK_LIBRARIES(benchmark_rx_rate uhd)
+
ADD_EXECUTABLE(rx_timed_samples rx_timed_samples.cpp)
TARGET_LINK_LIBRARIES(rx_timed_samples uhd)
-INSTALL(TARGETS rx_timed_samples RUNTIME DESTINATION ${PKG_DATA_DIR}/examples)
ADD_EXECUTABLE(tx_timed_samples tx_timed_samples.cpp)
TARGET_LINK_LIBRARIES(tx_timed_samples uhd)
-INSTALL(TARGETS tx_timed_samples RUNTIME DESTINATION ${PKG_DATA_DIR}/examples)
+
+INSTALL(TARGETS
+ benchmark_rx_rate
+ rx_timed_samples
+ tx_timed_samples
+ RUNTIME DESTINATION ${PKG_DATA_DIR}/examples
+)
diff --git a/host/examples/benchmark_rx_rate.cpp b/host/examples/benchmark_rx_rate.cpp
new file mode 100644
index 000000000..53f4a3c68
--- /dev/null
+++ b/host/examples/benchmark_rx_rate.cpp
@@ -0,0 +1,141 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/utils/thread_priority.hpp>
+#include <uhd/utils/safe_main.hpp>
+#include <uhd/usrp/simple_usrp.hpp>
+#include <boost/math/special_functions/round.hpp>
+#include <boost/program_options.hpp>
+#include <boost/format.hpp>
+#include <iostream>
+#include <complex>
+
+namespace po = boost::program_options;
+
+static inline void test_device(
+ uhd::usrp::simple_usrp::sptr sdev,
+ double rx_rate_sps,
+ double duration_secs
+){
+ uhd::device::sptr dev = sdev->get_device();
+ std::cout << boost::format("Testing receive rate %f Msps (%f second run)") % (rx_rate_sps/1e6) % duration_secs << std::endl;
+
+ //allocate recv buffer and metatdata
+ uhd::rx_metadata_t md;
+ std::vector<std::complex<float> > buff(dev->get_max_recv_samps_per_packet());
+
+ //declare status variables
+ bool got_first_packet = false;
+ size_t total_recv_packets = 0;
+ size_t total_lost_samples = 0;
+ size_t total_recv_samples = 0;
+ uhd::time_spec_t initial_time_spec;
+ uhd::time_spec_t next_expected_time_spec;
+
+ sdev->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
+ do {
+ size_t num_rx_samps = dev->recv(
+ boost::asio::buffer(buff), md,
+ uhd::io_type_t::COMPLEX_FLOAT32,
+ uhd::device::RECV_MODE_ONE_PACKET
+ );
+ if (num_rx_samps == 0){
+ std::cerr << "Unexpected timeout on recv, exit test..." << std::endl;
+ return;
+ }
+ if (not md.has_time_spec){
+ std::cerr << "Metadata missing time spec, exit test..." << std::endl;
+ return;
+ }
+
+ total_recv_samples += num_rx_samps;
+ total_recv_packets++;
+
+ if (not got_first_packet){
+ initial_time_spec = md.time_spec;
+ next_expected_time_spec = initial_time_spec;
+ got_first_packet = true;
+ }
+
+ total_lost_samples += boost::math::iround(rx_rate_sps*(md.time_spec - next_expected_time_spec).get_real_secs());
+ next_expected_time_spec = md.time_spec + uhd::time_spec_t(0, num_rx_samps, rx_rate_sps);
+
+ } while((next_expected_time_spec - initial_time_spec) < uhd::time_spec_t(duration_secs));
+ sdev->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
+
+ //flush the buffers
+ while(dev->recv(
+ boost::asio::buffer(buff), md,
+ uhd::io_type_t::COMPLEX_FLOAT32,
+ uhd::device::RECV_MODE_ONE_PACKET
+ ));
+
+ //print a summary
+ std::cout << std::endl; //go to newline, recv may spew SXSYSZ...
+ std::cout << boost::format(" Received packets: %d") % total_recv_packets << std::endl;
+ std::cout << boost::format(" Received samples: %d") % total_recv_samples << std::endl;
+ std::cout << boost::format(" Lost samples: %d") % total_lost_samples << std::endl;
+ size_t packets_lost = boost::math::iround(double(total_lost_samples)/dev->get_max_recv_samps_per_packet());
+ std::cout << boost::format(" Lost packets: %d (approximate)") % packets_lost << std::endl;
+ double actual_rx_rate_sps = (total_recv_samples*rx_rate_sps)/(total_recv_samples+total_lost_samples);
+ std::cout << boost::format(" Sustained receive rate: %f Msps") % (actual_rx_rate_sps/1e6) << std::endl;
+ std::cout << std::endl << std::endl;
+}
+
+int UHD_SAFE_MAIN(int argc, char *argv[]){
+ uhd::set_thread_priority_safe();
+
+ //variables to be set by po
+ std::string args;
+ double duration;
+
+ //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")
+ ("duration", po::value<double>(&duration)->default_value(10.0), "duration for each test in seconds")
+ ;
+ po::variables_map vm;
+ po::store(po::parse_command_line(argc, argv, desc), vm);
+ po::notify(vm);
+
+ //print the help message
+ if (vm.count("help")){
+ std::cout << boost::format("UHD Benchmark RX Rate %s") % desc << std::endl;
+ return ~0;
+ }
+
+ //create a usrp device
+ std::cout << std::endl;
+ std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
+ uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args);
+ std::cout << boost::format("Using Device: %s") % sdev->get_name() << std::endl;
+
+ sdev->set_rx_rate(500e3); //initial rate
+ while(true){
+ double rate = sdev->get_rx_rate();
+ test_device(sdev, rate, duration);
+ sdev->set_rx_rate(rate*2); //double the rate
+ if (sdev->get_rx_rate() == rate) break;
+ }
+
+ //finished
+ std::cout << std::endl << "Done!" << std::endl << std::endl;
+
+ return 0;
+}
diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp
index 64da260d5..8db312690 100644
--- a/host/examples/rx_timed_samples.cpp
+++ b/host/examples/rx_timed_samples.cpp
@@ -15,6 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
+#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/safe_main.hpp>
#include <uhd/usrp/simple_usrp.hpp>
#include <boost/program_options.hpp>
@@ -25,9 +26,11 @@
namespace po = boost::program_options;
int UHD_SAFE_MAIN(int argc, char *argv[]){
+ uhd::set_thread_priority_safe();
+
//variables to be set by po
std::string args;
- int seconds_in_future;
+ time_t seconds_in_future;
size_t total_num_samps;
double rx_rate, freq;
@@ -36,7 +39,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
desc.add_options()
("help", "help message")
("args", po::value<std::string>(&args)->default_value(""), "simple uhd device address args")
- ("secs", po::value<int>(&seconds_in_future)->default_value(3), "number of seconds in the future to receive")
+ ("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")
("freq", po::value<double>(&freq)->default_value(0), "rf center frequency in Hz")
@@ -64,7 +67,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::cout << boost::format("Actual RX Rate: %f Msps...") % (sdev->get_rx_rate()/1e6) << std::endl;
std::cout << boost::format("Setting device timestamp to 0...") << std::endl;
sdev->set_rx_freq(freq);
- sdev->set_time_now(uhd::time_spec_t(0));
+ sdev->set_time_now(uhd::time_spec_t(0.0));
//setup streaming
std::cout << std::endl;
@@ -82,8 +85,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
uhd::rx_metadata_t md;
std::vector<std::complex<float> > buff(dev->get_max_recv_samps_per_packet());
size_t num_rx_samps = dev->recv(
- boost::asio::buffer(buff),
- md, uhd::io_type_t::COMPLEX_FLOAT32,
+ boost::asio::buffer(buff), md,
+ uhd::io_type_t::COMPLEX_FLOAT32,
uhd::device::RECV_MODE_ONE_PACKET
);
if (num_rx_samps == 0 and num_acc_samps > 0){
@@ -92,8 +95,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
}
if (num_rx_samps == 0) continue; //wait for packets with contents
- std::cout << boost::format("Got packet: %u samples, %u secs, %u nsecs")
- % num_rx_samps % md.time_spec.secs % md.time_spec.nsecs << std::endl;
+ std::cout << boost::format("Got packet: %u samples, %u full secs, %f frac secs")
+ % num_rx_samps % md.time_spec.get_full_secs() % md.time_spec.get_frac_secs() << std::endl;
num_acc_samps += num_rx_samps;
}
diff --git a/host/examples/tx_timed_samples.cpp b/host/examples/tx_timed_samples.cpp
index e9e0c785e..333f03fbe 100644
--- a/host/examples/tx_timed_samples.cpp
+++ b/host/examples/tx_timed_samples.cpp
@@ -15,6 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
+#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/safe_main.hpp>
#include <uhd/usrp/simple_usrp.hpp>
#include <boost/program_options.hpp>
@@ -25,9 +26,11 @@
namespace po = boost::program_options;
int UHD_SAFE_MAIN(int argc, char *argv[]){
+ uhd::set_thread_priority_safe();
+
//variables to be set by po
std::string args;
- int seconds_in_future;
+ time_t seconds_in_future;
size_t total_num_samps;
double tx_rate, freq;
float ampl;
@@ -37,7 +40,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
desc.add_options()
("help", "help message")
("args", po::value<std::string>(&args)->default_value(""), "simple uhd device address args")
- ("secs", po::value<int>(&seconds_in_future)->default_value(3), "number of seconds in the future to transmit")
+ ("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")
("txrate", po::value<double>(&tx_rate)->default_value(100e6/16), "rate of outgoing samples")
("freq", po::value<double>(&freq)->default_value(0), "rf center frequency in Hz")
@@ -66,7 +69,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::cout << boost::format("Actual TX Rate: %f Msps...") % (sdev->get_tx_rate()/1e6) << std::endl;
std::cout << boost::format("Setting device timestamp to 0...") << std::endl;
sdev->set_tx_freq(freq);
- sdev->set_time_now(uhd::time_spec_t(0));
+ sdev->set_time_now(uhd::time_spec_t(0.0));
//data to send
std::vector<std::complex<float> > buff(total_num_samps, std::complex<float>(ampl, ampl));
diff --git a/host/include/uhd/types/time_spec.hpp b/host/include/uhd/types/time_spec.hpp
index 25d9e41d0..59b85f4b7 100644
--- a/host/include/uhd/types/time_spec.hpp
+++ b/host/include/uhd/types/time_spec.hpp
@@ -19,58 +19,92 @@
#define INCLUDED_UHD_TYPES_TIME_SPEC_HPP
#include <uhd/config.hpp>
-#include <boost/cstdint.hpp>
+#include <boost/operators.hpp>
+#include <ctime>
namespace uhd{
/*!
- * A time_spec_t holds a seconds and fractional seconds time value.
- * The time_spec_t can be used when setting the time on devices,
- * and for dealing with time stamped samples though the metadata.
- * and for controlling the start of streaming for applicable dsps.
+ * A time_spec_t holds a seconds and a fractional seconds time value.
+ * Depending upon usage, the time_spec_t can represent absolute times,
+ * relative times, or time differences (between absolute times).
*
- * The fractional seconds are represented in units of nanoseconds,
- * which provide a clock-domain independent unit of time storage.
- * The methods "get_ticks" and "set_ticks" can be used to convert
- * the fractional seconds to and from clock-domain specific units.
+ * The time_spec_t provides clock-domain independent time storage,
+ * but can convert fractional seconds to/from clock-domain specific units.
*
- * The nanoseconds count is stored as double precision floating point.
+ * The fractional seconds are stored as double precision floating point.
* This gives the fractional seconds enough precision to unambiguously
* specify a clock-tick/sample-count up to rates of several petahertz.
*/
- struct UHD_API time_spec_t{
+ class UHD_API time_spec_t : boost::additive<time_spec_t>, boost::totally_ordered<time_spec_t>{
+ public:
- //! whole/integer seconds count in seconds
- boost::uint32_t secs;
+ /*!
+ * Create a time_spec_t from a real-valued seconds count.
+ * \param secs the real-valued seconds count (default = 0)
+ */
+ time_spec_t(double secs = 0);
+
+ /*!
+ * Create a time_spec_t from whole and fractional seconds.
+ * \param full_secs the whole/integer seconds count
+ * \param frac_secs the fractional seconds count (default = 0)
+ */
+ time_spec_t(time_t full_secs, double frac_secs = 0);
- //! fractional seconds count in nano-seconds
- double nsecs;
+ /*!
+ * Create a time_spec_t from whole and fractional seconds.
+ * Translation from clock-domain specific units.
+ * \param full_secs the whole/integer seconds count
+ * \param tick_count the fractional seconds tick count
+ * \param tick_rate the number of ticks per second
+ */
+ time_spec_t(time_t full_secs, size_t tick_count, double tick_rate);
/*!
- * Convert the fractional nsecs to clock ticks.
+ * Convert the fractional seconds to clock ticks.
* Translation into clock-domain specific units.
* \param tick_rate the number of ticks per second
* \return the fractional seconds tick count
*/
- boost::uint32_t get_ticks(double tick_rate) const;
+ size_t get_tick_count(double tick_rate) const;
/*!
- * Set the fractional nsecs from clock ticks.
- * Translation from clock-domain specific units.
- * \param ticks the fractional seconds tick count
- * \param tick_rate the number of ticks per second
+ * Get the time as a real-valued seconds count.
+ * Note: If this time_spec_t represents an absolute time,
+ * the precision of the fractional seconds may be lost.
+ * \return the real-valued seconds
*/
- void set_ticks(boost::uint32_t ticks, double tick_rate);
+ double get_real_secs(void) const;
/*!
- * Create a time_spec_t from whole and fractional seconds.
- * \param secs the whole/integer seconds count in seconds (default = 0)
- * \param nsecs the fractional seconds count in nanoseconds (default = 0)
+ * Get the whole/integer part of the time in seconds.
+ * \return the whole/integer seconds
+ */
+ time_t get_full_secs(void) const;
+
+ /*!
+ * Get the fractional part of the time in seconds.
+ * \return the fractional seconds
*/
- time_spec_t(boost::uint32_t secs = 0, double nsecs = 0);
+ double get_frac_secs(void) const;
+
+ //! Implement addable interface
+ time_spec_t &operator+=(const time_spec_t &);
+
+ //! Implement subtractable interface
+ time_spec_t &operator-=(const time_spec_t &);
+ //private time storage details
+ private: time_t _full_secs; double _frac_secs;
};
+ //! Implement equality_comparable interface
+ UHD_API bool operator==(const time_spec_t &, const time_spec_t &);
+
+ //! Implement less_than_comparable interface
+ UHD_API bool operator<(const time_spec_t &, const time_spec_t &);
+
} //namespace uhd
#endif /* INCLUDED_UHD_TYPES_TIME_SPEC_HPP */
diff --git a/host/include/uhd/usrp/dboard_id.hpp b/host/include/uhd/usrp/dboard_id.hpp
index 8b6eaf6bd..4c45e4334 100644
--- a/host/include/uhd/usrp/dboard_id.hpp
+++ b/host/include/uhd/usrp/dboard_id.hpp
@@ -25,7 +25,7 @@
namespace uhd{ namespace usrp{
- class UHD_API dboard_id_t : boost::equality_comparable1<dboard_id_t>{
+ class UHD_API dboard_id_t : boost::equality_comparable<dboard_id_t>{
public:
/*!
* Create a dboard id from an integer.
diff --git a/host/include/uhd/usrp/dboard_iface.hpp b/host/include/uhd/usrp/dboard_iface.hpp
index 7ecfcd3c0..caf1e6ee6 100644
--- a/host/include/uhd/usrp/dboard_iface.hpp
+++ b/host/include/uhd/usrp/dboard_iface.hpp
@@ -22,6 +22,7 @@
#include <uhd/types/serial.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/cstdint.hpp>
+#include <vector>
namespace uhd{ namespace usrp{
@@ -35,13 +36,13 @@ class UHD_API dboard_iface{
public:
typedef boost::shared_ptr<dboard_iface> sptr;
- //tells the host which unit to use
+ //! tells the host which unit to use
enum unit_t{
UNIT_RX = 'r',
UNIT_TX = 't'
};
- //possible atr registers
+ //! possible atr registers
enum atr_reg_t{
ATR_REG_IDLE = 'i',
ATR_REG_TX_ONLY = 't',
@@ -49,6 +50,20 @@ public:
ATR_REG_FULL_DUPLEX = 'f'
};
+ //! aux dac selection enums (per unit)
+ enum aux_dac_t{
+ AUX_DAC_A = 'a',
+ AUX_DAC_B = 'b',
+ AUX_DAC_C = 'c',
+ AUX_DAC_D = 'd'
+ };
+
+ //! aux adc selection enums (per unit)
+ enum aux_adc_t{
+ AUX_ADC_A = 'a',
+ AUX_ADC_B = 'b'
+ };
+
/*!
* Write to an aux dac.
*
@@ -56,7 +71,7 @@ public:
* \param which_dac the dac index 0, 1, 2, 3...
* \param value the value in volts
*/
- virtual void write_aux_dac(unit_t unit, int which_dac, float value) = 0;
+ virtual void write_aux_dac(unit_t unit, aux_dac_t which_dac, float value) = 0;
/*!
* Read from an aux adc.
@@ -65,7 +80,7 @@ public:
* \param which_adc the adc index 0, 1, 2, 3...
* \return the value in volts
*/
- virtual float read_aux_adc(unit_t unit, int which_adc) = 0;
+ virtual float read_aux_adc(unit_t unit, aux_adc_t which_adc) = 0;
/*!
* Set a daughterboard output pin control source.
@@ -159,6 +174,14 @@ public:
) = 0;
/*!
+ * Set the rate of a dboard clock.
+ *
+ * \param unit which unit rx or tx
+ * \param rate the clock rate in Hz
+ */
+ virtual void set_clock_rate(unit_t unit, double rate) = 0;
+
+ /*!
* Get the rate of a dboard clock.
*
* \param unit which unit rx or tx
@@ -167,6 +190,14 @@ public:
virtual double get_clock_rate(unit_t unit) = 0;
/*!
+ * Get a list of possible rates for the dboard clock.
+ *
+ * \param unit which unit rx or tx
+ * \return a list of clock rates in Hz
+ */
+ virtual std::vector<double> get_clock_rates(unit_t unit) = 0;
+
+ /*!
* Enable or disable a dboard clock.
*
* \param unit which unit rx or tx
diff --git a/host/include/uhd/usrp/dboard_manager.hpp b/host/include/uhd/usrp/dboard_manager.hpp
index b84fee4e7..e5831d4cf 100644
--- a/host/include/uhd/usrp/dboard_manager.hpp
+++ b/host/include/uhd/usrp/dboard_manager.hpp
@@ -40,7 +40,7 @@ public:
typedef dboard_base::sptr(*dboard_ctor_t)(dboard_base::ctor_args_t);
/*!
- * Register a dboard into the system.
+ * Register a rx or tx dboard into the system.
* For single subdevice boards, omit subdev_names.
* \param dboard_id the dboard id (rx or tx)
* \param dboard_ctor the dboard constructor function pointer
@@ -48,7 +48,24 @@ public:
* \param subdev_names the names of the subdevs on this dboard
*/
static void register_dboard(
- dboard_id_t dboard_id,
+ const dboard_id_t &dboard_id,
+ dboard_ctor_t dboard_ctor,
+ const std::string &name,
+ const prop_names_t &subdev_names = prop_names_t(1, "")
+ );
+
+ /*!
+ * Register an xcvr dboard into the system.
+ * For single subdevice boards, omit subdev_names.
+ * \param rx_dboard_id the rx unit dboard id
+ * \param tx_dboard_id the tx unit dboard id
+ * \param dboard_ctor the dboard constructor function pointer
+ * \param name the canonical name for the dboard represented
+ * \param subdev_names the names of the subdevs on this dboard
+ */
+ static void register_dboard(
+ const dboard_id_t &rx_dboard_id,
+ const dboard_id_t &tx_dboard_id,
dboard_ctor_t dboard_ctor,
const std::string &name,
const prop_names_t &subdev_names = prop_names_t(1, "")
diff --git a/host/include/uhd/utils/CMakeLists.txt b/host/include/uhd/utils/CMakeLists.txt
index 3684fd6e7..c98eec639 100644
--- a/host/include/uhd/utils/CMakeLists.txt
+++ b/host/include/uhd/utils/CMakeLists.txt
@@ -25,5 +25,6 @@ INSTALL(FILES
props.hpp
safe_main.hpp
static.hpp
+ thread_priority.hpp
DESTINATION ${INCLUDE_DIR}/uhd/utils
)
diff --git a/host/include/uhd/utils/thread_priority.hpp b/host/include/uhd/utils/thread_priority.hpp
new file mode 100644
index 000000000..988fc3012
--- /dev/null
+++ b/host/include/uhd/utils/thread_priority.hpp
@@ -0,0 +1,58 @@
+//
+// 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_UTILS_THREAD_PRIORITY_HPP
+#define INCLUDED_UHD_UTILS_THREAD_PRIORITY_HPP
+
+#include <uhd/config.hpp>
+
+namespace uhd{
+
+ static const float default_thread_priority = float(0.5);
+
+ /*!
+ * Set the scheduling priority on the current thread.
+ *
+ * A new thread or calling process should make this call
+ * with the defailts this to enable realtime scheduling.
+ *
+ * A priority of zero corresponds to normal priority.
+ * Positive priority values are higher than normal.
+ * Negative priority values are lower than normal.
+ *
+ * \param priority a value between -1 and 1
+ * \param realtime true to use realtime mode
+ * \throw exception on set priority failure
+ */
+ UHD_API void set_thread_priority(
+ float priority = default_thread_priority,
+ bool realtime = true
+ );
+
+ /*!
+ * Set the scheduling priority on the current thread.
+ * Same as set_thread_priority but does not throw on failure.
+ * \return true on success, false on failure
+ */
+ UHD_API bool set_thread_priority_safe(
+ float priority = default_thread_priority,
+ bool realtime = true
+ );
+
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_UTILS_THREAD_PRIORITY_HPP */
diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt
index 50787f6a2..d13c43bfb 100644
--- a/host/lib/CMakeLists.txt
+++ b/host/lib/CMakeLists.txt
@@ -76,17 +76,38 @@ INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/usrp/usrp2/CMakeLists.txt)
########################################################################
# Setup defines for process scheduling
########################################################################
-MESSAGE(STATUS "Configuring process scheduling...")
+MESSAGE(STATUS "Configuring priority scheduling...")
+
+INCLUDE(CheckCXXSourceCompiles)
+CHECK_CXX_SOURCE_COMPILES("
+ #include <pthread.h>
+ int main(){
+ struct sched_param sp;
+ pthread_setschedparam(pthread_self(), SCHED_RR, &sp);
+ return 0;
+ }
+ " HAVE_PTHREAD_SETSCHEDPARAM
+)
-INCLUDE(CheckIncludeFileCXX)
-CHECK_INCLUDE_FILE_CXX(sched.h HAVE_SCHED_H)
+CHECK_CXX_SOURCE_COMPILES("
+ #include <windows.h>
+ int main(){
+ SetThreadPriority(GetCurrentThread(), 0);
+ SetPriorityClass(GetCurrentProcess(), 0);
+ return 0;
+ }
+ " HAVE_WIN_SETTHREADPRIORITY
+)
-IF(HAVE_SCHED_H)
- MESSAGE(STATUS " Process scheduling supported through sched_setscheduler.")
- ADD_DEFINITIONS(-DHAVE_SCHED_H)
-ELSE(HAVE_SCHED_H)
- MESSAGE(STATUS " Process scheduling not supported.")
-ENDIF(HAVE_SCHED_H)
+IF(HAVE_PTHREAD_SETSCHEDPARAM)
+ MESSAGE(STATUS " Priority scheduling supported through pthread_setschedparam.")
+ ADD_DEFINITIONS(-DHAVE_PTHREAD_SETSCHEDPARAM)
+ELSEIF(HAVE_WIN_SETTHREADPRIORITY)
+ MESSAGE(STATUS " Priority scheduling supported through windows SetThreadPriority.")
+ ADD_DEFINITIONS(-DHAVE_WIN_SETTHREADPRIORITY)
+ELSE(HAVE_PTHREAD_SETSCHEDPARAM)
+ MESSAGE(STATUS " Priority scheduling not supported.")
+ENDIF(HAVE_PTHREAD_SETSCHEDPARAM)
########################################################################
# Setup defines for module loading
@@ -114,7 +135,7 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/device.cpp
${CMAKE_CURRENT_SOURCE_DIR}/gain_handler.cpp
${CMAKE_CURRENT_SOURCE_DIR}/load_modules.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/sched.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/thread_priority.cpp
${CMAKE_CURRENT_SOURCE_DIR}/types.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils.cpp
${CMAKE_CURRENT_SOURCE_DIR}/wax.cpp
diff --git a/host/lib/ic_reg_maps/common.py b/host/lib/ic_reg_maps/common.py
index 173186eb1..47325a7e3 100644
--- a/host/lib/ic_reg_maps/common.py
+++ b/host/lib/ic_reg_maps/common.py
@@ -59,7 +59,7 @@ public:
delete _state;
}
-$body
+ $body
void save_state(void){
if (_state == NULL) _state = new $(name)_t();
@@ -181,7 +181,7 @@ def generate(name, regs_tmpl, body_tmpl='', file=__file__):
else: regs.append(reg(entry))
#evaluate the body template with the list of registers
- body = parse_tmpl(body_tmpl, regs=regs).replace('\n', '\n ').strip()
+ body = '\n '.join(parse_tmpl(body_tmpl, regs=regs).splitlines())
#evaluate the code template with the parsed registers and arguments
code = parse_tmpl(COMMON_TMPL,
diff --git a/host/lib/ic_reg_maps/gen_ad9522_regs.py b/host/lib/ic_reg_maps/gen_ad9522_regs.py
index 9da51205b..ed6b5f48d 100755
--- a/host/lib/ic_reg_maps/gen_ad9522_regs.py
+++ b/host/lib/ic_reg_maps/gen_ad9522_regs.py
@@ -32,9 +32,11 @@ cp_mode 0x010[3:2] 3 high_imp, force
pll_power_down 0x010[1:0] 1 normal=0, async=1, sync=3
r_counter_lsb 0x011[7:0] 1
r_counter_msb 0x012[5:0] 0
+~r_counter r_counter_lsb, r_counter_msb
a_counter 0x013[5:0] 0
b_counter_lsb 0x014[7:0] 3
b_counter_msb 0x015[4:0] 0
+~b_counter b_counter_lsb, b_counter_msb
set_cp_pin_to_vcp_2 0x016[7] 0 normal, vcp_2
reset_r_counter 0x016[6] 0
reset_a_and_b_counters 0x016[5] 0
diff --git a/host/lib/load_modules.cpp b/host/lib/load_modules.cpp
index d6bfe1369..dbb8d0695 100644
--- a/host/lib/load_modules.cpp
+++ b/host/lib/load_modules.cpp
@@ -30,7 +30,7 @@ namespace fs = boost::filesystem;
/***********************************************************************
* Module Load Function
**********************************************************************/
-#ifdef HAVE_DLFCN_H
+#if defined(HAVE_DLFCN_H)
#include <dlfcn.h>
static const std::string env_path_sep = ":";
@@ -42,7 +42,7 @@ static void load_module(const std::string &file_name){
}
}
-#elif HAVE_WINDOWS_H
+#elif defined(HAVE_WINDOWS_H)
#include <windows.h>
static const std::string env_path_sep = ";";
diff --git a/host/lib/sched.cpp b/host/lib/sched.cpp
deleted file mode 100644
index 712014c9c..000000000
--- a/host/lib/sched.cpp
+++ /dev/null
@@ -1,45 +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 <uhd/utils/static.hpp>
-#include <stdexcept>
-#include <iostream>
-
-#ifdef HAVE_SCHED_H
-#include <sched.h>
-
-/*
- * # /etc/security/limits.conf
-#
-@usrp - rtprio 99
-*/
-
-UHD_STATIC_BLOCK(setup_process_sched){
- try{
- int policy = SCHED_RR;
- int max_pri = sched_get_priority_max(policy);
- if (max_pri == -1) throw std::runtime_error("sched_get_priority_max with SCHED_RR failed");
- sched_param sp; sp.sched_priority = max_pri;
- int ss_ret = sched_setscheduler(0, policy, &sp);
- if (ss_ret == -1) throw std::runtime_error("sched_setscheduler with SCHED_RR failed");
- }
- catch(const std::exception &e){
- std::cerr << "Process scheduling error: " << e.what() << std::endl;
- }
-}
-
-#endif /* HAVE_SCHED_H */
diff --git a/host/lib/thread_priority.cpp b/host/lib/thread_priority.cpp
new file mode 100644
index 000000000..c35e5fcb1
--- /dev/null
+++ b/host/lib/thread_priority.cpp
@@ -0,0 +1,98 @@
+//
+// Copyright 2010 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/utils/thread_priority.hpp>
+#include <stdexcept>
+#include <iostream>
+
+bool uhd::set_thread_priority_safe(float priority, bool realtime){
+ try{
+ set_thread_priority(priority, realtime);
+ return true;
+ }catch(const std::exception &e){
+ std::cerr << "set_thread_priority: " << e.what() << std::endl;
+ return false;
+ }
+}
+
+static void check_priority_range(float priority){
+ if (priority > +1.0 or priority < -1.0)
+ throw std::range_error("priority out of range [-1.0, +1.0]");
+}
+
+/***********************************************************************
+ * Pthread API to set priority
+ **********************************************************************/
+#if defined(HAVE_PTHREAD_SETSCHEDPARAM)
+ #include <pthread.h>
+
+ void uhd::set_thread_priority(float priority, bool realtime){
+ check_priority_range(priority);
+
+ //when realtime is not enabled, use sched other
+ int policy = (realtime)? SCHED_RR : SCHED_OTHER;
+
+ //we cannot have below normal priority, set to zero
+ if (priority < 0) priority = 0;
+
+ //get the priority bounds for the selected policy
+ int min_pri = sched_get_priority_min(policy);
+ int max_pri = sched_get_priority_max(policy);
+ if (min_pri == -1 or max_pri == -1) throw std::runtime_error("error in sched_get_priority_min/max");
+
+ //set the new priority and policy
+ sched_param sp;
+ sp.sched_priority = int(priority*(max_pri - min_pri)) + min_pri;
+ int ret = pthread_setschedparam(pthread_self(), policy, &sp);
+ if (ret != 0) throw std::runtime_error("error in pthread_setschedparam");
+ }
+
+/***********************************************************************
+ * Windows API to set priority
+ **********************************************************************/
+#elif defined(HAVE_WIN_SETTHREADPRIORITY)
+ #include <windows.h>
+
+ void uhd::set_thread_priority(float priority, bool realtime){
+ check_priority_range(priority);
+
+ //set the priority class on the process
+ int pri_class = (realtime)? REALTIME_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS;
+ if (SetPriorityClass(GetCurrentProcess(), pri_class) == 0)
+ throw std::runtime_error("error in SetPriorityClass");
+
+ //scale the priority value to the constants
+ int priorities[] = {
+ THREAD_PRIORITY_IDLE, THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_BELOW_NORMAL, THREAD_PRIORITY_NORMAL,
+ THREAD_PRIORITY_ABOVE_NORMAL, THREAD_PRIORITY_HIGHEST, THREAD_PRIORITY_TIME_CRITICAL
+ };
+ size_t pri_index = size_t((priority+1.0)*6/2.0); // -1 -> 0, +1 -> 6
+
+ //set the thread priority on the thread
+ if (SetThreadPriority(GetCurrentThread(), priorities[pri_index]) == 0)
+ throw std::runtime_error("error in SetThreadPriority");
+ }
+
+/***********************************************************************
+ * Unimplemented API to set priority
+ **********************************************************************/
+#else
+ void uhd::set_thread_priority(float, bool){
+ throw std::runtime_error("set thread priority not implemented");
+ }
+
+#endif /* HAVE_PTHREAD_SETSCHEDPARAM */
diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt
index 872865d6c..70cf6312d 100644
--- a/host/lib/transport/CMakeLists.txt
+++ b/host/lib/transport/CMakeLists.txt
@@ -18,6 +18,16 @@
#This file will be included by cmake, use absolute paths!
########################################################################
+# Check for SIMD headers
+########################################################################
+INCLUDE(CheckIncludeFileCXX)
+CHECK_INCLUDE_FILE_CXX(emmintrin.h HAVE_EMMINTRIN_H)
+
+IF(HAVE_EMMINTRIN_H)
+ ADD_DEFINITIONS(-DHAVE_EMMINTRIN_H)
+ENDIF(HAVE_EMMINTRIN_H)
+
+########################################################################
# Setup defines for interface address discovery
########################################################################
MESSAGE(STATUS "Configuring interface address discovery...")
@@ -49,6 +59,16 @@ LIBUHD_PYTHON_GEN_SOURCE(
${CMAKE_BINARY_DIR}/lib/transport/convert_types.cpp
)
+# append this directory to the include path so the generated convert types
+# can include the implementation convert types file in the source directory
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/transport)
+
+# make the generated convert types depend on the implementation header
+SET_SOURCE_FILES_PROPERTIES(
+ ${CMAKE_BINARY_DIR}/lib/transport/convert_types.cpp PROPERTIES
+ OBJECT_DEPENDS ${CMAKE_SOURCE_DIR}/lib/transport/convert_types_impl.hpp
+)
+
LIBUHD_APPEND_SOURCES(
${CMAKE_SOURCE_DIR}/lib/transport/if_addrs.cpp
${CMAKE_SOURCE_DIR}/lib/transport/udp_simple.cpp
diff --git a/host/lib/transport/convert_types_impl.hpp b/host/lib/transport/convert_types_impl.hpp
new file mode 100644
index 000000000..5958b08cb
--- /dev/null
+++ b/host/lib/transport/convert_types_impl.hpp
@@ -0,0 +1,201 @@
+//
+// 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_CONVERT_TYPES_IMPL_HPP
+#define INCLUDED_LIBUHD_TRANSPORT_CONVERT_TYPES_IMPL_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/utils/byteswap.hpp>
+#include <boost/cstdint.hpp>
+#include <cstring>
+#include <complex>
+
+#ifdef HAVE_EMMINTRIN_H
+ #define USE_EMMINTRIN_H //use sse2 intrinsics
+#endif
+
+/***********************************************************************
+ * Typedefs
+ **********************************************************************/
+typedef std::complex<float> fc32_t;
+typedef std::complex<boost::int16_t> sc16_t;
+typedef boost::uint32_t item32_t;
+
+/***********************************************************************
+ * Convert complex short buffer to items32
+ **********************************************************************/
+static UHD_INLINE void sc16_to_item32_nswap(
+ const sc16_t *input, item32_t *output, size_t nsamps
+){
+ std::memcpy(output, input, nsamps*sizeof(item32_t));
+}
+
+static UHD_INLINE void sc16_to_item32_bswap(
+ const sc16_t *input, item32_t *output, size_t nsamps
+){
+ const item32_t *item32_input = (const item32_t *)input;
+ for (size_t i = 0; i < nsamps; i++){
+ output[i] = uhd::byteswap(item32_input[i]);
+ }
+}
+
+/***********************************************************************
+ * Convert items32 buffer to complex short
+ **********************************************************************/
+static UHD_INLINE void item32_to_sc16_nswap(
+ const item32_t *input, sc16_t *output, size_t nsamps
+){
+ std::memcpy(output, input, nsamps*sizeof(item32_t));
+}
+
+static UHD_INLINE void item32_to_sc16_bswap(
+ const item32_t *input, sc16_t *output, size_t nsamps
+){
+ item32_t *item32_output = (item32_t *)output;
+ for (size_t i = 0; i < nsamps; i++){
+ item32_output[i] = uhd::byteswap(input[i]);
+ }
+}
+
+/***********************************************************************
+ * Convert complex float buffer to items32
+ **********************************************************************/
+static const float shorts_per_float = float(32767);
+
+static UHD_INLINE item32_t fc32_to_item32(fc32_t num){
+ boost::uint16_t real = boost::int16_t(num.real()*shorts_per_float);
+ boost::uint16_t imag = boost::int16_t(num.imag()*shorts_per_float);
+ return (item32_t(real) << 16) | (item32_t(imag) << 0);
+}
+
+static UHD_INLINE void fc32_to_item32_nswap(
+ const fc32_t *input, item32_t *output, size_t nsamps
+){
+ for (size_t i = 0; i < nsamps; i++){
+ output[i] = fc32_to_item32(input[i]);
+ }
+}
+
+#if defined(USE_EMMINTRIN_H)
+#include <emmintrin.h>
+
+static UHD_INLINE void fc32_to_item32_bswap(
+ const fc32_t *input, item32_t *output, size_t nsamps
+){
+ __m128 scalar = _mm_set_ps1(shorts_per_float);
+
+ //convert blocks of samples with intrinsics
+ size_t i = 0; for (; i < (nsamps & ~0x3); i+=4){
+ //load from input
+ __m128 tmplo = _mm_loadu_ps(reinterpret_cast<const float *>(input+i+0));
+ __m128 tmphi = _mm_loadu_ps(reinterpret_cast<const float *>(input+i+2));
+
+ //convert and scale
+ __m128i tmpilo = _mm_cvtps_epi32(_mm_mul_ps(tmplo, scalar));
+ __m128i tmpihi = _mm_cvtps_epi32(_mm_mul_ps(tmphi, scalar));
+
+ //pack + byteswap -> byteswap 32 bit words
+ __m128i tmpi = _mm_packs_epi32(tmpilo, tmpihi);
+ tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8));
+
+ //store to output
+ _mm_storeu_si128(reinterpret_cast<__m128i *>(output+i), tmpi);
+ }
+
+ //convert remainder
+ for (; i < nsamps; i++){
+ output[i] = uhd::byteswap(fc32_to_item32(input[i]));
+ }
+}
+
+#else
+static UHD_INLINE void fc32_to_item32_bswap(
+ const fc32_t *input, item32_t *output, size_t nsamps
+){
+ for (size_t i = 0; i < nsamps; i++){
+ output[i] = uhd::byteswap(fc32_to_item32(input[i]));
+ }
+}
+
+#endif
+
+/***********************************************************************
+ * Convert items32 buffer to complex float
+ **********************************************************************/
+static const float floats_per_short = float(1.0/shorts_per_float);
+
+static UHD_INLINE fc32_t item32_to_fc32(item32_t item){
+ return fc32_t(
+ float(boost::int16_t(item >> 16)*floats_per_short),
+ float(boost::int16_t(item >> 0)*floats_per_short)
+ );
+}
+
+static UHD_INLINE void item32_to_fc32_nswap(
+ const item32_t *input, fc32_t *output, size_t nsamps
+){
+ for (size_t i = 0; i < nsamps; i++){
+ output[i] = item32_to_fc32(input[i]);
+ }
+}
+
+#if defined(USE_EMMINTRIN_H)
+#include <emmintrin.h>
+
+static UHD_INLINE void item32_to_fc32_bswap(
+ const item32_t *input, fc32_t *output, size_t nsamps
+){
+ __m128 scalar = _mm_set_ps1(floats_per_short/(1 << 16));
+ __m128i zeroi = _mm_setzero_si128();
+
+ //convert blocks of samples with intrinsics
+ size_t i = 0; for (; i < (nsamps & ~0x3); i+=4){
+ //load from input
+ __m128i tmpi = _mm_loadu_si128(reinterpret_cast<const __m128i *>(input+i));
+
+ //byteswap + unpack -> byteswap 32 bit words
+ tmpi = _mm_or_si128(_mm_srli_epi16(tmpi, 8), _mm_slli_epi16(tmpi, 8));
+ __m128i tmpilo = _mm_unpacklo_epi16(zeroi, tmpi); //value in upper 16 bits
+ __m128i tmpihi = _mm_unpackhi_epi16(zeroi, tmpi);
+
+ //convert and scale
+ __m128 tmplo = _mm_mul_ps(_mm_cvtepi32_ps(tmpilo), scalar);
+ __m128 tmphi = _mm_mul_ps(_mm_cvtepi32_ps(tmpihi), scalar);
+
+ //store to output
+ _mm_storeu_ps(reinterpret_cast<float *>(output+i+0), tmplo);
+ _mm_storeu_ps(reinterpret_cast<float *>(output+i+2), tmphi);
+ }
+
+ //convert remainder
+ for (; i < nsamps; i++){
+ output[i] = item32_to_fc32(uhd::byteswap(input[i]));
+ }
+}
+
+#else
+static UHD_INLINE void item32_to_fc32_bswap(
+ const item32_t *input, fc32_t *output, size_t nsamps
+){
+ for (size_t i = 0; i < nsamps; i++){
+ output[i] = item32_to_fc32(uhd::byteswap(input[i]));
+ }
+}
+
+#endif
+
+#endif /* INCLUDED_LIBUHD_TRANSPORT_CONVERT_TYPES_IMPL_HPP */
diff --git a/host/lib/transport/gen_convert_types.py b/host/lib/transport/gen_convert_types.py
index af2bcc7cb..951b634d9 100755
--- a/host/lib/transport/gen_convert_types.py
+++ b/host/lib/transport/gen_convert_types.py
@@ -24,66 +24,15 @@ TMPL_TEXT = """
\#include <uhd/config.hpp>
\#include <uhd/transport/convert_types.hpp>
-\#include <uhd/utils/byteswap.hpp>
\#include <boost/cstdint.hpp>
\#include <boost/detail/endian.hpp>
\#include <stdexcept>
-\#include <complex>
-
-//define the endian macros to convert integers
-\#ifdef BOOST_BIG_ENDIAN
- \#define BE_MACRO(x) x
- \#define LE_MACRO(x) uhd::byteswap(x)
- static const bool is_big_endian = true;
-\#else
- \#define BE_MACRO(x) uhd::byteswap(x)
- \#define LE_MACRO(x) x
- static const bool is_big_endian = false;
-\#endif
+\#include "convert_types_impl.hpp"
using namespace uhd;
/***********************************************************************
- * Constants
- **********************************************************************/
-typedef std::complex<float> fc32_t;
-typedef std::complex<boost::int16_t> sc16_t;
-typedef boost::uint32_t item32_t;
-
-static const float shorts_per_float = float(32767);
-static const float floats_per_short = float(1.0/shorts_per_float);
-
-/***********************************************************************
- * Single-sample converters
- **********************************************************************/
-static UHD_INLINE item32_t sc16_to_item32(sc16_t num){
- boost::uint16_t real = boost::int16_t(num.real());
- boost::uint16_t imag = boost::int16_t(num.imag());
- return (item32_t(real) << 16) | (item32_t(imag) << 0);
-}
-
-static UHD_INLINE sc16_t item32_to_sc16(item32_t item){
- return sc16_t(
- boost::uint16_t(item >> 16),
- boost::uint16_t(item >> 0)
- );
-}
-
-static UHD_INLINE item32_t fc32_to_item32(fc32_t num){
- boost::uint16_t real = boost::int16_t(num.real()*shorts_per_float);
- boost::uint16_t imag = boost::int16_t(num.imag()*shorts_per_float);
- return (item32_t(real) << 16) | (item32_t(imag) << 0);
-}
-
-static UHD_INLINE fc32_t item32_to_fc32(item32_t item){
- return fc32_t(
- float(boost::int16_t(item >> 16)*floats_per_short),
- float(boost::int16_t(item >> 0)*floats_per_short)
- );
-}
-
-/***********************************************************************
- * Sample-buffer converters
+ * Generate predicate for jump table
**********************************************************************/
UHD_INLINE boost::uint8_t get_pred(
const io_type_t &io_type,
@@ -92,27 +41,34 @@ UHD_INLINE boost::uint8_t get_pred(
boost::uint8_t pred = 0;
switch(otw_type.byteorder){
- case otw_type_t::BO_BIG_ENDIAN: pred |= $ph.be_p; break;
- case otw_type_t::BO_LITTLE_ENDIAN: pred |= $ph.le_p; break;
- ##let the compiler determine the native byte order (we could use python sys.byteorder)
- case otw_type_t::BO_NATIVE: pred |= (is_big_endian)? $ph.be_p : $ph.le_p; break;
- default: throw std::runtime_error("unhandled byteorder type");
+ \#ifdef BOOST_BIG_ENDIAN
+ case otw_type_t::BO_BIG_ENDIAN: pred |= $ph.nswap_p; break;
+ case otw_type_t::BO_LITTLE_ENDIAN: pred |= $ph.bswap_p; break;
+ \#else
+ case otw_type_t::BO_BIG_ENDIAN: pred |= $ph.bswap_p; break;
+ case otw_type_t::BO_LITTLE_ENDIAN: pred |= $ph.nswap_p; break;
+ \#endif
+ case otw_type_t::BO_NATIVE: pred |= $ph.nswap_p; break;
+ default: throw std::runtime_error("unhandled otw byteorder type");
}
- switch(otw_type.width){
- case 16: pred |= $ph.w16_p; break;
- default: throw std::runtime_error("unhandled bit width");
+ switch(otw_type.get_sample_size()){
+ case sizeof(boost::uint32_t): pred |= $ph.item32_p; break;
+ default: throw std::runtime_error("unhandled otw sample size");
}
switch(io_type.tid){
- case io_type_t::COMPLEX_INT16: pred |= $ph.sc16_p; break;
case io_type_t::COMPLEX_FLOAT32: pred |= $ph.fc32_p; break;
+ case io_type_t::COMPLEX_INT16: pred |= $ph.sc16_p; break;
default: throw std::runtime_error("unhandled io type id");
}
return pred;
}
+/***********************************************************************
+ * Convert host type to device type
+ **********************************************************************/
void transport::convert_io_type_to_otw_type(
const void *io_buff, const io_type_t &io_type,
void *otw_buff, const otw_type_t &otw_type,
@@ -123,16 +79,16 @@ void transport::convert_io_type_to_otw_type(
case $pred:
#set $out_type = $ph.get_dev_type($pred)
#set $in_type = $ph.get_host_type($pred)
- #set $converter = $in_type+"_to_"+$out_type
- #set $xe_macro = $ph.get_xe_macro($pred)
- for (size_t i = 0; i < num_samps; i++){
- (($(out_type)_t *)otw_buff)[i] = $(xe_macro)($(converter)(((const $(in_type)_t *)io_buff)[i]));
- }
+ #set $converter = '_'.join([$in_type, 'to', $out_type, $ph.get_swap_type($pred)])
+ $(converter)((const $(in_type)_t *)io_buff, ($(out_type)_t *)otw_buff, num_samps);
break;
#end for
}
}
+/***********************************************************************
+ * Convert device type to host type
+ **********************************************************************/
void transport::convert_otw_type_to_io_type(
const void *otw_buff, const otw_type_t &otw_type,
void *io_buff, const io_type_t &io_type,
@@ -143,11 +99,8 @@ void transport::convert_otw_type_to_io_type(
case $pred:
#set $out_type = $ph.get_host_type($pred)
#set $in_type = $ph.get_dev_type($pred)
- #set $converter = $in_type+"_to_"+$out_type
- #set $xe_macro = $ph.get_xe_macro($pred)
- for (size_t i = 0; i < num_samps; i++){
- (($(out_type)_t *)io_buff)[i] = $(converter)($(xe_macro)(((const $(in_type)_t *)otw_buff)[i]));
- }
+ #set $converter = '_'.join([$in_type, 'to', $out_type, $ph.get_swap_type($pred)])
+ $(converter)((const $(in_type)_t *)otw_buff, ($(out_type)_t *)io_buff, num_samps);
break;
#end for
}
@@ -160,29 +113,32 @@ def parse_tmpl(_tmpl_text, **kwargs):
return str(Template(_tmpl_text, kwargs))
class ph:
- be_p = 0b00001
- le_p = 0b00000
- w16_p = 0b00000
- sc16_p = 0b00010
- fc32_p = 0b00000
+ bswap_p = 0b00001
+ nswap_p = 0b00000
+ item32_p = 0b00000
+ sc16_p = 0b00010
+ fc32_p = 0b00000
nbits = 2 #see above
@staticmethod
- def get_xe_macro(pred):
- if (pred & ph.be_p) == ph.be_p: return 'BE_MACRO'
- if (pred & ph.le_p) == ph.le_p: return 'LE_MACRO'
+ def has(pred, flag): return (pred & flag) == flag
+
+ @staticmethod
+ def get_swap_type(pred):
+ if ph.has(pred, ph.bswap_p): return 'bswap'
+ if ph.has(pred, ph.nswap_p): return 'nswap'
raise NotImplementedError
@staticmethod
def get_dev_type(pred):
- if (pred & ph.w16_p) == ph.w16_p: return 'item32'
+ if ph.has(pred, ph.item32_p): return 'item32'
raise NotImplementedError
@staticmethod
def get_host_type(pred):
- if (pred & ph.sc16_p) == ph.sc16_p: return 'sc16'
- if (pred & ph.fc32_p) == ph.fc32_p: return 'fc32'
+ if ph.has(pred, ph.sc16_p): return 'sc16'
+ if ph.has(pred, ph.fc32_p): return 'fc32'
raise NotImplementedError
if __name__ == '__main__':
diff --git a/host/lib/transport/gen_vrt.py b/host/lib/transport/gen_vrt.py
index 6cdd6645d..8e0fce9ff 100755
--- a/host/lib/transport/gen_vrt.py
+++ b/host/lib/transport/gen_vrt.py
@@ -97,7 +97,7 @@ void vrt::pack_$(suffix)(
#end if
########## Integer Time ##########
#if $pred & $tsi_p
- header_buff[$num_header_words] = $(XE_MACRO)(metadata.time_spec.secs);
+ header_buff[$num_header_words] = $(XE_MACRO)(boost::uint32_t(metadata.time_spec.get_full_secs()));
#set $num_header_words += 1
#set $flags |= (0x3 << 22);
#end if
@@ -105,7 +105,7 @@ void vrt::pack_$(suffix)(
#if $pred & $tsf_p
header_buff[$num_header_words] = 0;
#set $num_header_words += 1
- header_buff[$num_header_words] = $(XE_MACRO)(metadata.time_spec.get_ticks(tick_rate));
+ header_buff[$num_header_words] = $(XE_MACRO)(boost::uint32_t(metadata.time_spec.get_tick_count(tick_rate)));
#set $num_header_words += 1
#set $flags |= (0x1 << 20);
#end if
@@ -147,6 +147,7 @@ void vrt::unpack_$(suffix)(
){
//clear the metadata
metadata = rx_metadata_t();
+ boost::uint32_t secs = 0, ticks = 0;
//extract vrt header
boost::uint32_t vrt_hdr_word = $(XE_MACRO)(header_buff[0]);
@@ -169,7 +170,7 @@ void vrt::unpack_$(suffix)(
switch(pred){
#for $pred in range(2**5)
case $pred:
- #set $set_has_time_spec = False
+ #set $has_time_spec = False
#set $num_header_words = 1
########## Stream ID ##########
#if $pred & $sid_p
@@ -184,21 +185,21 @@ void vrt::unpack_$(suffix)(
#end if
########## Integer Time ##########
#if $pred & $tsi_p
- metadata.has_time_spec = true;
- #set $set_has_time_spec = True
- metadata.time_spec.secs = $(XE_MACRO)(header_buff[$num_header_words]);
+ #set $has_time_spec = True
+ secs = $(XE_MACRO)(header_buff[$num_header_words]);
#set $num_header_words += 1
#end if
########## Fractional Time ##########
#if $pred & $tsf_p
- #if not $set_has_time_spec
- metadata.has_time_spec = true;
- #set $set_has_time_spec = True
- #end if
+ #set $has_time_spec = True
#set $num_header_words += 1
- metadata.time_spec.set_ticks($(XE_MACRO)(header_buff[$num_header_words]), tick_rate);
+ ticks = $(XE_MACRO)(header_buff[$num_header_words]);
#set $num_header_words += 1
#end if
+ #if $has_time_spec
+ metadata.has_time_spec = true;
+ metadata.time_spec = time_spec_t(secs, ticks, tick_rate);
+ #end if
########## Trailer ##########
#if $pred & $tlr_p
#set $num_trailer_words = 1;
diff --git a/host/lib/transport/if_addrs.cpp b/host/lib/transport/if_addrs.cpp
index 5c8c8a176..ad9a2325b 100644
--- a/host/lib/transport/if_addrs.cpp
+++ b/host/lib/transport/if_addrs.cpp
@@ -27,7 +27,7 @@ uhd::transport::if_addrs_t::if_addrs_t(void){
/***********************************************************************
* Interface address discovery through ifaddrs api
**********************************************************************/
-#ifdef HAVE_IFADDRS_H
+#if defined(HAVE_IFADDRS_H)
#include <ifaddrs.h>
static boost::asio::ip::address_v4 sockaddr_to_ip_addr(sockaddr *addr){
@@ -59,9 +59,9 @@ std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void){
}
/***********************************************************************
- * Interface address discovery through windows api (TODO)
+ * Interface address discovery through windows api
**********************************************************************/
-#elif HAVE_WINSOCK2_H
+#elif defined(HAVE_WINSOCK2_H)
#include <winsock2.h>
std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void){
diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp
index c3c02707e..7f9292d24 100644
--- a/host/lib/transport/udp_zero_copy_asio.cpp
+++ b/host/lib/transport/udp_zero_copy_asio.cpp
@@ -27,7 +27,8 @@ using namespace uhd::transport;
/***********************************************************************
* Constants
**********************************************************************/
-static const size_t MIN_SOCK_BUFF_SIZE = size_t(100e3);
+//enough buffering for half a second of samples at full rate on usrp2
+static const size_t MIN_SOCK_BUFF_SIZE = size_t(sizeof(boost::uint32_t) * 25e6 * 0.5);
static const size_t MAX_DGRAM_SIZE = 1500; //assume max size on send and recv
static const double RECV_TIMEOUT = 0.1; //100 ms
@@ -159,6 +160,12 @@ template<typename Opt> static void resize_buff_helper(
//otherwise, ensure that the buffer is at least the minimum size
else if (udp_trans->get_buff_size<Opt>() < MIN_SOCK_BUFF_SIZE){
resize_buff_helper<Opt>(udp_trans, MIN_SOCK_BUFF_SIZE, name);
+ if (udp_trans->get_buff_size<Opt>() < MIN_SOCK_BUFF_SIZE){
+ std::cerr << boost::format(
+ "Warning: the %s buffer size is smaller than the recommended size of %d bytes.\n"
+ " See the USRP2 application notes on buffer resizing."
+ ) % name % MIN_SOCK_BUFF_SIZE << std::endl;
+ }
}
}
diff --git a/host/lib/types.cpp b/host/lib/types.cpp
index daf3be7f7..6a9fcf5b5 100644
--- a/host/lib/types.cpp
+++ b/host/lib/types.cpp
@@ -120,19 +120,63 @@ tx_metadata_t::tx_metadata_t(void):
/***********************************************************************
* time spec
**********************************************************************/
-time_spec_t::time_spec_t(boost::uint32_t secs, double nsecs):
- secs(secs),
- nsecs(nsecs)
+time_spec_t::time_spec_t(double secs):
+ _full_secs(0),
+ _frac_secs(secs)
{
/* NOP */
}
-boost::uint32_t time_spec_t::get_ticks(double tick_rate) const{
- return boost::math::iround(nsecs*tick_rate*1e-9);
+time_spec_t::time_spec_t(time_t full_secs, double frac_secs):
+ _full_secs(full_secs),
+ _frac_secs(frac_secs)
+{
+ /* NOP */
+}
+
+time_spec_t::time_spec_t(time_t full_secs, size_t tick_count, double tick_rate):
+ _full_secs(full_secs),
+ _frac_secs(double(tick_count)/tick_rate)
+{
+ /* NOP */
+}
+
+size_t time_spec_t::get_tick_count(double tick_rate) const{
+ return boost::math::iround(this->get_frac_secs()*tick_rate);
+}
+
+double time_spec_t::get_real_secs(void) const{
+ return this->_full_secs + this->_frac_secs;
+}
+
+time_t time_spec_t::get_full_secs(void) const{
+ return this->_full_secs + time_t(std::floor(this->_frac_secs));
+}
+
+double time_spec_t::get_frac_secs(void) const{
+ return std::fmod(this->_frac_secs, 1.0);
+}
+
+time_spec_t &time_spec_t::operator+=(const time_spec_t &rhs){
+ this->_full_secs += rhs.get_full_secs();
+ this->_frac_secs += rhs.get_frac_secs();
+ return *this;
+}
+
+time_spec_t &time_spec_t::operator-=(const time_spec_t &rhs){
+ this->_full_secs -= rhs.get_full_secs();
+ this->_frac_secs -= rhs.get_frac_secs();
+ return *this;
+}
+
+bool uhd::operator==(const time_spec_t &lhs, const time_spec_t &rhs){
+ return lhs.get_full_secs() == rhs.get_full_secs() and lhs.get_frac_secs() == rhs.get_frac_secs();
}
-void time_spec_t::set_ticks(boost::uint32_t ticks, double tick_rate){
- nsecs = double(ticks)*1e9/tick_rate;
+bool uhd::operator<(const time_spec_t &lhs, const time_spec_t &rhs){
+ if (lhs.get_full_secs() < rhs.get_full_secs()) return true;
+ if (lhs.get_full_secs() > rhs.get_full_secs()) return false;
+ return lhs.get_frac_secs() < rhs.get_frac_secs();
}
/***********************************************************************
diff --git a/host/lib/usrp/dboard/CMakeLists.txt b/host/lib/usrp/dboard/CMakeLists.txt
index 3a6c2d84a..6093583d3 100644
--- a/host/lib/usrp/dboard/CMakeLists.txt
+++ b/host/lib/usrp/dboard/CMakeLists.txt
@@ -22,5 +22,6 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_rfx.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_xcvr2450.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_wbx.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_unknown.cpp
)
diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp
index 2585dfa8d..2d6088983 100644
--- a/host/lib/usrp/dboard/db_rfx.cpp
+++ b/host/lib/usrp/dboard/db_rfx.cpp
@@ -137,25 +137,21 @@ static dboard_base::sptr make_rfx_flex1200(dboard_base::ctor_args_t args){
return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(1150e6, 1450e6), true, true));
}
+static dboard_base::sptr make_rfx_flex2200(dboard_base::ctor_args_t args){
+ return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(2000e6, 2400e6), false, false));
+}
+
static dboard_base::sptr make_rfx_flex2400(dboard_base::ctor_args_t args){
return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(2300e6, 2900e6), false, false));
}
UHD_STATIC_BLOCK(reg_rfx_dboards){
- dboard_manager::register_dboard(0x0024, &make_rfx_flex400, "Flex 400 Rx MIMO B");
- dboard_manager::register_dboard(0x0028, &make_rfx_flex400, "Flex 400 Tx MIMO B");
-
- dboard_manager::register_dboard(0x0025, &make_rfx_flex900, "Flex 900 Rx MIMO B");
- dboard_manager::register_dboard(0x0029, &make_rfx_flex900, "Flex 900 Tx MIMO B");
-
- dboard_manager::register_dboard(0x0034, &make_rfx_flex1800, "Flex 1800 Rx MIMO B");
- dboard_manager::register_dboard(0x0035, &make_rfx_flex1800, "Flex 1800 Tx MIMO B");
-
- dboard_manager::register_dboard(0x0026, &make_rfx_flex1200, "Flex 1200 Rx MIMO B");
- dboard_manager::register_dboard(0x002a, &make_rfx_flex1200, "Flex 1200 Tx MIMO B");
-
- dboard_manager::register_dboard(0x0027, &make_rfx_flex2400, "Flex 2400 Rx MIMO B");
- dboard_manager::register_dboard(0x002b, &make_rfx_flex2400, "Flex 2400 Tx MIMO B");
+ dboard_manager::register_dboard(0x0024, 0x0028, &make_rfx_flex400, "Flex 400 MIMO B");
+ dboard_manager::register_dboard(0x0025, 0x0029, &make_rfx_flex900, "Flex 900 MIMO B");
+ dboard_manager::register_dboard(0x0034, 0x0035, &make_rfx_flex1800, "Flex 1800 MIMO B");
+ dboard_manager::register_dboard(0x0026, 0x002a, &make_rfx_flex1200, "Flex 1200 MIMO B");
+ dboard_manager::register_dboard(0x002c, 0x002d, &make_rfx_flex2200, "Flex 2200 MIMO B");
+ dboard_manager::register_dboard(0x0027, 0x002b, &make_rfx_flex2400, "Flex 2400 MIMO B");
}
/***********************************************************************
@@ -257,7 +253,7 @@ void rfx_xcvr::set_rx_gain(float gain, const std::string &name){
_rx_gains[name] = gain;
//write the new voltage to the aux dac
- this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, 0, dac_volts);
+ this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_A, dac_volts);
}
else UHD_THROW_INVALID_CODE_PATH();
}
diff --git a/host/lib/usrp/dboard/db_unknown.cpp b/host/lib/usrp/dboard/db_unknown.cpp
new file mode 100644
index 000000000..ced27e34d
--- /dev/null
+++ b/host/lib/usrp/dboard/db_unknown.cpp
@@ -0,0 +1,265 @@
+//
+// 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/subdev_props.hpp>
+#include <uhd/types/ranges.hpp>
+#include <uhd/utils/assert.hpp>
+#include <uhd/utils/static.hpp>
+#include <uhd/usrp/dboard_base.hpp>
+#include <uhd/usrp/dboard_manager.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/format.hpp>
+
+using namespace uhd;
+using namespace uhd::usrp;
+using namespace boost::assign;
+
+/***********************************************************************
+ * The unknown boards:
+ * Like a basic board, but with only one subdev.
+ **********************************************************************/
+class unknown_rx : public rx_dboard_base{
+public:
+ unknown_rx(ctor_args_t args);
+ ~unknown_rx(void);
+
+ void rx_get(const wax::obj &key, wax::obj &val);
+ void rx_set(const wax::obj &key, const wax::obj &val);
+};
+
+class unknown_tx : public tx_dboard_base{
+public:
+ unknown_tx(ctor_args_t args);
+ ~unknown_tx(void);
+
+ void tx_get(const wax::obj &key, wax::obj &val);
+ void tx_set(const wax::obj &key, const wax::obj &val);
+};
+
+/***********************************************************************
+ * Register the unknown dboards
+ **********************************************************************/
+static dboard_base::sptr make_unknown_rx(dboard_base::ctor_args_t args){
+ return dboard_base::sptr(new unknown_rx(args));
+}
+
+static dboard_base::sptr make_unknown_tx(dboard_base::ctor_args_t args){
+ return dboard_base::sptr(new unknown_tx(args));
+}
+
+UHD_STATIC_BLOCK(reg_unknown_dboards){
+ dboard_manager::register_dboard(0xfff0, &make_unknown_tx, "Unknown TX");
+ dboard_manager::register_dboard(0xfff1, &make_unknown_rx, "Unknown RX");
+}
+
+/***********************************************************************
+ * Unknown RX dboard
+ **********************************************************************/
+unknown_rx::unknown_rx(ctor_args_t args) : rx_dboard_base(args){
+ /* NOP */
+}
+
+unknown_rx::~unknown_rx(void){
+ /* NOP */
+}
+
+void unknown_rx::rx_get(const wax::obj &key_, wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+ case SUBDEV_PROP_NAME:
+ val = "Unknown - " + get_rx_id().to_pp_string();
+ return;
+
+ case SUBDEV_PROP_OTHERS:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ val = float(0);
+ return;
+
+ case SUBDEV_PROP_GAIN_RANGE:
+ val = gain_range_t(0, 0, 0);
+ return;
+
+ case SUBDEV_PROP_GAIN_NAMES:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ val = double(0);
+ return;
+
+ case SUBDEV_PROP_FREQ_RANGE:
+ val = freq_range_t(0, 0);
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ val = std::string("");
+ return;
+
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ val = prop_names_t(1, ""); //vector of 1 empty string
+ return;
+
+ case SUBDEV_PROP_QUADRATURE:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_IQ_SWAPPED:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_SPECTRUM_INVERTED:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_USE_LO_OFFSET:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_LO_LOCKED:
+ val = true; //there is no LO, so it must be true!
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void unknown_rx::rx_set(const wax::obj &key_, const wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+
+ case SUBDEV_PROP_GAIN:
+ UHD_ASSERT_THROW(val.as<float>() == float(0));
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ UHD_ASSERT_THROW(val.as<std::string>() == std::string(""));
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ return; // it wont do you much good, but you can set it
+
+ default: UHD_THROW_PROP_SET_ERROR();
+ }
+}
+
+/***********************************************************************
+ * Basic and LF TX dboard
+ **********************************************************************/
+unknown_tx::unknown_tx(ctor_args_t args) : tx_dboard_base(args){
+ /* NOP */
+}
+
+unknown_tx::~unknown_tx(void){
+ /* NOP */
+}
+
+void unknown_tx::tx_get(const wax::obj &key_, wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+ case SUBDEV_PROP_NAME:
+ val = "Unknown - " + get_tx_id().to_pp_string();
+ return;
+
+ case SUBDEV_PROP_OTHERS:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ val = float(0);
+ return;
+
+ case SUBDEV_PROP_GAIN_RANGE:
+ val = gain_range_t(0, 0, 0);
+ return;
+
+ case SUBDEV_PROP_GAIN_NAMES:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ val = double(0);
+ return;
+
+ case SUBDEV_PROP_FREQ_RANGE:
+ val = freq_range_t(0, 0);
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ val = std::string("");
+ return;
+
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ val = prop_names_t(1, ""); //vector of 1 empty string
+ return;
+
+ case SUBDEV_PROP_QUADRATURE:
+ val = true;
+ return;
+
+ case SUBDEV_PROP_IQ_SWAPPED:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_SPECTRUM_INVERTED:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_USE_LO_OFFSET:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_LO_LOCKED:
+ val = true; //there is no LO, so it must be true!
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void unknown_tx::tx_set(const wax::obj &key_, const wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<subdev_prop_t>()){
+
+ case SUBDEV_PROP_GAIN:
+ UHD_ASSERT_THROW(val.as<float>() == float(0));
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ UHD_ASSERT_THROW(val.as<std::string>() == std::string(""));
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ return; // it wont do you much good, but you can set it
+
+ default: UHD_THROW_PROP_SET_ERROR();
+ }
+}
diff --git a/host/lib/usrp/dboard/db_wbx.cpp b/host/lib/usrp/dboard/db_wbx.cpp
index 95dcb3802..2b2822b6b 100644
--- a/host/lib/usrp/dboard/db_wbx.cpp
+++ b/host/lib/usrp/dboard/db_wbx.cpp
@@ -154,8 +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, &make_wbx, "WBX RX");
- dboard_manager::register_dboard(0x0053, &make_wbx, "WBX TX");
+ dboard_manager::register_dboard(0x0052, 0x0053, &make_wbx, "WBX");
}
/***********************************************************************
@@ -246,7 +245,7 @@ void wbx_xcvr::set_tx_gain(float gain, const std::string &name){
_tx_gains[name] = gain;
//write the new voltage to the aux dac
- this->get_iface()->write_aux_dac(dboard_iface::UNIT_TX, 0, dac_volts);
+ this->get_iface()->write_aux_dac(dboard_iface::UNIT_TX, dboard_iface::AUX_DAC_A, dac_volts);
}
else UHD_THROW_INVALID_CODE_PATH();
}
diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp
index 974a378bd..5032b6f31 100644
--- a/host/lib/usrp/dboard/db_xcvr2450.cpp
+++ b/host/lib/usrp/dboard/db_xcvr2450.cpp
@@ -144,7 +144,7 @@ private:
static const float min_v = float(0.5), max_v = float(2.5);
static const float rssi_dyn_range = 60;
//calculate the rssi from the voltage
- float voltage = this->get_iface()->read_aux_adc(dboard_iface::UNIT_RX, 1);
+ float voltage = this->get_iface()->read_aux_adc(dboard_iface::UNIT_RX, dboard_iface::AUX_ADC_B);
return rssi_dyn_range*(voltage - min_v)/(max_v - min_v);
}
};
@@ -158,8 +158,7 @@ static dboard_base::sptr make_xcvr2450(dboard_base::ctor_args_t args){
UHD_STATIC_BLOCK(reg_xcvr2450_dboard){
//register the factory function for the rx and tx dbids
- dboard_manager::register_dboard(0x0060, &make_xcvr2450, "XCVR2450 TX");
- dboard_manager::register_dboard(0x0061, &make_xcvr2450, "XCVR2450 RX");
+ dboard_manager::register_dboard(0x0061, 0x0060, &make_xcvr2450, "XCVR2450");
}
/***********************************************************************
diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp
index 35ddfc4ee..6321e018f 100644
--- a/host/lib/usrp/dboard_manager.cpp
+++ b/host/lib/usrp/dboard_manager.cpp
@@ -43,7 +43,7 @@ typedef uhd::dict<dboard_id_t, args_t> id_to_args_map_t;
UHD_SINGLETON_FCN(id_to_args_map_t, get_id_to_args_map)
void dboard_manager::register_dboard(
- dboard_id_t dboard_id,
+ const dboard_id_t &dboard_id,
dboard_ctor_t dboard_ctor,
const std::string &name,
const prop_names_t &subdev_names
@@ -57,6 +57,26 @@ void dboard_manager::register_dboard(
get_id_to_args_map()[dboard_id] = args_t(dboard_ctor, name, subdev_names);
}
+//map an xcvr dboard id to its partner dboard id
+typedef uhd::dict<dboard_id_t, dboard_id_t> xcvr_id_to_id_map_t;
+UHD_SINGLETON_FCN(xcvr_id_to_id_map_t, get_xcvr_id_to_id_map)
+
+void dboard_manager::register_dboard(
+ const dboard_id_t &rx_dboard_id,
+ const dboard_id_t &tx_dboard_id,
+ dboard_ctor_t dboard_ctor,
+ const std::string &name,
+ const prop_names_t &subdev_names
+){
+ //regular registration for ids
+ register_dboard(rx_dboard_id, dboard_ctor, name + " RX", subdev_names);
+ register_dboard(tx_dboard_id, dboard_ctor, name + " TX", subdev_names);
+
+ //register xcvr mapping for ids
+ get_xcvr_id_to_id_map()[rx_dboard_id] = tx_dboard_id;
+ get_xcvr_id_to_id_map()[tx_dboard_id] = rx_dboard_id;
+}
+
std::string dboard_id_t::to_pp_string(void) const{
std::string name = "unknown";
if (get_id_to_args_map().has_key(*this)){
@@ -168,26 +188,27 @@ dboard_manager::sptr dboard_manager::make(
**********************************************************************/
static args_t get_dboard_args(
dboard_iface::unit_t unit,
- dboard_id_t dboard_id
+ dboard_id_t dboard_id,
+ bool force_to_unknown = false
){
//special case, the none id was provided, use the following ids
- if (dboard_id == dboard_id_t::none()){
+ if (dboard_id == dboard_id_t::none() or force_to_unknown){
std::cerr << boost::format(
- "Warning: unregistered dboard id: %s"
- " -> defaulting to a basic board"
+ "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(0x0001));
- UHD_ASSERT_THROW(get_id_to_args_map().has_key(0x0000));
+ UHD_ASSERT_THROW(get_id_to_args_map().has_key(0xfff1));
+ UHD_ASSERT_THROW(get_id_to_args_map().has_key(0xfff0));
switch(unit){
- case dboard_iface::UNIT_RX: return get_dboard_args(unit, 0x0001);
- case dboard_iface::UNIT_TX: return get_dboard_args(unit, 0x0000);
+ case dboard_iface::UNIT_RX: return get_dboard_args(unit, 0xfff1);
+ case dboard_iface::UNIT_TX: return get_dboard_args(unit, 0xfff0);
default: UHD_THROW_INVALID_CODE_PATH();
}
}
//verify that there is a registered constructor for this id
if (not get_id_to_args_map().has_key(dboard_id)){
- return get_dboard_args(unit, dboard_id_t::none());
+ return get_dboard_args(unit, dboard_id, true);
}
//return the dboard args for this id
@@ -201,11 +222,21 @@ dboard_manager_impl::dboard_manager_impl(
){
_iface = iface;
+ //determine xcvr status
+ bool rx_dboard_is_xcvr = get_xcvr_id_to_id_map().has_key(rx_dboard_id);
+ bool tx_dboard_is_xcvr = get_xcvr_id_to_id_map().has_key(tx_dboard_id);
+ bool this_dboard_is_xcvr = (
+ rx_dboard_is_xcvr and tx_dboard_is_xcvr and
+ (get_xcvr_id_to_id_map()[rx_dboard_id] == tx_dboard_id) and
+ (get_xcvr_id_to_id_map()[tx_dboard_id] == rx_dboard_id)
+ );
+
+ //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);
+ 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);
+ 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();
@@ -215,7 +246,8 @@ dboard_manager_impl::dboard_manager_impl(
db_ctor_args.db_iface = iface;
//make xcvr subdevs (make one subdev for both rx and tx dboards)
- if (rx_dboard_ctor == tx_dboard_ctor){
+ if (this_dboard_is_xcvr){
+ UHD_ASSERT_THROW(rx_dboard_ctor == tx_dboard_ctor);
UHD_ASSERT_THROW(rx_subdevs == tx_subdevs);
BOOST_FOREACH(const std::string &subdev, rx_subdevs){
db_ctor_args.sd_name = subdev;
diff --git a/host/lib/usrp/usrp2/clock_ctrl.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp
index d9baa66cf..b9be037c0 100644
--- a/host/lib/usrp/usrp2/clock_ctrl.cpp
+++ b/host/lib/usrp/usrp2/clock_ctrl.cpp
@@ -18,6 +18,7 @@
#include "clock_ctrl.hpp"
#include "ad9510_regs.hpp"
#include "usrp2_regs.hpp" //spi slave constants
+#include <uhd/utils/assert.hpp>
#include <boost/cstdint.hpp>
using namespace uhd;
@@ -79,23 +80,63 @@ public:
_ad9510_regs.power_down_lvds_cmos_out7 = enb? 0 : 1;
_ad9510_regs.lvds_cmos_select_out7 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT7_CMOS;
_ad9510_regs.output_level_lvds_out7 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT7_1_75MA;
- _ad9510_regs.bypass_divider_out7 = 1;
this->write_reg(0x43);
+ this->update_regs();
+ }
+
+ void set_rate_rx_dboard_clock(double rate){
+ assert_has(get_rates_rx_dboard_clock(), rate, "rx dboard clock rate");
+ size_t divider = size_t(rate/get_master_clock_rate());
+ //bypass when the divider ratio is one
+ _ad9510_regs.bypass_divider_out7 = (divider == 1)? 1 : 0;
+ //calculate the low and high dividers
+ size_t high = divider/2;
+ size_t low = divider - high;
+ //set the registers (divider - 1)
+ _ad9510_regs.divider_low_cycles_out7 = low - 1;
+ _ad9510_regs.divider_high_cycles_out7 = high - 1;
+ //write the registers
+ this->write_reg(0x56);
this->write_reg(0x57);
this->update_regs();
}
+ std::vector<double> get_rates_rx_dboard_clock(void){
+ std::vector<double> rates;
+ for (size_t i = 1; i <= 16+16; i++) rates.push_back(get_master_clock_rate()/i);
+ return rates;
+ }
+
//uses output clock 6 (cmos)
void enable_tx_dboard_clock(bool enb){
_ad9510_regs.power_down_lvds_cmos_out6 = enb? 0 : 1;
_ad9510_regs.lvds_cmos_select_out6 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT6_CMOS;
_ad9510_regs.output_level_lvds_out6 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT6_1_75MA;
- _ad9510_regs.bypass_divider_out6 = 1;
this->write_reg(0x42);
+ this->update_regs();
+ }
+
+ void set_rate_tx_dboard_clock(double rate){
+ assert_has(get_rates_tx_dboard_clock(), rate, "tx dboard clock rate");
+ size_t divider = size_t(rate/get_master_clock_rate());
+ //bypass when the divider ratio is one
+ _ad9510_regs.bypass_divider_out6 = (divider == 1)? 1 : 0;
+ //calculate the low and high dividers
+ size_t high = divider/2;
+ size_t low = divider - high;
+ //set the registers (divider - 1)
+ _ad9510_regs.divider_low_cycles_out6 = low - 1;
+ _ad9510_regs.divider_high_cycles_out6 = high - 1;
+ //write the registers
+ this->write_reg(0x54);
this->write_reg(0x55);
this->update_regs();
}
+ std::vector<double> get_rates_tx_dboard_clock(void){
+ return get_rates_rx_dboard_clock(); //same master clock, same dividers...
+ }
+
/*!
* If we are to use an external reference, enable the charge pump.
* \param enb true to enable the CP
diff --git a/host/lib/usrp/usrp2/clock_ctrl.hpp b/host/lib/usrp/usrp2/clock_ctrl.hpp
index 0ad8d9532..70a104a81 100644
--- a/host/lib/usrp/usrp2/clock_ctrl.hpp
+++ b/host/lib/usrp/usrp2/clock_ctrl.hpp
@@ -21,6 +21,7 @@
#include "usrp2_iface.hpp"
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
+#include <vector>
class usrp2_clock_ctrl : boost::noncopyable{
public:
@@ -46,12 +47,38 @@ public:
virtual void enable_rx_dboard_clock(bool enb) = 0;
/*!
+ * Set the clock rate on the rx dboard clock.
+ * \param rate the new clock rate
+ * \throw exception when rate invalid
+ */
+ virtual void set_rate_rx_dboard_clock(double rate) = 0;
+
+ /*!
+ * Get a list of possible rx dboard clock rates.
+ * \return a list of clock rates in Hz
+ */
+ virtual std::vector<double> get_rates_rx_dboard_clock(void) = 0;
+
+ /*!
* Enable/disable the tx dboard clock.
* \param enb true to enable
*/
virtual void enable_tx_dboard_clock(bool enb) = 0;
/*!
+ * Set the clock rate on the tx dboard clock.
+ * \param rate the new clock rate
+ * \throw exception when rate invalid
+ */
+ virtual void set_rate_tx_dboard_clock(double rate) = 0;
+
+ /*!
+ * Get a list of possible tx dboard clock rates.
+ * \return a list of clock rates in Hz
+ */
+ virtual std::vector<double> get_rates_tx_dboard_clock(void) = 0;
+
+ /*!
* Enable/disable external reference.
* \param enb true to enable
*/
diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp
index 114f83f41..6f2fb9396 100644
--- a/host/lib/usrp/usrp2/dboard_iface.cpp
+++ b/host/lib/usrp/usrp2/dboard_iface.cpp
@@ -21,6 +21,7 @@
#include <uhd/usrp/dboard_iface.hpp>
#include <uhd/types/dict.hpp>
#include <uhd/utils/assert.hpp>
+#include <uhd/utils/algorithm.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/asio.hpp> //htonl and ntohl
#include <boost/math/special_functions/round.hpp>
@@ -36,8 +37,8 @@ public:
usrp2_dboard_iface(usrp2_iface::sptr iface, usrp2_clock_ctrl::sptr clock_ctrl);
~usrp2_dboard_iface(void);
- void write_aux_dac(unit_t, int, float);
- float read_aux_adc(unit_t, int);
+ void write_aux_dac(unit_t, aux_dac_t, float);
+ float read_aux_adc(unit_t, aux_adc_t);
void set_pin_ctrl(unit_t, boost::uint16_t);
void set_atr_reg(unit_t, atr_reg_t, boost::uint16_t);
@@ -48,9 +49,10 @@ public:
void write_i2c(boost::uint8_t, const byte_vector_t &);
byte_vector_t read_i2c(boost::uint8_t, size_t);
+ void set_clock_rate(unit_t, double);
double get_clock_rate(unit_t);
+ std::vector<double> get_clock_rates(unit_t);
void set_clock_enabled(unit_t, bool);
- bool get_clock_enabled(unit_t);
void write_spi(
unit_t unit,
@@ -73,6 +75,7 @@ private:
boost::uint32_t _gpio_shadow;
uhd::dict<unit_t, ad5623_regs_t> _dac_regs;
+ uhd::dict<unit_t, double> _clock_rates;
void _write_aux_dac(unit_t);
};
@@ -107,6 +110,10 @@ usrp2_dboard_iface::usrp2_dboard_iface(
_dac_regs[unit].cmd = ad5623_regs_t::CMD_RESET;
this->_write_aux_dac(unit);
}
+
+ //init the clock rate shadows with max rate clock
+ this->set_clock_rate(UNIT_RX, sorted(this->get_clock_rates(UNIT_RX)).back());
+ this->set_clock_rate(UNIT_TX, sorted(this->get_clock_rates(UNIT_TX)).back());
}
usrp2_dboard_iface::~usrp2_dboard_iface(void){
@@ -116,8 +123,24 @@ usrp2_dboard_iface::~usrp2_dboard_iface(void){
/***********************************************************************
* Clocks
**********************************************************************/
-double usrp2_dboard_iface::get_clock_rate(unit_t){
- return _clock_ctrl->get_master_clock_rate();
+void usrp2_dboard_iface::set_clock_rate(unit_t unit, double rate){
+ _clock_rates[unit] = rate; //set to shadow
+ switch(unit){
+ case UNIT_RX: _clock_ctrl->set_rate_rx_dboard_clock(rate); return;
+ case UNIT_TX: _clock_ctrl->set_rate_tx_dboard_clock(rate); return;
+ }
+}
+
+double usrp2_dboard_iface::get_clock_rate(unit_t unit){
+ return _clock_rates[unit]; //get from shadow
+}
+
+std::vector<double> usrp2_dboard_iface::get_clock_rates(unit_t unit){
+ switch(unit){
+ case UNIT_RX: return _clock_ctrl->get_rates_rx_dboard_clock();
+ case UNIT_TX: return _clock_ctrl->get_rates_tx_dboard_clock();
+ default: UHD_THROW_INVALID_CODE_PATH();
+ }
}
void usrp2_dboard_iface::set_clock_enabled(unit_t unit, bool enb){
@@ -240,31 +263,30 @@ void usrp2_dboard_iface::_write_aux_dac(unit_t unit){
);
}
-void usrp2_dboard_iface::write_aux_dac(unit_t unit, int which, float value){
+void usrp2_dboard_iface::write_aux_dac(unit_t unit, aux_dac_t which, float value){
_dac_regs[unit].data = boost::math::iround(4095*value/3.3);
_dac_regs[unit].cmd = ad5623_regs_t::CMD_WR_UP_DAC_CHAN_N;
- //standardize on USRP1 interface, A=0, B=1, C=2, D=3
- static const uhd::dict<
- unit_t, uhd::dict<int, ad5623_regs_t::addr_t>
- > unit_to_which_to_addr = map_list_of
+
+ typedef uhd::dict<aux_dac_t, ad5623_regs_t::addr_t> aux_dac_to_addr;
+ static const uhd::dict<unit_t, aux_dac_to_addr> unit_to_which_to_addr = map_list_of
(UNIT_RX, map_list_of
- (0, ad5623_regs_t::ADDR_DAC_B)
- (1, ad5623_regs_t::ADDR_DAC_A)
- (2, ad5623_regs_t::ADDR_DAC_A)
- (3, ad5623_regs_t::ADDR_DAC_B)
+ (AUX_DAC_A, ad5623_regs_t::ADDR_DAC_B)
+ (AUX_DAC_B, ad5623_regs_t::ADDR_DAC_A)
+ (AUX_DAC_C, ad5623_regs_t::ADDR_DAC_A)
+ (AUX_DAC_D, ad5623_regs_t::ADDR_DAC_B)
)
(UNIT_TX, map_list_of
- (0, ad5623_regs_t::ADDR_DAC_A)
- (1, ad5623_regs_t::ADDR_DAC_B)
- (2, ad5623_regs_t::ADDR_DAC_B)
- (3, ad5623_regs_t::ADDR_DAC_A)
+ (AUX_DAC_A, ad5623_regs_t::ADDR_DAC_A)
+ (AUX_DAC_B, ad5623_regs_t::ADDR_DAC_B)
+ (AUX_DAC_C, ad5623_regs_t::ADDR_DAC_B)
+ (AUX_DAC_D, ad5623_regs_t::ADDR_DAC_A)
)
;
_dac_regs[unit].addr = unit_to_which_to_addr[unit][which];
this->_write_aux_dac(unit);
}
-float usrp2_dboard_iface::read_aux_adc(unit_t unit, int which){
+float usrp2_dboard_iface::read_aux_adc(unit_t unit, aux_adc_t which){
static const uhd::dict<unit_t, int> unit_to_spi_adc = map_list_of
(UNIT_RX, SPI_SS_RX_ADC)
(UNIT_TX, SPI_SS_TX_ADC)
@@ -277,8 +299,10 @@ float usrp2_dboard_iface::read_aux_adc(unit_t unit, int which){
//setup the spi registers
ad7922_regs_t ad7922_regs;
- ad7922_regs.mod = which; //normal mode: mod == chn
- ad7922_regs.chn = which;
+ switch(which){
+ case AUX_ADC_A: ad7922_regs.mod = 0; break;
+ case AUX_ADC_B: ad7922_regs.mod = 1; break;
+ } ad7922_regs.chn = ad7922_regs.mod; //normal mode: mod == chn
//write and read spi
_iface->transact_spi(
diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h
index 75f5b1779..242d268ec 100644
--- a/host/lib/usrp/usrp2/fw_common.h
+++ b/host/lib/usrp/usrp2/fw_common.h
@@ -32,9 +32,13 @@ extern "C" {
#define _SINS_
#endif
+// define limits on bytes per udp packet
+#define USRP2_MTU_BYTES 1500
+#define USRP2_UDP_BYTES ((USRP2_MTU_BYTES) - (2 + 14 + 20 + 8)) //size of headers (pad, eth, ip, udp)
+
//defines the protocol version in this shared header
//increment this value when the protocol is changed
-#define USRP2_PROTO_VERSION 3
+#define USRP2_PROTO_VERSION 4
//used to differentiate control packets over data port
#define USRP2_INVALID_VRT_HEADER 0
@@ -102,7 +106,7 @@ typedef struct{
struct {
_SINS_ uint8_t addr;
_SINS_ uint8_t bytes;
- _SINS_ uint8_t data[sizeof(_SINS_ uint32_t)];
+ _SINS_ uint8_t data[20];
} i2c_args;
struct {
_SINS_ uint32_t addr;
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index 6cb2a735b..aa0f63321 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -18,6 +18,7 @@
#include "../../transport/vrt_packet_handler.hpp"
#include "usrp2_impl.hpp"
#include "usrp2_regs.hpp"
+#include <uhd/utils/thread_priority.hpp>
#include <uhd/transport/convert_types.hpp>
#include <uhd/transport/bounded_buffer.hpp>
#include <boost/format.hpp>
@@ -78,6 +79,7 @@ managed_recv_buffer::sptr usrp2_impl::io_impl::get_recv_buff(void){
}
void usrp2_impl::io_impl::recv_pirate_loop(zero_copy_if::sptr zc_if){
+ set_thread_priority_safe();
recv_pirate_running = true;
while(recv_pirate_running){
managed_recv_buffer::sptr buff = zc_if->get_recv_buff();
diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp
index 78fc5dc23..2c900b328 100644
--- a/host/lib/usrp/usrp2/mboard_impl.cpp
+++ b/host/lib/usrp/usrp2/mboard_impl.cpp
@@ -84,14 +84,14 @@ void usrp2_impl::update_clock_config(void){
void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){
//set the ticks
- _iface->poke32(U2_REG_TIME64_TICKS, time_spec.get_ticks(get_master_clock_freq()));
+ _iface->poke32(U2_REG_TIME64_TICKS, time_spec.get_tick_count(get_master_clock_freq()));
//set the flags register
boost::uint32_t imm_flags = (now)? U2_FLAG_TIME64_LATCH_NOW : U2_FLAG_TIME64_LATCH_NEXT_PPS;
_iface->poke32(U2_REG_TIME64_IMM, imm_flags);
//set the seconds (latches in all 3 registers)
- _iface->poke32(U2_REG_TIME64_SECS, time_spec.secs);
+ _iface->poke32(U2_REG_TIME64_SECS, boost::uint32_t(time_spec.get_full_secs()));
}
void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){
@@ -118,8 +118,8 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){
(inst_chain)? 1 : 0,
(inst_reload)? 1 : 0
));
- _iface->poke32(U2_REG_RX_CTRL_TIME_SECS, stream_cmd.time_spec.secs);
- _iface->poke32(U2_REG_RX_CTRL_TIME_TICKS, stream_cmd.time_spec.get_ticks(get_master_clock_freq()));
+ _iface->poke32(U2_REG_RX_CTRL_TIME_SECS, boost::uint32_t(stream_cmd.time_spec.get_full_secs()));
+ _iface->poke32(U2_REG_RX_CTRL_TIME_TICKS, stream_cmd.time_spec.get_tick_count(get_master_clock_freq()));
}
/***********************************************************************
diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp
index 6e0d3266a..66a1a57f6 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.cpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.cpp
@@ -146,7 +146,7 @@ public:
_ctrl_transport->send(boost::asio::buffer(&out_copy, sizeof(usrp2_ctrl_data_t)));
//loop until we get the packet or timeout
- boost::uint8_t usrp2_ctrl_data_in_mem[1500]; //allocate MTU bytes for recv
+ boost::uint8_t usrp2_ctrl_data_in_mem[USRP2_UDP_BYTES]; //allocate max bytes for recv
usrp2_ctrl_data_t *ctrl_data_in = reinterpret_cast<usrp2_ctrl_data_t *>(usrp2_ctrl_data_in_mem);
while(true){
size_t len = _ctrl_transport->recv(boost::asio::buffer(usrp2_ctrl_data_in_mem));
@@ -200,7 +200,7 @@ private:
//send and recv
usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data);
UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE);
- return T(ntohl(out_data.data.poke_args.data));
+ return T(ntohl(in_data.data.poke_args.data));
}
};
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index 0837f4ac4..36c264c3c 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -79,12 +79,12 @@ uhd::device_addrs_t usrp2::find(const device_addr_t &hint){
udp_transport->send(boost::asio::buffer(&ctrl_data_out, sizeof(ctrl_data_out)));
//loop and recieve until the timeout
- boost::uint8_t usrp2_ctrl_data_in_mem[1500]; //allocate MTU bytes for recv
+ boost::uint8_t usrp2_ctrl_data_in_mem[USRP2_UDP_BYTES]; //allocate max bytes for recv
usrp2_ctrl_data_t *ctrl_data_in = reinterpret_cast<usrp2_ctrl_data_t *>(usrp2_ctrl_data_in_mem);
while(true){
size_t len = udp_transport->recv(asio::buffer(usrp2_ctrl_data_in_mem));
//std::cout << len << "\n";
- if (len >= sizeof(usrp2_ctrl_data_t)){
+ if (len > offsetof(usrp2_ctrl_data_t, data)){
//handle the received data
switch(ntohl(ctrl_data_in->id)){
case USRP2_CTRL_ID_WAZZUP_DUDE:
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
index ccc09003e..2126b9565 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -141,15 +141,13 @@ private:
/*******************************************************************
* Deal with the rx and tx packet sizes
******************************************************************/
- static const size_t _mtu = 1500; //FIXME we have no idea
- static const size_t _hdrs = (2 + 14 + 20 + 8); //size of headers (pad, eth, ip, udp)
static const size_t _max_rx_bytes_per_packet =
- _mtu - _hdrs -
+ USRP2_UDP_BYTES -
USRP2_HOST_RX_VRT_HEADER_WORDS32*sizeof(boost::uint32_t) -
USRP2_HOST_RX_VRT_TRAILER_WORDS32*sizeof(boost::uint32_t)
;
static const size_t _max_tx_bytes_per_packet =
- _mtu - _hdrs -
+ USRP2_UDP_BYTES -
uhd::transport::vrt::max_header_words32*sizeof(boost::uint32_t)
;
diff --git a/host/test/vrt_test.cpp b/host/test/vrt_test.cpp
index 3e596164c..3776e33aa 100644
--- a/host/test/vrt_test.cpp
+++ b/host/test/vrt_test.cpp
@@ -66,8 +66,8 @@ static void pack_and_unpack(
}
BOOST_CHECK_EQUAL(metadata.has_time_spec, metadata_out.has_time_spec);
if (metadata.has_time_spec and metadata_out.has_time_spec){
- BOOST_CHECK_EQUAL(metadata.time_spec.secs, metadata_out.time_spec.secs);
- BOOST_CHECK_EQUAL(metadata.time_spec.nsecs, metadata_out.time_spec.nsecs);
+ BOOST_CHECK_EQUAL(metadata.time_spec.get_full_secs(), metadata_out.time_spec.get_full_secs());
+ BOOST_CHECK_EQUAL(metadata.time_spec.get_frac_secs(), metadata_out.time_spec.get_frac_secs());
}
}
@@ -86,8 +86,7 @@ BOOST_AUTO_TEST_CASE(test_with_sid){
BOOST_AUTO_TEST_CASE(test_with_time_spec){
uhd::tx_metadata_t metadata;
metadata.has_time_spec = true;
- metadata.time_spec.secs = 7;
- metadata.time_spec.nsecs = 2000;
+ metadata.time_spec = uhd::time_spec_t(7, 0.2);
pack_and_unpack(metadata, 500, 3);
}
@@ -96,7 +95,6 @@ BOOST_AUTO_TEST_CASE(test_with_sid_and_time_spec){
metadata.has_stream_id = true;
metadata.stream_id = 2;
metadata.has_time_spec = true;
- metadata.time_spec.secs = 5;
- metadata.time_spec.nsecs = 1000;
+ metadata.time_spec = uhd::time_spec_t(5, 0.1);
pack_and_unpack(metadata, 600, 4);
}
diff --git a/host/utils/uhd_burn_db_eeprom.cpp b/host/utils/uhd_burn_db_eeprom.cpp
index dfd9decba..ba7aa6cec 100644
--- a/host/utils/uhd_burn_db_eeprom.cpp
+++ b/host/utils/uhd_burn_db_eeprom.cpp
@@ -32,16 +32,6 @@ using namespace uhd;
using namespace uhd::usrp;
namespace po = boost::program_options;
-//used with lexical cast to parse a hex string
-template <class T> struct to_hex{
- T value;
- operator T() const {return value;}
- friend std::istream& operator>>(std::istream& in, to_hex& out){
- in >> std::hex >> out.value;
- return in;
- }
-};
-
int UHD_SAFE_MAIN(int argc, char *argv[]){
//command line variables
std::string args, db_name, unit;
@@ -55,7 +45,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]")
("db", po::value<std::string>(&db_name)->default_value(""), "dboard name [default = \"\"]")
("unit", po::value<std::string>(&unit)->default_value(""), "which unit [RX or TX]")
- ("id", po::value<std::string>(), "dboard id to burn (hex string), omit for readback")
+ ("id", po::value<std::string>(), "dboard id to burn, omit for readback")
;
po::variables_map vm;