aboutsummaryrefslogtreecommitdiffstats
path: root/host/tests
diff options
context:
space:
mode:
Diffstat (limited to 'host/tests')
-rw-r--r--host/tests/CMakeLists.txt57
-rw-r--r--host/tests/addr_test.cpp81
-rw-r--r--host/tests/buffer_test.cpp64
-rw-r--r--host/tests/byteswap_test.cpp39
-rw-r--r--host/tests/convert_test.cpp343
-rw-r--r--host/tests/dict_test.cpp72
-rw-r--r--host/tests/error_test.cpp93
-rw-r--r--host/tests/gain_group_test.cpp122
-rw-r--r--host/tests/module_test.cpp26
-rw-r--r--host/tests/msg_test.cpp40
-rw-r--r--host/tests/property_test.cpp175
-rw-r--r--host/tests/ranges_test.cpp70
-rw-r--r--host/tests/sph_recv_test.cpp707
-rw-r--r--host/tests/sph_send_test.cpp198
-rw-r--r--host/tests/subdev_spec_test.cpp45
-rw-r--r--host/tests/time_spec_test.cpp99
-rw-r--r--host/tests/vrt_test.cpp141
17 files changed, 2372 insertions, 0 deletions
diff --git a/host/tests/CMakeLists.txt b/host/tests/CMakeLists.txt
new file mode 100644
index 000000000..67e99941b
--- /dev/null
+++ b/host/tests/CMakeLists.txt
@@ -0,0 +1,57 @@
+#
+# Copyright 2010-2011 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/>.
+#
+
+########################################################################
+# unit test suite
+########################################################################
+SET(test_sources
+ addr_test.cpp
+ buffer_test.cpp
+ byteswap_test.cpp
+ convert_test.cpp
+ dict_test.cpp
+ error_test.cpp
+ gain_group_test.cpp
+ msg_test.cpp
+ property_test.cpp
+ ranges_test.cpp
+ sph_recv_test.cpp
+ sph_send_test.cpp
+ subdev_spec_test.cpp
+ time_spec_test.cpp
+ vrt_test.cpp
+)
+
+#turn each test cpp file into an executable with an int main() function
+ADD_DEFINITIONS(-DBOOST_TEST_DYN_LINK -DBOOST_TEST_MAIN)
+
+#for each source: build an executable, register it as a test, and install
+FOREACH(test_source ${test_sources})
+ GET_FILENAME_COMPONENT(test_name ${test_source} NAME_WE)
+ ADD_EXECUTABLE(${test_name} ${test_source})
+ TARGET_LINK_LIBRARIES(${test_name} uhd)
+ ADD_TEST(${test_name} ${test_name})
+ INSTALL(TARGETS ${test_name} RUNTIME DESTINATION ${PKG_LIB_DIR}/tests COMPONENT tests)
+ENDFOREACH(test_source)
+
+########################################################################
+# demo of a loadable module
+########################################################################
+IF(MSVC OR APPLE OR LINUX)
+ ADD_LIBRARY(module_test MODULE module_test.cpp)
+ TARGET_LINK_LIBRARIES(module_test uhd)
+ENDIF()
diff --git a/host/tests/addr_test.cpp b/host/tests/addr_test.cpp
new file mode 100644
index 000000000..cea2f224c
--- /dev/null
+++ b/host/tests/addr_test.cpp
@@ -0,0 +1,81 @@
+//
+// Copyright 2010-2011 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 <boost/test/unit_test.hpp>
+#include <uhd/types/mac_addr.hpp>
+#include <uhd/types/device_addr.hpp>
+#include <uhd/usrp/dboard_id.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/foreach.hpp>
+#include <algorithm>
+#include <iostream>
+
+BOOST_AUTO_TEST_CASE(test_mac_addr){
+ std::cout << "Testing mac addr..." << std::endl;
+ const std::string mac_addr_str("00:01:23:45:67:89");
+ uhd::mac_addr_t mac_addr = uhd::mac_addr_t::from_string(mac_addr_str);
+ std::cout << "Input: " << mac_addr_str << std::endl;
+ std::cout << "Output: " << mac_addr.to_string() << std::endl;
+ BOOST_CHECK_EQUAL(mac_addr_str, mac_addr.to_string());
+}
+
+BOOST_AUTO_TEST_CASE(test_device_addr){
+ std::cout << "Testing device addr..." << std::endl;
+
+ //load the device address with something
+ uhd::device_addr_t dev_addr;
+ dev_addr["key1"] = "val1";
+ dev_addr["key1"] = "val1";
+ dev_addr["key3"] = "";
+
+ //convert to and from args string
+ std::cout << "Pretty Print: " << std::endl << dev_addr.to_pp_string();
+ std::string args_str = dev_addr.to_string();
+ std::cout << "Args String: " << args_str << std::endl;
+ uhd::device_addr_t new_dev_addr(args_str);
+
+ //they should be the same size
+ BOOST_REQUIRE_EQUAL(dev_addr.size(), new_dev_addr.size());
+
+ //the keys should match
+ std::vector<std::string> old_dev_addr_keys = dev_addr.keys();
+ std::vector<std::string> new_dev_addr_keys = new_dev_addr.keys();
+ BOOST_CHECK_EQUAL_COLLECTIONS(
+ old_dev_addr_keys.begin(), old_dev_addr_keys.end(),
+ new_dev_addr_keys.begin(), new_dev_addr_keys.end()
+ );
+
+ //the vals should match
+ std::vector<std::string> old_dev_addr_vals = dev_addr.vals();
+ std::vector<std::string> new_dev_addr_vals = new_dev_addr.vals();
+ BOOST_CHECK_EQUAL_COLLECTIONS(
+ old_dev_addr_vals.begin(), old_dev_addr_vals.end(),
+ new_dev_addr_vals.begin(), new_dev_addr_vals.end()
+ );
+}
+
+BOOST_AUTO_TEST_CASE(test_dboard_id){
+ std::cout << "Testing dboard id..." << std::endl;
+
+ using namespace uhd::usrp;
+
+ BOOST_CHECK(dboard_id_t() == dboard_id_t::none());
+ BOOST_CHECK_EQUAL(dboard_id_t().to_uint16(), dboard_id_t::none().to_uint16());
+ BOOST_CHECK_EQUAL(dboard_id_t::from_string("0x1234").to_uint16(), 0x1234);
+ BOOST_CHECK_EQUAL(dboard_id_t::from_string("1234").to_uint16(), 1234);
+ std::cout << "Pretty Print: " << std::endl << dboard_id_t::none().to_pp_string();
+}
diff --git a/host/tests/buffer_test.cpp b/host/tests/buffer_test.cpp
new file mode 100644
index 000000000..23b52a9bf
--- /dev/null
+++ b/host/tests/buffer_test.cpp
@@ -0,0 +1,64 @@
+//
+// Copyright 2010-2011 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 <boost/test/unit_test.hpp>
+#include <uhd/transport/bounded_buffer.hpp>
+#include <boost/assign/list_of.hpp>
+
+using namespace boost::assign;
+using namespace uhd::transport;
+
+static const double timeout = 0.01/*secs*/;
+
+BOOST_AUTO_TEST_CASE(test_bounded_buffer_with_timed_wait){
+ bounded_buffer<int> bb(3);
+
+ //push elements, check for timeout
+ BOOST_CHECK(bb.push_with_timed_wait(0, timeout));
+ BOOST_CHECK(bb.push_with_timed_wait(1, timeout));
+ BOOST_CHECK(bb.push_with_timed_wait(2, timeout));
+ BOOST_CHECK(not bb.push_with_timed_wait(3, timeout));
+
+ int val;
+ //pop elements, check for timeout and check values
+ BOOST_CHECK(bb.pop_with_timed_wait(val, timeout));
+ BOOST_CHECK_EQUAL(val, 0);
+ BOOST_CHECK(bb.pop_with_timed_wait(val, timeout));
+ BOOST_CHECK_EQUAL(val, 1);
+ BOOST_CHECK(bb.pop_with_timed_wait(val, timeout));
+ BOOST_CHECK_EQUAL(val, 2);
+ BOOST_CHECK(not bb.pop_with_timed_wait(val, timeout));
+}
+
+BOOST_AUTO_TEST_CASE(test_bounded_buffer_with_pop_on_full){
+ bounded_buffer<int> bb(3);
+
+ //push elements, check for timeout
+ BOOST_CHECK(bb.push_with_pop_on_full(0));
+ BOOST_CHECK(bb.push_with_pop_on_full(1));
+ BOOST_CHECK(bb.push_with_pop_on_full(2));
+ BOOST_CHECK(not bb.push_with_pop_on_full(3));
+
+ int val;
+ //pop elements, check for timeout and check values
+ BOOST_CHECK(bb.pop_with_timed_wait(val, timeout));
+ BOOST_CHECK_EQUAL(val, 1);
+ BOOST_CHECK(bb.pop_with_timed_wait(val, timeout));
+ BOOST_CHECK_EQUAL(val, 2);
+ BOOST_CHECK(bb.pop_with_timed_wait(val, timeout));
+ BOOST_CHECK_EQUAL(val, 3);
+}
diff --git a/host/tests/byteswap_test.cpp b/host/tests/byteswap_test.cpp
new file mode 100644
index 000000000..7d94bbfba
--- /dev/null
+++ b/host/tests/byteswap_test.cpp
@@ -0,0 +1,39 @@
+//
+// Copyright 2010-2011 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 <boost/test/unit_test.hpp>
+#include <uhd/utils/byteswap.hpp>
+
+BOOST_AUTO_TEST_CASE(test_byteswap16){
+ boost::uint16_t x = 0x0123;
+ boost::uint16_t y = 0x2301;
+ BOOST_CHECK_EQUAL(uhd::byteswap(x), y);
+}
+
+BOOST_AUTO_TEST_CASE(test_byteswap32){
+ boost::uint32_t x = 0x01234567;
+ boost::uint32_t y = 0x67452301;
+ BOOST_CHECK_EQUAL(uhd::byteswap(x), y);
+}
+
+BOOST_AUTO_TEST_CASE(test_byteswap64){
+ //split up 64 bit constants to avoid long-long compiler warnings
+ boost::uint64_t x = 0x01234567 | (boost::uint64_t(0x89abcdef) << 32);
+ boost::uint64_t y = 0xefcdab89 | (boost::uint64_t(0x67452301) << 32);
+ BOOST_CHECK_EQUAL(uhd::byteswap(x), y);
+}
+
diff --git a/host/tests/convert_test.cpp b/host/tests/convert_test.cpp
new file mode 100644
index 000000000..6b0ae53a9
--- /dev/null
+++ b/host/tests/convert_test.cpp
@@ -0,0 +1,343 @@
+//
+// Copyright 2011-2012 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/convert.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/foreach.hpp>
+#include <boost/cstdint.hpp>
+#include <complex>
+#include <vector>
+#include <cstdlib>
+#include <iostream>
+
+using namespace uhd;
+
+//typedefs for complex types
+typedef std::complex<boost::int16_t> sc16_t;
+typedef std::complex<float> fc32_t;
+typedef std::complex<double> fc64_t;
+
+#define MY_CHECK_CLOSE(a, b, f) { \
+ BOOST_CHECK_MESSAGE(std::abs((a)-(b)) < f, "\n\t" << #a << " (" << (a) << ") error " << #b << " (" << (b) << ")"); \
+}
+
+/***********************************************************************
+ * Loopback runner:
+ * convert input buffer into intermediate buffer
+ * convert intermediate buffer into output buffer
+ **********************************************************************/
+template <typename Range> static void loopback(
+ size_t nsamps,
+ convert::id_type &in_id,
+ convert::id_type &out_id,
+ const Range &input,
+ Range &output
+){
+ //item32 is largest device type
+ std::vector<boost::uint32_t> interm(nsamps);
+
+ std::vector<const void *> input0(1, &input[0]), input1(1, &interm[0]);
+ std::vector<void *> output0(1, &interm[0]), output1(1, &output[0]);
+
+ //convert to intermediate type
+ convert::converter::sptr c0 = convert::get_converter(in_id)();
+ c0->set_scalar(32767.);
+ c0->conv(input0, output0, nsamps);
+
+ //convert back to host type
+ convert::converter::sptr c1 = convert::get_converter(out_id)();
+ c1->set_scalar(1/32767.);
+ c1->conv(input1, output1, nsamps);
+}
+
+/***********************************************************************
+ * Test short conversion
+ **********************************************************************/
+static void test_convert_types_sc16(
+ size_t nsamps, convert::id_type &id, const int extra_div = 1
+){
+ //fill the input samples
+ std::vector<sc16_t> input(nsamps), output(nsamps);
+ BOOST_FOREACH(sc16_t &in, input) in = sc16_t(
+ short(((std::rand()/double(RAND_MAX/2)) - 1)*32767/extra_div),
+ short(((std::rand()/double(RAND_MAX/2)) - 1)*32767/extra_div)
+ );
+
+ //run the loopback and test
+ convert::id_type in_id = id;
+ convert::id_type out_id = id;
+ std::swap(out_id.input_format, out_id.output_format);
+ std::swap(out_id.num_inputs, out_id.num_outputs);
+ loopback(nsamps, in_id, out_id, input, output);
+ BOOST_CHECK_EQUAL_COLLECTIONS(input.begin(), input.end(), output.begin(), output.end());
+}
+
+BOOST_AUTO_TEST_CASE(test_convert_types_be_sc16){
+ convert::id_type id;
+ id.input_format = "sc16";
+ id.num_inputs = 1;
+ id.output_format = "sc16_item32_be";
+ id.num_outputs = 1;
+
+ //try various lengths to test edge cases
+ for (size_t nsamps = 1; nsamps < 16; nsamps++){
+ test_convert_types_sc16(nsamps, id);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_convert_types_le_sc16){
+ convert::id_type id;
+ id.input_format = "sc16";
+ id.num_inputs = 1;
+ id.output_format = "sc16_item32_le";
+ id.num_outputs = 1;
+
+ //try various lengths to test edge cases
+ for (size_t nsamps = 1; nsamps < 16; nsamps++){
+ test_convert_types_sc16(nsamps, id);
+ }
+}
+
+/***********************************************************************
+ * Test float conversion
+ **********************************************************************/
+template <typename data_type>
+static void test_convert_types_for_floats(
+ size_t nsamps, convert::id_type &id, const double extra_scale = 1.0
+){
+ typedef typename data_type::value_type value_type;
+
+ //fill the input samples
+ std::vector<data_type> input(nsamps), output(nsamps);
+ BOOST_FOREACH(data_type &in, input) in = data_type(
+ ((std::rand()/value_type(RAND_MAX/2)) - 1)*float(extra_scale),
+ ((std::rand()/value_type(RAND_MAX/2)) - 1)*float(extra_scale)
+ );
+
+ //run the loopback and test
+ convert::id_type in_id = id;
+ convert::id_type out_id = id;
+ std::swap(out_id.input_format, out_id.output_format);
+ std::swap(out_id.num_inputs, out_id.num_outputs);
+ loopback(nsamps, in_id, out_id, input, output);
+ for (size_t i = 0; i < nsamps; i++){
+ MY_CHECK_CLOSE(input[i].real(), output[i].real(), value_type(1./32767));
+ MY_CHECK_CLOSE(input[i].imag(), output[i].imag(), value_type(1./32767));
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_convert_types_be_fc32){
+ convert::id_type id;
+ id.input_format = "fc32";
+ id.num_inputs = 1;
+ id.output_format = "sc16_item32_be";
+ id.num_outputs = 1;
+
+ //try various lengths to test edge cases
+ for (size_t nsamps = 1; nsamps < 16; nsamps++){
+ test_convert_types_for_floats<fc32_t>(nsamps, id);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_convert_types_le_fc32){
+ convert::id_type id;
+ id.input_format = "fc32";
+ id.num_inputs = 1;
+ id.output_format = "sc16_item32_le";
+ id.num_outputs = 1;
+
+ //try various lengths to test edge cases
+ for (size_t nsamps = 1; nsamps < 16; nsamps++){
+ test_convert_types_for_floats<fc32_t>(nsamps, id);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_convert_types_be_fc64){
+ convert::id_type id;
+ id.input_format = "fc64";
+ id.num_inputs = 1;
+ id.output_format = "sc16_item32_be";
+ id.num_outputs = 1;
+
+ //try various lengths to test edge cases
+ for (size_t nsamps = 1; nsamps < 16; nsamps++){
+ test_convert_types_for_floats<fc64_t>(nsamps, id);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_convert_types_le_fc64){
+ convert::id_type id;
+ id.input_format = "fc64";
+ id.num_inputs = 1;
+ id.output_format = "sc16_item32_le";
+ id.num_outputs = 1;
+
+ //try various lengths to test edge cases
+ for (size_t nsamps = 1; nsamps < 16; nsamps++){
+ test_convert_types_for_floats<fc64_t>(nsamps, id);
+ }
+}
+
+/***********************************************************************
+ * Test float to short conversion loopback
+ **********************************************************************/
+BOOST_AUTO_TEST_CASE(test_convert_types_fc32_to_sc16){
+ convert::id_type in_id;
+ in_id.input_format = "fc32";
+ in_id.num_inputs = 1;
+ in_id.output_format = "sc16_item32_le";
+ in_id.num_outputs = 1;
+
+ convert::id_type out_id;
+ out_id.input_format = "sc16_item32_le";
+ out_id.num_inputs = 1;
+ out_id.output_format = "sc16";
+ out_id.num_outputs = 1;
+
+ const size_t nsamps = 13;
+ std::vector<fc32_t> input(nsamps);
+ BOOST_FOREACH(fc32_t &in, input) in = fc32_t(
+ (std::rand()/float(RAND_MAX/2)) - 1,
+ (std::rand()/float(RAND_MAX/2)) - 1
+ );
+ std::vector<boost::uint32_t> interm(nsamps);
+ std::vector<sc16_t> output(nsamps);
+
+ std::vector<const void *> input0(1, &input[0]), input1(1, &interm[0]);
+ std::vector<void *> output0(1, &interm[0]), output1(1, &output[0]);
+
+ //convert float to intermediate
+ convert::converter::sptr c0 = convert::get_converter(in_id)();
+ c0->set_scalar(32767.);
+ c0->conv(input0, output0, nsamps);
+
+ //convert intermediate to short
+ convert::converter::sptr c1 = convert::get_converter(out_id)();
+ c1->set_scalar(1/32767.);
+ c1->conv(input1, output1, nsamps);
+
+ //test that the inputs and outputs match
+ for (size_t i = 0; i < nsamps; i++){
+ MY_CHECK_CLOSE(input[i].real(), output[i].real()/float(32767), float(0.01));
+ MY_CHECK_CLOSE(input[i].imag(), output[i].imag()/float(32767), float(0.01));
+ }
+}
+
+/***********************************************************************
+ * Test short to float conversion loopback
+ **********************************************************************/
+BOOST_AUTO_TEST_CASE(test_convert_types_sc16_to_fc32){
+ convert::id_type in_id;
+ in_id.input_format = "sc16";
+ in_id.num_inputs = 1;
+ in_id.output_format = "sc16_item32_le";
+ in_id.num_outputs = 1;
+
+ convert::id_type out_id;
+ out_id.input_format = "sc16_item32_le";
+ out_id.num_inputs = 1;
+ out_id.output_format = "fc32";
+ out_id.num_outputs = 1;
+
+ const size_t nsamps = 13;
+ std::vector<sc16_t> input(nsamps);
+ BOOST_FOREACH(sc16_t &in, input) in = sc16_t(
+ std::rand()-(RAND_MAX/2),
+ std::rand()-(RAND_MAX/2)
+ );
+ std::vector<boost::uint32_t> interm(nsamps);
+ std::vector<fc32_t> output(nsamps);
+
+ std::vector<const void *> input0(1, &input[0]), input1(1, &interm[0]);
+ std::vector<void *> output0(1, &interm[0]), output1(1, &output[0]);
+
+ //convert short to intermediate
+ convert::converter::sptr c0 = convert::get_converter(in_id)();
+ c0->set_scalar(32767.);
+ c0->conv(input0, output0, nsamps);
+
+ //convert intermediate to float
+ convert::converter::sptr c1 = convert::get_converter(out_id)();
+ c1->set_scalar(1/32767.);
+ c1->conv(input1, output1, nsamps);
+
+ //test that the inputs and outputs match
+ for (size_t i = 0; i < nsamps; i++){
+ MY_CHECK_CLOSE(input[i].real()/float(32767), output[i].real(), float(0.01));
+ MY_CHECK_CLOSE(input[i].imag()/float(32767), output[i].imag(), float(0.01));
+ }
+}
+
+/***********************************************************************
+ * Test sc8 conversions
+ **********************************************************************/
+BOOST_AUTO_TEST_CASE(test_convert_types_fc64_and_sc8){
+ convert::id_type id;
+ id.input_format = "fc64";
+ id.num_inputs = 1;
+ id.num_outputs = 1;
+
+ //try various lengths to test edge cases
+ id.output_format = "sc8_item32_le";
+ for (size_t nsamps = 1; nsamps < 16; nsamps++){
+ test_convert_types_for_floats<fc64_t>(nsamps, id, 1./256);
+ }
+
+ //try various lengths to test edge cases
+ id.output_format = "sc8_item32_be";
+ for (size_t nsamps = 1; nsamps < 16; nsamps++){
+ test_convert_types_for_floats<fc64_t>(nsamps, id, 1./256);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_convert_types_fc32_and_sc8){
+ convert::id_type id;
+ id.input_format = "fc32";
+ id.num_inputs = 1;
+ id.num_outputs = 1;
+
+ //try various lengths to test edge cases
+ id.output_format = "sc8_item32_le";
+ for (size_t nsamps = 1; nsamps < 16; nsamps++){
+ test_convert_types_for_floats<fc32_t>(nsamps, id, 1./256);
+ }
+
+ //try various lengths to test edge cases
+ id.output_format = "sc8_item32_be";
+ for (size_t nsamps = 1; nsamps < 16; nsamps++){
+ test_convert_types_for_floats<fc32_t>(nsamps, id, 1./256);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_convert_types_sc16_and_sc8){
+ convert::id_type id;
+ id.input_format = "sc16";
+ id.num_inputs = 1;
+ id.num_outputs = 1;
+
+ //try various lengths to test edge cases
+ id.output_format = "sc8_item32_le";
+ for (size_t nsamps = 1; nsamps < 16; nsamps++){
+ test_convert_types_sc16(nsamps, id, 256);
+ }
+
+ //try various lengths to test edge cases
+ id.output_format = "sc8_item32_be";
+ for (size_t nsamps = 1; nsamps < 16; nsamps++){
+ test_convert_types_sc16(nsamps, id, 256);
+ }
+}
diff --git a/host/tests/dict_test.cpp b/host/tests/dict_test.cpp
new file mode 100644
index 000000000..7b388d090
--- /dev/null
+++ b/host/tests/dict_test.cpp
@@ -0,0 +1,72 @@
+//
+// Copyright 2010-2011 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 <boost/test/unit_test.hpp>
+#include <uhd/types/dict.hpp>
+#include <boost/assign/list_of.hpp>
+
+BOOST_AUTO_TEST_CASE(test_dict_init){
+ uhd::dict<int, int> d;
+ d[-1] = 3;
+ d[0] = 4;
+ d[1] = 5;
+ BOOST_CHECK(d.has_key(0));
+ BOOST_CHECK(not d.has_key(2));
+ BOOST_CHECK(d.keys()[1] == 0);
+ BOOST_CHECK(d.vals()[1] == 4);
+ BOOST_CHECK_EQUAL(d[-1], 3);
+}
+
+BOOST_AUTO_TEST_CASE(test_dict_assign){
+ uhd::dict<int, int> d = boost::assign::map_list_of
+ (-1, 3)
+ (0, 4)
+ (1, 5)
+ ;
+ BOOST_CHECK(d.has_key(0));
+ BOOST_CHECK(not d.has_key(2));
+ BOOST_CHECK(d.keys()[1] == 0);
+ BOOST_CHECK(d.vals()[1] == 4);
+ BOOST_CHECK_EQUAL(d[-1], 3);
+}
+
+BOOST_AUTO_TEST_CASE(test_const_dict){
+ const uhd::dict<int, int> d = boost::assign::map_list_of
+ (-1, 3)
+ (0, 4)
+ (1, 5)
+ ;
+ BOOST_CHECK(d.has_key(0));
+ BOOST_CHECK(not d.has_key(2));
+ BOOST_CHECK(d.keys()[1] == 0);
+ BOOST_CHECK(d.vals()[1] == 4);
+ BOOST_CHECK_EQUAL(d[-1], 3);
+ BOOST_CHECK_THROW(d[2], std::exception);
+}
+
+BOOST_AUTO_TEST_CASE(test_dict_pop){
+ uhd::dict<int, int> d = boost::assign::map_list_of
+ (-1, 3)
+ (0, 4)
+ (1, 5)
+ ;
+ BOOST_CHECK(d.has_key(0));
+ BOOST_CHECK_EQUAL(d.pop(0), 4);
+ BOOST_CHECK(not d.has_key(0));
+ BOOST_CHECK(d.keys()[0] == -1);
+ BOOST_CHECK(d.keys()[1] == 1);
+}
diff --git a/host/tests/error_test.cpp b/host/tests/error_test.cpp
new file mode 100644
index 000000000..3d784b1f7
--- /dev/null
+++ b/host/tests/error_test.cpp
@@ -0,0 +1,93 @@
+//
+// Copyright 2010-2011 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 <boost/test/unit_test.hpp>
+#include <uhd/exception.hpp>
+#include <uhd/utils/assert_has.hpp>
+#include <vector>
+#include <iostream>
+
+BOOST_AUTO_TEST_CASE(test_exception_methods){
+ try{
+ throw uhd::assertion_error("your assertion failed: 1 != 2");
+ }
+ catch(const uhd::exception &e){
+ std::cout << "what: " << e.what() << std::endl;
+ std::cout << "code: " << e.code() << std::endl;
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_assert_has){
+ std::vector<int> vec;
+ vec.push_back(2);
+ vec.push_back(3);
+ vec.push_back(5);
+
+ //verify the uhd::has utility
+ BOOST_CHECK(uhd::has(vec, 2));
+ BOOST_CHECK(not uhd::has(vec, 1));
+
+ std::cout << "The output of the assert_has error:" << std::endl;
+ try{
+ uhd::assert_has(vec, 1, "prime");
+ }
+ catch(const std::exception &e){
+ std::cout << e.what() << std::endl;
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_assert_throw){
+ std::cout << "The output of the assert throw error:" << std::endl;
+ try{
+ UHD_ASSERT_THROW(2 + 2 == 5);
+ }
+ catch(const std::exception &e){
+ std::cout << e.what() << std::endl;
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_exception_dynamic){
+ uhd::exception *exception_clone;
+
+ //throw an exception and dynamically clone it
+ try{
+ throw uhd::runtime_error("noooooo");
+ }
+ catch(const uhd::exception &e){
+ std::cout << e.what() << std::endl;
+ exception_clone = e.dynamic_clone();
+ }
+
+ //now we dynamically re-throw the exception
+ try{
+ exception_clone->dynamic_throw();
+ }
+ catch(const uhd::assertion_error &e){
+ std::cout << e.what() << std::endl;
+ BOOST_CHECK(false);
+ }
+ catch(const uhd::runtime_error &e){
+ std::cout << e.what() << std::endl;
+ BOOST_CHECK(true);
+ }
+ catch(const uhd::exception &e){
+ std::cout << e.what() << std::endl;
+ BOOST_CHECK(false);
+ }
+
+ delete exception_clone; //manual cleanup
+}
diff --git a/host/tests/gain_group_test.cpp b/host/tests/gain_group_test.cpp
new file mode 100644
index 000000000..07eaf146e
--- /dev/null
+++ b/host/tests/gain_group_test.cpp
@@ -0,0 +1,122 @@
+//
+// Copyright 2010-2011 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 <boost/test/unit_test.hpp>
+#include <uhd/utils/gain_group.hpp>
+#include <boost/bind.hpp>
+#include <boost/math/special_functions/round.hpp>
+#include <iostream>
+
+#define rint(x) boost::math::iround(x)
+
+using namespace uhd;
+
+/***********************************************************************
+ * Define gain element classes with needed functions
+ **********************************************************************/
+class gain_element1{
+public:
+
+ gain_range_t get_range(void){
+ return gain_range_t(0, 90, 1);
+ }
+
+ double get_value(void){
+ return _gain;
+ }
+
+ void set_value(double gain){
+ double step = get_range().step();
+ _gain = step*rint(gain/step);
+ }
+
+private:
+ double _gain;
+};
+
+class gain_element2{
+public:
+
+ gain_range_t get_range(void){
+ return gain_range_t(-20, 10, 0.1);
+ }
+
+ double get_value(void){
+ return _gain;
+ }
+
+ void set_value(double gain){
+ double step = get_range().step();
+ _gain = step*rint(gain/step);
+ }
+
+private:
+ double _gain;
+};
+
+//create static instances of gain elements to be shared by the tests
+static gain_element1 g1;
+static gain_element2 g2;
+
+static gain_group::sptr get_gain_group(size_t pri1 = 0, size_t pri2 = 0){
+ //create instance of gain group
+ gain_fcns_t gain_fcns;
+ gain_group::sptr gg(gain_group::make());
+
+ //load gain group with function sets
+ gain_fcns.get_range = boost::bind(&gain_element1::get_range, &g1);
+ gain_fcns.get_value = boost::bind(&gain_element1::get_value, &g1);
+ gain_fcns.set_value = boost::bind(&gain_element1::set_value, &g1, _1);
+ gg->register_fcns("g1", gain_fcns, pri1);
+
+ gain_fcns.get_range = boost::bind(&gain_element2::get_range, &g2);
+ gain_fcns.get_value = boost::bind(&gain_element2::get_value, &g2);
+ gain_fcns.set_value = boost::bind(&gain_element2::set_value, &g2, _1);
+ gg->register_fcns("g2", gain_fcns, pri2);
+
+ return gg;
+}
+
+/***********************************************************************
+ * Test cases
+ **********************************************************************/
+static const double tolerance = 0.001;
+
+BOOST_AUTO_TEST_CASE(test_gain_group_overall){
+ gain_group::sptr gg = get_gain_group();
+
+ //test the overall stuff
+ gg->set_value(80);
+ BOOST_CHECK_CLOSE(gg->get_value(), 80.0, tolerance);
+ BOOST_CHECK_CLOSE(gg->get_range().start(), -20.0, tolerance);
+ BOOST_CHECK_CLOSE(gg->get_range().stop(), 100.0, tolerance);
+ BOOST_CHECK_CLOSE(gg->get_range().step(), 0.1, tolerance);
+}
+
+BOOST_AUTO_TEST_CASE(test_gain_group_priority){
+ gain_group::sptr gg = get_gain_group(0, 1);
+
+ //test the overall stuff
+ gg->set_value(80);
+ BOOST_CHECK_CLOSE(gg->get_value(), 80.0, tolerance);
+ BOOST_CHECK_CLOSE(gg->get_range().start(), -20.0, tolerance);
+ BOOST_CHECK_CLOSE(gg->get_range().stop(), 100.0, tolerance);
+ BOOST_CHECK_CLOSE(gg->get_range().step(), 0.1, tolerance);
+
+ //test the the higher priority gain got filled first (gain 2)
+ BOOST_CHECK_CLOSE(g2.get_value(), g2.get_range().stop(), tolerance);
+}
diff --git a/host/tests/module_test.cpp b/host/tests/module_test.cpp
new file mode 100644
index 000000000..af2f749a7
--- /dev/null
+++ b/host/tests/module_test.cpp
@@ -0,0 +1,26 @@
+//
+// Copyright 2010-2011 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 <iostream>
+
+UHD_STATIC_BLOCK(module_test){
+ std::cout << "---------------------------------------" << std::endl;
+ std::cout << "-- Good news, everyone!" << std::endl;
+ std::cout << "-- The test module has been loaded." << std::endl;
+ std::cout << "---------------------------------------" << std::endl;
+}
diff --git a/host/tests/msg_test.cpp b/host/tests/msg_test.cpp
new file mode 100644
index 000000000..94b81268c
--- /dev/null
+++ b/host/tests/msg_test.cpp
@@ -0,0 +1,40 @@
+//
+// Copyright 2010-2011 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 <boost/test/unit_test.hpp>
+#include <uhd/utils/msg.hpp>
+#include <iostream>
+
+BOOST_AUTO_TEST_CASE(test_messages){
+ std::cerr << "---begin print test ---" << std::endl;
+ UHD_MSG(status) <<
+ "This is a test print for a status message.\n"
+ "And this is the second line of the test print.\n"
+ ;
+ UHD_MSG(warning) <<
+ "This is a test print for a warning message.\n"
+ "And this is the second line of the test print.\n"
+ ;
+ UHD_MSG(error) <<
+ "This is a test print for an error message.\n"
+ "And this is the second line of the test print.\n"
+ ;
+ UHD_HERE();
+ const int x = 42;
+ UHD_VAR(x);
+ std::cerr << "---end print test ---" << std::endl;
+}
diff --git a/host/tests/property_test.cpp b/host/tests/property_test.cpp
new file mode 100644
index 000000000..04d3a831c
--- /dev/null
+++ b/host/tests/property_test.cpp
@@ -0,0 +1,175 @@
+//
+// Copyright 2011 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 <boost/test/unit_test.hpp>
+#include <uhd/property_tree.hpp>
+#include <boost/bind.hpp>
+#include <exception>
+#include <iostream>
+
+struct coercer_type{
+ int doit(int x){
+ return x & ~0x3;
+ }
+};
+
+struct setter_type{
+ void doit(int x){
+ _x = x;
+ }
+
+ int _x;
+};
+
+struct getter_type{
+ int doit(void){
+ return _x;
+ }
+
+ int _x;
+};
+
+BOOST_AUTO_TEST_CASE(test_prop_simple){
+ uhd::property_tree::sptr tree = uhd::property_tree::make();
+ uhd::property<int> &prop = tree->create<int>("/");
+
+ BOOST_CHECK(prop.empty());
+ prop.set(0);
+ BOOST_CHECK(not prop.empty());
+
+ prop.set(42);
+ BOOST_CHECK_EQUAL(prop.get(), 42);
+ prop.set(34);
+ BOOST_CHECK_EQUAL(prop.get(), 34);
+}
+
+BOOST_AUTO_TEST_CASE(test_prop_with_subscriber){
+ uhd::property_tree::sptr tree = uhd::property_tree::make();
+ uhd::property<int> &prop = tree->create<int>("/");
+
+ setter_type setter;
+ prop.subscribe(boost::bind(&setter_type::doit, &setter, _1));
+
+ prop.set(42);
+ BOOST_CHECK_EQUAL(prop.get(), 42);
+ BOOST_CHECK_EQUAL(setter._x, 42);
+
+ prop.set(34);
+ BOOST_CHECK_EQUAL(prop.get(), 34);
+ BOOST_CHECK_EQUAL(setter._x, 34);
+}
+
+BOOST_AUTO_TEST_CASE(test_prop_with_publisher){
+ uhd::property_tree::sptr tree = uhd::property_tree::make();
+ uhd::property<int> &prop = tree->create<int>("/");
+
+ BOOST_CHECK(prop.empty());
+ getter_type getter;
+ prop.publish(boost::bind(&getter_type::doit, &getter));
+ BOOST_CHECK(not prop.empty());
+
+ getter._x = 42;
+ prop.set(0); //should not change
+ BOOST_CHECK_EQUAL(prop.get(), 42);
+
+ getter._x = 34;
+ prop.set(0); //should not change
+ BOOST_CHECK_EQUAL(prop.get(), 34);
+}
+
+BOOST_AUTO_TEST_CASE(test_prop_with_publisher_and_subscriber){
+ uhd::property_tree::sptr tree = uhd::property_tree::make();
+ uhd::property<int> &prop = tree->create<int>("/");
+
+ getter_type getter;
+ prop.publish(boost::bind(&getter_type::doit, &getter));
+
+ setter_type setter;
+ prop.subscribe(boost::bind(&setter_type::doit, &setter, _1));
+
+ getter._x = 42;
+ prop.set(0);
+ BOOST_CHECK_EQUAL(prop.get(), 42);
+ BOOST_CHECK_EQUAL(setter._x, 0);
+
+ getter._x = 34;
+ prop.set(1);
+ BOOST_CHECK_EQUAL(prop.get(), 34);
+ BOOST_CHECK_EQUAL(setter._x, 1);
+}
+
+BOOST_AUTO_TEST_CASE(test_prop_with_coercion){
+ uhd::property_tree::sptr tree = uhd::property_tree::make();
+ uhd::property<int> &prop = tree->create<int>("/");
+
+ setter_type setter;
+ prop.subscribe(boost::bind(&setter_type::doit, &setter, _1));
+
+ coercer_type coercer;
+ prop.coerce(boost::bind(&coercer_type::doit, &coercer, _1));
+
+ prop.set(42);
+ BOOST_CHECK_EQUAL(prop.get(), 40);
+ BOOST_CHECK_EQUAL(setter._x, 40);
+
+ prop.set(34);
+ BOOST_CHECK_EQUAL(prop.get(), 32);
+ BOOST_CHECK_EQUAL(setter._x, 32);
+}
+
+BOOST_AUTO_TEST_CASE(test_prop_tree){
+ uhd::property_tree::sptr tree = uhd::property_tree::make();
+
+ tree->create<int>("/test/prop0");
+ tree->create<int>("/test/prop1");
+
+ BOOST_CHECK(tree->exists("/test"));
+ BOOST_CHECK_THROW(tree->access<int>("/test"), std::exception);
+ BOOST_CHECK(tree->exists("/test/prop0"));
+ BOOST_CHECK(tree->exists("/test/prop1"));
+
+ tree->access<int>("/test/prop0").set(42);
+ tree->access<int>("/test/prop1").set(34);
+
+ BOOST_CHECK_EQUAL(tree->access<int>("/test/prop0").get(), 42);
+ BOOST_CHECK_EQUAL(tree->access<int>("/test/prop1").get(), 34);
+
+ tree->remove("/test/prop0");
+ BOOST_CHECK(not tree->exists("/test/prop0"));
+ BOOST_CHECK(tree->exists("/test/prop1"));
+
+ tree->remove("/test");
+ BOOST_CHECK(not tree->exists("/test/prop0"));
+ BOOST_CHECK(not tree->exists("/test/prop1"));
+
+}
+
+BOOST_AUTO_TEST_CASE(test_prop_subtree){
+ uhd::property_tree::sptr tree = uhd::property_tree::make();
+ tree->create<int>("/subdir1/subdir2");
+
+ uhd::property_tree::sptr subtree1 = tree->subtree("/");
+ const std::vector<std::string> tree_dirs1 = tree->list("/");
+ const std::vector<std::string> subtree1_dirs = subtree1->list("");
+ BOOST_CHECK_EQUAL_COLLECTIONS(tree_dirs1.begin(), tree_dirs1.end(), subtree1_dirs.begin(), subtree1_dirs.end());
+
+ uhd::property_tree::sptr subtree2 = subtree1->subtree("subdir1");
+ const std::vector<std::string> tree_dirs2 = tree->list("/subdir1");
+ const std::vector<std::string> subtree2_dirs = subtree2->list("");
+ BOOST_CHECK_EQUAL_COLLECTIONS(tree_dirs2.begin(), tree_dirs2.end(), subtree2_dirs.begin(), subtree2_dirs.end());
+
+}
diff --git a/host/tests/ranges_test.cpp b/host/tests/ranges_test.cpp
new file mode 100644
index 000000000..85bb4c3c4
--- /dev/null
+++ b/host/tests/ranges_test.cpp
@@ -0,0 +1,70 @@
+//
+// Copyright 2010-2011 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 <boost/test/unit_test.hpp>
+#include <uhd/types/ranges.hpp>
+#include <iostream>
+
+using namespace uhd;
+
+static const double tolerance = 0.001;
+
+BOOST_AUTO_TEST_CASE(test_ranges_bounds){
+ meta_range_t mr;
+ mr.push_back(range_t(-1.0, +1.0, 0.1));
+ BOOST_CHECK_CLOSE(mr.start(), -1.0, tolerance);
+ BOOST_CHECK_CLOSE(mr.stop(), +1.0, tolerance);
+ BOOST_CHECK_CLOSE(mr.step(), 0.1, tolerance);
+
+ mr.push_back(range_t(40.0, 60.0, 1.0));
+ BOOST_CHECK_CLOSE(mr.start(), -1.0, tolerance);
+ BOOST_CHECK_CLOSE(mr.stop(), 60.0, tolerance);
+ BOOST_CHECK_CLOSE(mr.step(), 0.1, tolerance);
+
+ BOOST_CHECK_EQUAL(mr.size(), unsigned(2));
+
+ BOOST_CHECK_CLOSE(mr[0].start(), -1.0, tolerance);
+ BOOST_CHECK_CLOSE(mr[0].stop(), +1.0, tolerance);
+ BOOST_CHECK_CLOSE(mr[0].step(), 0.1, tolerance);
+}
+
+BOOST_AUTO_TEST_CASE(test_ranges_clip){
+ meta_range_t mr;
+ mr.push_back(range_t(-1.0, +1.0, 0.1));
+ mr.push_back(range_t(40.0, 60.0, 1.0));
+
+ BOOST_CHECK_CLOSE(mr.clip(-30.0), -1.0, tolerance);
+ BOOST_CHECK_CLOSE(mr.clip(70.0), 60.0, tolerance);
+ BOOST_CHECK_CLOSE(mr.clip(20.0), 1.0, tolerance);
+ BOOST_CHECK_CLOSE(mr.clip(50.0), 50.0, tolerance);
+
+ BOOST_CHECK_CLOSE(mr.clip(50.9, false), 50.9, tolerance);
+ BOOST_CHECK_CLOSE(mr.clip(50.9, true), 51.0, tolerance);
+}
+
+BOOST_AUTO_TEST_CASE(test_ranges_clip2){
+ meta_range_t mr;
+ mr.push_back(range_t(1.));
+ mr.push_back(range_t(2.));
+ mr.push_back(range_t(3.));
+
+ BOOST_CHECK_CLOSE(mr.clip(2., true), 2., tolerance);
+ BOOST_CHECK_CLOSE(mr.clip(0., true), 1., tolerance);
+ BOOST_CHECK_CLOSE(mr.clip(1.2, true), 1., tolerance);
+ BOOST_CHECK_CLOSE(mr.clip(3.1, true), 3., tolerance);
+ BOOST_CHECK_CLOSE(mr.clip(4., true), 3., tolerance);
+}
diff --git a/host/tests/sph_recv_test.cpp b/host/tests/sph_recv_test.cpp
new file mode 100644
index 000000000..9b45d7016
--- /dev/null
+++ b/host/tests/sph_recv_test.cpp
@@ -0,0 +1,707 @@
+//
+// Copyright 2011-2012 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 <boost/test/unit_test.hpp>
+#include "../lib/transport/super_recv_packet_handler.hpp"
+#include <boost/shared_array.hpp>
+#include <boost/bind.hpp>
+#include <complex>
+#include <vector>
+#include <list>
+
+#define BOOST_CHECK_TS_CLOSE(a, b) \
+ BOOST_CHECK_CLOSE((a).get_real_secs(), (b).get_real_secs(), 0.001)
+
+/***********************************************************************
+ * A dummy overflow handler for testing
+ **********************************************************************/
+struct overflow_handler_type{
+ overflow_handler_type(void){
+ num_overflow = 0;
+ }
+ void handle(void){
+ num_overflow++;
+ }
+ size_t num_overflow;
+};
+
+/***********************************************************************
+ * A dummy managed receive buffer for testing
+ **********************************************************************/
+class dummy_mrb : public uhd::transport::managed_recv_buffer{
+public:
+ void release(void){
+ //NOP
+ }
+
+ sptr get_new(boost::shared_array<char> mem, size_t len){
+ _mem = mem;
+ _len = len;
+ return make_managed_buffer(this);
+ }
+
+private:
+ const void *get_buff(void) const{return _mem.get();}
+ size_t get_size(void) const{return _len;}
+
+ boost::shared_array<char> _mem;
+ size_t _len;
+};
+
+/***********************************************************************
+ * A dummy transport class to fill with fake data
+ **********************************************************************/
+class dummy_recv_xport_class{
+public:
+ dummy_recv_xport_class(const std::string &end){
+ _end = end;
+ }
+
+ void push_back_packet(
+ uhd::transport::vrt::if_packet_info_t &ifpi,
+ const boost::uint32_t optional_msg_word = 0
+ ){
+ const size_t max_pkt_len = (ifpi.num_payload_words32 + uhd::transport::vrt::max_if_hdr_words32 + 1/*tlr*/)*sizeof(boost::uint32_t);
+ _mems.push_back(boost::shared_array<char>(new char[max_pkt_len]));
+ if (_end == "big"){
+ uhd::transport::vrt::if_hdr_pack_be(reinterpret_cast<boost::uint32_t *>(_mems.back().get()), ifpi);
+ }
+ if (_end == "little"){
+ uhd::transport::vrt::if_hdr_pack_le(reinterpret_cast<boost::uint32_t *>(_mems.back().get()), ifpi);
+ }
+ (reinterpret_cast<boost::uint32_t *>(_mems.back().get()) + ifpi.num_header_words32)[0] = optional_msg_word | uhd::byteswap(optional_msg_word);
+ _lens.push_back(ifpi.num_packet_words32*sizeof(boost::uint32_t));
+ }
+
+ uhd::transport::managed_recv_buffer::sptr get_recv_buff(double){
+ if (_mems.empty()) return uhd::transport::managed_recv_buffer::sptr(); //timeout
+ _mrbs.push_back(dummy_mrb());
+ uhd::transport::managed_recv_buffer::sptr mrb = _mrbs.back().get_new(_mems.front(), _lens.front());
+ _mems.pop_front();
+ _lens.pop_front();
+ return mrb;
+ }
+
+private:
+ std::list<boost::shared_array<char> > _mems;
+ std::list<size_t> _lens;
+ std::list<dummy_mrb> _mrbs; //list means no-realloc
+ std::string _end;
+};
+
+////////////////////////////////////////////////////////////////////////
+BOOST_AUTO_TEST_CASE(test_sph_recv_one_channel_normal){
+////////////////////////////////////////////////////////////////////////
+ uhd::convert::id_type id;
+ id.input_format = "sc16_item32_be";
+ id.num_inputs = 1;
+ id.output_format = "fc32";
+ id.num_outputs = 1;
+
+ dummy_recv_xport_class dummy_recv_xport("big");
+ uhd::transport::vrt::if_packet_info_t ifpi;
+ ifpi.packet_type = uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_DATA;
+ ifpi.num_payload_words32 = 0;
+ ifpi.packet_count = 0;
+ ifpi.sob = true;
+ ifpi.eob = false;
+ ifpi.has_sid = false;
+ ifpi.has_cid = false;
+ ifpi.has_tsi = true;
+ ifpi.has_tsf = true;
+ ifpi.tsi = 0;
+ ifpi.tsf = 0;
+ ifpi.has_tlr = false;
+
+ static const double TICK_RATE = 100e6;
+ static const double SAMP_RATE = 10e6;
+ static const size_t NUM_PKTS_TO_TEST = 30;
+
+ //generate a bunch of packets
+ for (size_t i = 0; i < NUM_PKTS_TO_TEST; i++){
+ ifpi.num_payload_words32 = 10 + i%10;
+ dummy_recv_xport.push_back_packet(ifpi);
+ ifpi.packet_count++;
+ ifpi.tsf += ifpi.num_payload_words32*size_t(TICK_RATE/SAMP_RATE);
+ }
+
+ //create the super receive packet handler
+ uhd::transport::sph::recv_packet_handler handler(1);
+ handler.set_vrt_unpacker(&uhd::transport::vrt::if_hdr_unpack_be);
+ handler.set_tick_rate(TICK_RATE);
+ handler.set_samp_rate(SAMP_RATE);
+ handler.set_xport_chan_get_buff(0, boost::bind(&dummy_recv_xport_class::get_recv_buff, &dummy_recv_xport, _1));
+ handler.set_converter(id);
+
+ //check the received packets
+ size_t num_accum_samps = 0;
+ std::vector<std::complex<float> > buff(20);
+ uhd::rx_metadata_t metadata;
+ for (size_t i = 0; i < NUM_PKTS_TO_TEST; i++){
+ std::cout << "data check " << i << std::endl;
+ size_t num_samps_ret = handler.recv(
+ &buff.front(), buff.size(), metadata, 1.0, true
+ );
+ BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
+ BOOST_CHECK(not metadata.more_fragments);
+ BOOST_CHECK(metadata.has_time_spec);
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_EQUAL(num_samps_ret, 10 + i%10);
+ num_accum_samps += num_samps_ret;
+ }
+
+ //subsequent receives should be a timeout
+ for (size_t i = 0; i < 3; i++){
+ std::cout << "timeout check " << i << std::endl;
+ handler.recv(
+ &buff.front(), buff.size(), metadata, 1.0, true
+ );
+ BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_TIMEOUT);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+BOOST_AUTO_TEST_CASE(test_sph_recv_one_channel_sequence_error){
+////////////////////////////////////////////////////////////////////////
+ uhd::convert::id_type id;
+ id.input_format = "sc16_item32_be";
+ id.num_inputs = 1;
+ id.output_format = "fc32";
+ id.num_outputs = 1;
+
+ dummy_recv_xport_class dummy_recv_xport("big");
+ uhd::transport::vrt::if_packet_info_t ifpi;
+ ifpi.packet_type = uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_DATA;
+ ifpi.num_payload_words32 = 0;
+ ifpi.packet_count = 0;
+ ifpi.sob = true;
+ ifpi.eob = false;
+ ifpi.has_sid = false;
+ ifpi.has_cid = false;
+ ifpi.has_tsi = true;
+ ifpi.has_tsf = true;
+ ifpi.tsi = 0;
+ ifpi.tsf = 0;
+ ifpi.has_tlr = false;
+
+ static const double TICK_RATE = 100e6;
+ static const double SAMP_RATE = 10e6;
+ static const size_t NUM_PKTS_TO_TEST = 30;
+
+ //generate a bunch of packets
+ for (size_t i = 0; i < NUM_PKTS_TO_TEST; i++){
+ ifpi.num_payload_words32 = 10 + i%10;
+ if (i != NUM_PKTS_TO_TEST/2){ //simulate a lost packet
+ dummy_recv_xport.push_back_packet(ifpi);
+ }
+ ifpi.packet_count++;
+ ifpi.tsf += ifpi.num_payload_words32*size_t(TICK_RATE/SAMP_RATE);
+ }
+
+ //create the super receive packet handler
+ uhd::transport::sph::recv_packet_handler handler(1);
+ handler.set_vrt_unpacker(&uhd::transport::vrt::if_hdr_unpack_be);
+ handler.set_tick_rate(TICK_RATE);
+ handler.set_samp_rate(SAMP_RATE);
+ handler.set_xport_chan_get_buff(0, boost::bind(&dummy_recv_xport_class::get_recv_buff, &dummy_recv_xport, _1));
+ handler.set_converter(id);
+
+ //check the received packets
+ size_t num_accum_samps = 0;
+ std::vector<std::complex<float> > buff(20);
+ uhd::rx_metadata_t metadata;
+ for (size_t i = 0; i < NUM_PKTS_TO_TEST; i++){
+ std::cout << "data check " << i << std::endl;
+ size_t num_samps_ret = handler.recv(
+ &buff.front(), buff.size(), metadata, 1.0, true
+ );
+ if (i == NUM_PKTS_TO_TEST/2){
+ //must get the soft overflow here
+ BOOST_REQUIRE(metadata.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW);
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
+ num_accum_samps += 10 + i%10;
+ }
+ else{
+ BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
+ BOOST_CHECK(not metadata.more_fragments);
+ BOOST_CHECK(metadata.has_time_spec);
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_EQUAL(num_samps_ret, 10 + i%10);
+ num_accum_samps += num_samps_ret;
+ }
+ }
+
+ //subsequent receives should be a timeout
+ for (size_t i = 0; i < 3; i++){
+ std::cout << "timeout check " << i << std::endl;
+ handler.recv(
+ &buff.front(), buff.size(), metadata, 1.0, true
+ );
+ BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_TIMEOUT);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+BOOST_AUTO_TEST_CASE(test_sph_recv_one_channel_inline_message){
+////////////////////////////////////////////////////////////////////////
+ uhd::convert::id_type id;
+ id.input_format = "sc16_item32_be";
+ id.num_inputs = 1;
+ id.output_format = "fc32";
+ id.num_outputs = 1;
+
+ dummy_recv_xport_class dummy_recv_xport("big");
+ uhd::transport::vrt::if_packet_info_t ifpi;
+ ifpi.packet_type = uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_DATA;
+ ifpi.num_payload_words32 = 0;
+ ifpi.packet_count = 0;
+ ifpi.sob = true;
+ ifpi.eob = false;
+ ifpi.has_sid = false;
+ ifpi.has_cid = false;
+ ifpi.has_tsi = true;
+ ifpi.has_tsf = true;
+ ifpi.tsi = 0;
+ ifpi.tsf = 0;
+ ifpi.has_tlr = false;
+
+ static const double TICK_RATE = 100e6;
+ static const double SAMP_RATE = 10e6;
+ static const size_t NUM_PKTS_TO_TEST = 30;
+
+ //generate a bunch of packets
+ for (size_t i = 0; i < NUM_PKTS_TO_TEST; i++){
+ ifpi.packet_type = uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_DATA;
+ ifpi.num_payload_words32 = 10 + i%10;
+ dummy_recv_xport.push_back_packet(ifpi);
+ ifpi.packet_count++;
+ ifpi.tsf += ifpi.num_payload_words32*size_t(TICK_RATE/SAMP_RATE);
+
+ //simulate overflow
+ if (i == NUM_PKTS_TO_TEST/2){
+ ifpi.packet_type = uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_EXTENSION;
+ ifpi.num_payload_words32 = 1;
+ dummy_recv_xport.push_back_packet(ifpi, uhd::rx_metadata_t::ERROR_CODE_OVERFLOW);
+ }
+ }
+
+ //create the super receive packet handler
+ uhd::transport::sph::recv_packet_handler handler(1);
+ handler.set_vrt_unpacker(&uhd::transport::vrt::if_hdr_unpack_be);
+ handler.set_tick_rate(TICK_RATE);
+ handler.set_samp_rate(SAMP_RATE);
+ handler.set_xport_chan_get_buff(0, boost::bind(&dummy_recv_xport_class::get_recv_buff, &dummy_recv_xport, _1));
+ handler.set_converter(id);
+
+ //create an overflow handler
+ overflow_handler_type overflow_handler;
+ handler.set_overflow_handler(0, boost::bind(&overflow_handler_type::handle, &overflow_handler));
+
+ //check the received packets
+ size_t num_accum_samps = 0;
+ std::vector<std::complex<float> > buff(20);
+ uhd::rx_metadata_t metadata;
+ for (size_t i = 0; i < NUM_PKTS_TO_TEST; i++){
+ std::cout << "data check " << i << std::endl;
+ size_t num_samps_ret = handler.recv(
+ &buff.front(), buff.size(), metadata, 1.0, true
+ );
+ BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
+ BOOST_CHECK(not metadata.more_fragments);
+ BOOST_CHECK(metadata.has_time_spec);
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_EQUAL(num_samps_ret, 10 + i%10);
+ num_accum_samps += num_samps_ret;
+ if (i == NUM_PKTS_TO_TEST/2){
+ handler.recv(
+ &buff.front(), buff.size(), metadata, 1.0, true
+ );
+ std::cout << "metadata.error_code " << metadata.error_code << std::endl;
+ BOOST_REQUIRE(metadata.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW);
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_EQUAL(overflow_handler.num_overflow, size_t(1));
+ }
+ }
+
+ //subsequent receives should be a timeout
+ for (size_t i = 0; i < 3; i++){
+ std::cout << "timeout check " << i << std::endl;
+ handler.recv(
+ &buff.front(), buff.size(), metadata, 1.0, true
+ );
+ BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_TIMEOUT);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_normal){
+////////////////////////////////////////////////////////////////////////
+ uhd::convert::id_type id;
+ id.input_format = "sc16_item32_be";
+ id.num_inputs = 1;
+ id.output_format = "fc32";
+ id.num_outputs = 1;
+
+ uhd::transport::vrt::if_packet_info_t ifpi;
+ ifpi.packet_type = uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_DATA;
+ ifpi.num_payload_words32 = 0;
+ ifpi.packet_count = 0;
+ ifpi.sob = true;
+ ifpi.eob = false;
+ ifpi.has_sid = false;
+ ifpi.has_cid = false;
+ ifpi.has_tsi = true;
+ ifpi.has_tsf = true;
+ ifpi.tsi = 0;
+ ifpi.tsf = 0;
+ ifpi.has_tlr = false;
+
+ static const double TICK_RATE = 100e6;
+ static const double SAMP_RATE = 10e6;
+ static const size_t NUM_PKTS_TO_TEST = 30;
+ static const size_t NUM_SAMPS_PER_BUFF = 20;
+ static const size_t NCHANNELS = 4;
+
+ std::vector<dummy_recv_xport_class> dummy_recv_xports(NCHANNELS, dummy_recv_xport_class("big"));
+
+ //generate a bunch of packets
+ for (size_t i = 0; i < NUM_PKTS_TO_TEST; i++){
+ ifpi.num_payload_words32 = 10 + i%10;
+ for (size_t ch = 0; ch < NCHANNELS; ch++){
+ dummy_recv_xports[ch].push_back_packet(ifpi);
+ }
+ ifpi.packet_count++;
+ ifpi.tsf += ifpi.num_payload_words32*size_t(TICK_RATE/SAMP_RATE);
+ }
+
+ //create the super receive packet handler
+ uhd::transport::sph::recv_packet_handler handler(NCHANNELS);
+ handler.set_vrt_unpacker(&uhd::transport::vrt::if_hdr_unpack_be);
+ handler.set_tick_rate(TICK_RATE);
+ handler.set_samp_rate(SAMP_RATE);
+ for (size_t ch = 0; ch < NCHANNELS; ch++){
+ handler.set_xport_chan_get_buff(ch, boost::bind(&dummy_recv_xport_class::get_recv_buff, &dummy_recv_xports[ch], _1));
+ }
+ handler.set_converter(id);
+
+ //check the received packets
+ size_t num_accum_samps = 0;
+ std::vector<std::complex<float> > mem(NUM_SAMPS_PER_BUFF*NCHANNELS);
+ std::vector<std::complex<float> *> buffs(NCHANNELS);
+ for (size_t ch = 0; ch < NCHANNELS; ch++){
+ buffs[ch] = &mem[ch*NUM_SAMPS_PER_BUFF];
+ }
+ uhd::rx_metadata_t metadata;
+ for (size_t i = 0; i < NUM_PKTS_TO_TEST; i++){
+ std::cout << "data check " << i << std::endl;
+ size_t num_samps_ret = handler.recv(
+ buffs, NUM_SAMPS_PER_BUFF, metadata, 1.0, true
+ );
+ BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
+ BOOST_CHECK(not metadata.more_fragments);
+ BOOST_CHECK(metadata.has_time_spec);
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_EQUAL(num_samps_ret, 10 + i%10);
+ num_accum_samps += num_samps_ret;
+ }
+
+ //subsequent receives should be a timeout
+ for (size_t i = 0; i < 3; i++){
+ std::cout << "timeout check " << i << std::endl;
+ handler.recv(
+ buffs, NUM_SAMPS_PER_BUFF, metadata, 1.0, true
+ );
+ BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_TIMEOUT);
+ }
+
+}
+
+////////////////////////////////////////////////////////////////////////
+BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_sequence_error){
+////////////////////////////////////////////////////////////////////////
+ uhd::convert::id_type id;
+ id.input_format = "sc16_item32_be";
+ id.num_inputs = 1;
+ id.output_format = "fc32";
+ id.num_outputs = 1;
+
+ uhd::transport::vrt::if_packet_info_t ifpi;
+ ifpi.packet_type = uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_DATA;
+ ifpi.num_payload_words32 = 0;
+ ifpi.packet_count = 0;
+ ifpi.sob = true;
+ ifpi.eob = false;
+ ifpi.has_sid = false;
+ ifpi.has_cid = false;
+ ifpi.has_tsi = true;
+ ifpi.has_tsf = true;
+ ifpi.tsi = 0;
+ ifpi.tsf = 0;
+ ifpi.has_tlr = false;
+
+ static const double TICK_RATE = 100e6;
+ static const double SAMP_RATE = 10e6;
+ static const size_t NUM_PKTS_TO_TEST = 30;
+ static const size_t NUM_SAMPS_PER_BUFF = 20;
+ static const size_t NCHANNELS = 4;
+
+ std::vector<dummy_recv_xport_class> dummy_recv_xports(NCHANNELS, dummy_recv_xport_class("big"));
+
+ //generate a bunch of packets
+ for (size_t i = 0; i < NUM_PKTS_TO_TEST; i++){
+ ifpi.num_payload_words32 = 10 + i%10;
+ for (size_t ch = 0; ch < NCHANNELS; ch++){
+ if (i == NUM_PKTS_TO_TEST/2 and ch == 2){
+ continue; //simulates a lost packet
+ }
+ dummy_recv_xports[ch].push_back_packet(ifpi);
+ }
+ ifpi.packet_count++;
+ ifpi.tsf += ifpi.num_payload_words32*size_t(TICK_RATE/SAMP_RATE);
+ }
+
+ //create the super receive packet handler
+ uhd::transport::sph::recv_packet_handler handler(NCHANNELS);
+ handler.set_vrt_unpacker(&uhd::transport::vrt::if_hdr_unpack_be);
+ handler.set_tick_rate(TICK_RATE);
+ handler.set_samp_rate(SAMP_RATE);
+ for (size_t ch = 0; ch < NCHANNELS; ch++){
+ handler.set_xport_chan_get_buff(ch, boost::bind(&dummy_recv_xport_class::get_recv_buff, &dummy_recv_xports[ch], _1));
+ }
+ handler.set_converter(id);
+
+ //check the received packets
+ size_t num_accum_samps = 0;
+ std::vector<std::complex<float> > mem(NUM_SAMPS_PER_BUFF*NCHANNELS);
+ std::vector<std::complex<float> *> buffs(NCHANNELS);
+ for (size_t ch = 0; ch < NCHANNELS; ch++){
+ buffs[ch] = &mem[ch*NUM_SAMPS_PER_BUFF];
+ }
+ uhd::rx_metadata_t metadata;
+ for (size_t i = 0; i < NUM_PKTS_TO_TEST; i++){
+ std::cout << "data check " << i << std::endl;
+ size_t num_samps_ret = handler.recv(
+ buffs, NUM_SAMPS_PER_BUFF, metadata, 1.0, true
+ );
+ if (i == NUM_PKTS_TO_TEST/2){
+ //must get the soft overflow here
+ BOOST_REQUIRE(metadata.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW);
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
+ num_accum_samps += 10 + i%10;
+ }
+ else{
+ BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
+ BOOST_CHECK(not metadata.more_fragments);
+ BOOST_CHECK(metadata.has_time_spec);
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_EQUAL(num_samps_ret, 10 + i%10);
+ num_accum_samps += num_samps_ret;
+ }
+ }
+
+ //subsequent receives should be a timeout
+ for (size_t i = 0; i < 3; i++){
+ std::cout << "timeout check " << i << std::endl;
+ handler.recv(
+ buffs, NUM_SAMPS_PER_BUFF, metadata, 1.0, true
+ );
+ BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_TIMEOUT);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_time_error){
+////////////////////////////////////////////////////////////////////////
+ uhd::convert::id_type id;
+ id.input_format = "sc16_item32_be";
+ id.num_inputs = 1;
+ id.output_format = "fc32";
+ id.num_outputs = 1;
+
+ uhd::transport::vrt::if_packet_info_t ifpi;
+ ifpi.packet_type = uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_DATA;
+ ifpi.num_payload_words32 = 0;
+ ifpi.packet_count = 0;
+ ifpi.sob = true;
+ ifpi.eob = false;
+ ifpi.has_sid = false;
+ ifpi.has_cid = false;
+ ifpi.has_tsi = true;
+ ifpi.has_tsf = true;
+ ifpi.tsi = 0;
+ ifpi.tsf = 0;
+ ifpi.has_tlr = false;
+
+ static const double TICK_RATE = 100e6;
+ static const double SAMP_RATE = 10e6;
+ static const size_t NUM_PKTS_TO_TEST = 30;
+ static const size_t NUM_SAMPS_PER_BUFF = 20;
+ static const size_t NCHANNELS = 4;
+
+ std::vector<dummy_recv_xport_class> dummy_recv_xports(NCHANNELS, dummy_recv_xport_class("big"));
+
+ //generate a bunch of packets
+ for (size_t i = 0; i < NUM_PKTS_TO_TEST; i++){
+ ifpi.num_payload_words32 = 10 + i%10;
+ for (size_t ch = 0; ch < NCHANNELS; ch++){
+ dummy_recv_xports[ch].push_back_packet(ifpi);
+ }
+ ifpi.packet_count++;
+ ifpi.tsf += ifpi.num_payload_words32*size_t(TICK_RATE/SAMP_RATE);
+ if (i == NUM_PKTS_TO_TEST/2){
+ ifpi.tsf = 0; //simulate the user changing the time
+ }
+ }
+
+ //create the super receive packet handler
+ uhd::transport::sph::recv_packet_handler handler(NCHANNELS);
+ handler.set_vrt_unpacker(&uhd::transport::vrt::if_hdr_unpack_be);
+ handler.set_tick_rate(TICK_RATE);
+ handler.set_samp_rate(SAMP_RATE);
+ for (size_t ch = 0; ch < NCHANNELS; ch++){
+ handler.set_xport_chan_get_buff(ch, boost::bind(&dummy_recv_xport_class::get_recv_buff, &dummy_recv_xports[ch], _1));
+ }
+ handler.set_converter(id);
+
+ //check the received packets
+ size_t num_accum_samps = 0;
+ std::vector<std::complex<float> > mem(NUM_SAMPS_PER_BUFF*NCHANNELS);
+ std::vector<std::complex<float> *> buffs(NCHANNELS);
+ for (size_t ch = 0; ch < NCHANNELS; ch++){
+ buffs[ch] = &mem[ch*NUM_SAMPS_PER_BUFF];
+ }
+ uhd::rx_metadata_t metadata;
+ for (size_t i = 0; i < NUM_PKTS_TO_TEST; i++){
+ std::cout << "data check " << i << std::endl;
+ size_t num_samps_ret = handler.recv(
+ buffs, NUM_SAMPS_PER_BUFF, metadata, 1.0, true
+ );
+ BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
+ BOOST_CHECK(not metadata.more_fragments);
+ BOOST_CHECK(metadata.has_time_spec);
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_EQUAL(num_samps_ret, 10 + i%10);
+ num_accum_samps += num_samps_ret;
+ if (i == NUM_PKTS_TO_TEST/2){
+ num_accum_samps = 0; //simulate the user changing the time
+ }
+ }
+
+ //subsequent receives should be a timeout
+ for (size_t i = 0; i < 3; i++){
+ std::cout << "timeout check " << i << std::endl;
+ handler.recv(
+ buffs, NUM_SAMPS_PER_BUFF, metadata, 1.0, true
+ );
+ BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_TIMEOUT);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_fragment){
+////////////////////////////////////////////////////////////////////////
+ uhd::convert::id_type id;
+ id.input_format = "sc16_item32_be";
+ id.num_inputs = 1;
+ id.output_format = "fc32";
+ id.num_outputs = 1;
+
+ uhd::transport::vrt::if_packet_info_t ifpi;
+ ifpi.packet_type = uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_DATA;
+ ifpi.num_payload_words32 = 0;
+ ifpi.packet_count = 0;
+ ifpi.sob = true;
+ ifpi.eob = false;
+ ifpi.has_sid = false;
+ ifpi.has_cid = false;
+ ifpi.has_tsi = true;
+ ifpi.has_tsf = true;
+ ifpi.tsi = 0;
+ ifpi.tsf = 0;
+ ifpi.has_tlr = false;
+
+ static const double TICK_RATE = 100e6;
+ static const double SAMP_RATE = 10e6;
+ static const size_t NUM_PKTS_TO_TEST = 30;
+ static const size_t NUM_SAMPS_PER_BUFF = 10;
+ static const size_t NCHANNELS = 4;
+
+ std::vector<dummy_recv_xport_class> dummy_recv_xports(NCHANNELS, dummy_recv_xport_class("big"));
+
+ //generate a bunch of packets
+ for (size_t i = 0; i < NUM_PKTS_TO_TEST; i++){
+ ifpi.num_payload_words32 = 10 + i%10;
+ for (size_t ch = 0; ch < NCHANNELS; ch++){
+ dummy_recv_xports[ch].push_back_packet(ifpi);
+ }
+ ifpi.packet_count++;
+ ifpi.tsf += ifpi.num_payload_words32*size_t(TICK_RATE/SAMP_RATE);
+ }
+
+ //create the super receive packet handler
+ uhd::transport::sph::recv_packet_handler handler(NCHANNELS);
+ handler.set_vrt_unpacker(&uhd::transport::vrt::if_hdr_unpack_be);
+ handler.set_tick_rate(TICK_RATE);
+ handler.set_samp_rate(SAMP_RATE);
+ for (size_t ch = 0; ch < NCHANNELS; ch++){
+ handler.set_xport_chan_get_buff(ch, boost::bind(&dummy_recv_xport_class::get_recv_buff, &dummy_recv_xports[ch], _1));
+ }
+ handler.set_converter(id);
+
+ //check the received packets
+ size_t num_accum_samps = 0;
+ std::vector<std::complex<float> > mem(NUM_SAMPS_PER_BUFF*NCHANNELS);
+ std::vector<std::complex<float> *> buffs(NCHANNELS);
+ for (size_t ch = 0; ch < NCHANNELS; ch++){
+ buffs[ch] = &mem[ch*NUM_SAMPS_PER_BUFF];
+ }
+ uhd::rx_metadata_t metadata;
+ for (size_t i = 0; i < NUM_PKTS_TO_TEST; i++){
+ std::cout << "data check " << i << std::endl;
+ size_t num_samps_ret = handler.recv(
+ buffs, NUM_SAMPS_PER_BUFF, metadata, 1.0, true
+ );
+ BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
+ BOOST_CHECK(metadata.has_time_spec);
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_EQUAL(num_samps_ret, 10);
+ num_accum_samps += num_samps_ret;
+
+ if (not metadata.more_fragments) continue;
+
+ num_samps_ret = handler.recv(
+ buffs, NUM_SAMPS_PER_BUFF, metadata, 1.0, true
+ );
+ BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_NONE);
+ BOOST_CHECK(not metadata.more_fragments);
+ BOOST_CHECK_EQUAL(metadata.fragment_offset, 10);
+ BOOST_CHECK(metadata.has_time_spec);
+ BOOST_CHECK_TS_CLOSE(metadata.time_spec, uhd::time_spec_t::from_ticks(num_accum_samps, SAMP_RATE));
+ BOOST_CHECK_EQUAL(num_samps_ret, i%10);
+ num_accum_samps += num_samps_ret;
+ }
+
+ //subsequent receives should be a timeout
+ for (size_t i = 0; i < 3; i++){
+ std::cout << "timeout check " << i << std::endl;
+ handler.recv(
+ buffs, NUM_SAMPS_PER_BUFF, metadata, 1.0, true
+ );
+ BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_TIMEOUT);
+ }
+
+}
diff --git a/host/tests/sph_send_test.cpp b/host/tests/sph_send_test.cpp
new file mode 100644
index 000000000..c31399d12
--- /dev/null
+++ b/host/tests/sph_send_test.cpp
@@ -0,0 +1,198 @@
+//
+// Copyright 2011-2012 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 <boost/test/unit_test.hpp>
+#include "../lib/transport/super_send_packet_handler.hpp"
+#include <boost/shared_array.hpp>
+#include <boost/bind.hpp>
+#include <complex>
+#include <vector>
+#include <list>
+
+#define BOOST_CHECK_TS_CLOSE(a, b) \
+ BOOST_CHECK_CLOSE((a).get_real_secs(), (b).get_real_secs(), 0.001)
+
+/***********************************************************************
+ * A dummy managed send buffer for testing
+ **********************************************************************/
+class dummy_msb : public uhd::transport::managed_send_buffer{
+public:
+ void commit(size_t len){
+ if (len == 0) return;
+ *_len = len;
+ }
+
+ sptr get_new(boost::shared_array<char> mem, size_t *len){
+ _mem = mem;
+ _len = len;
+ return make_managed_buffer(this);
+ }
+
+private:
+ void *get_buff(void) const{return _mem.get();}
+ size_t get_size(void) const{return *_len;}
+
+ boost::shared_array<char> _mem;
+ size_t *_len;
+};
+
+/***********************************************************************
+ * A dummy transport class to fill with fake data
+ **********************************************************************/
+class dummy_send_xport_class{
+public:
+ dummy_send_xport_class(const std::string &end){
+ _end = end;
+ }
+
+ void pop_front_packet(
+ uhd::transport::vrt::if_packet_info_t &ifpi
+ ){
+ ifpi.num_packet_words32 = _lens.front()/sizeof(boost::uint32_t);
+ if (_end == "big"){
+ uhd::transport::vrt::if_hdr_unpack_be(reinterpret_cast<boost::uint32_t *>(_mems.front().get()), ifpi);
+ }
+ if (_end == "little"){
+ uhd::transport::vrt::if_hdr_unpack_le(reinterpret_cast<boost::uint32_t *>(_mems.front().get()), ifpi);
+ }
+ _mems.pop_front();
+ _lens.pop_front();
+ }
+
+ uhd::transport::managed_send_buffer::sptr get_send_buff(double){
+ _msbs.push_back(dummy_msb());
+ _mems.push_back(boost::shared_array<char>(new char[1000]));
+ _lens.push_back(1000);
+ uhd::transport::managed_send_buffer::sptr mrb = _msbs.back().get_new(_mems.back(), &_lens.back());
+ return mrb;
+ }
+
+private:
+ std::list<boost::shared_array<char> > _mems;
+ std::list<size_t> _lens;
+ std::list<dummy_msb> _msbs; //list means no-realloc
+ std::string _end;
+};
+
+////////////////////////////////////////////////////////////////////////
+BOOST_AUTO_TEST_CASE(test_sph_send_one_channel_one_packet_mode){
+////////////////////////////////////////////////////////////////////////
+ uhd::convert::id_type id;
+ id.input_format = "fc32";
+ id.num_inputs = 1;
+ id.output_format = "sc16_item32_be";
+ id.num_outputs = 1;
+
+ dummy_send_xport_class dummy_send_xport("big");
+
+ static const double TICK_RATE = 100e6;
+ static const double SAMP_RATE = 10e6;
+ static const size_t NUM_PKTS_TO_TEST = 30;
+
+ //create the super send packet handler
+ uhd::transport::sph::send_packet_handler handler(1);
+ handler.set_vrt_packer(&uhd::transport::vrt::if_hdr_pack_be);
+ handler.set_tick_rate(TICK_RATE);
+ handler.set_samp_rate(SAMP_RATE);
+ handler.set_xport_chan_get_buff(0, boost::bind(&dummy_send_xport_class::get_send_buff, &dummy_send_xport, _1));
+ handler.set_converter(id);
+ handler.set_max_samples_per_packet(20);
+
+ //allocate metadata and buffer
+ std::vector<std::complex<float> > buff(20);
+ uhd::tx_metadata_t metadata;
+ metadata.has_time_spec = true;
+ metadata.time_spec = uhd::time_spec_t(0.0);
+
+ //generate the test data
+ for (size_t i = 0; i < NUM_PKTS_TO_TEST; i++){
+ metadata.start_of_burst = (i == 0);
+ metadata.end_of_burst = (i == NUM_PKTS_TO_TEST-1);
+ const size_t num_sent = handler.send(
+ &buff.front(), 10 + i%10, metadata, 1.0
+ );
+ BOOST_CHECK_EQUAL(num_sent, 10 + i%10);
+ metadata.time_spec += uhd::time_spec_t(0, num_sent, SAMP_RATE);
+ }
+
+ //check the sent packets
+ size_t num_accum_samps = 0;
+ uhd::transport::vrt::if_packet_info_t ifpi;
+ for (size_t i = 0; i < NUM_PKTS_TO_TEST; i++){
+ std::cout << "data check " << i << std::endl;
+ dummy_send_xport.pop_front_packet(ifpi);
+ BOOST_CHECK_EQUAL(ifpi.num_payload_words32, 10+i%10);
+ BOOST_CHECK(ifpi.has_tsf);
+ BOOST_CHECK_EQUAL(ifpi.tsf, num_accum_samps*TICK_RATE/SAMP_RATE);
+ BOOST_CHECK_EQUAL(ifpi.sob, i == 0);
+ BOOST_CHECK_EQUAL(ifpi.eob, i == NUM_PKTS_TO_TEST-1);
+ num_accum_samps += ifpi.num_payload_words32;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+BOOST_AUTO_TEST_CASE(test_sph_send_one_channel_full_buffer_mode){
+////////////////////////////////////////////////////////////////////////
+ uhd::convert::id_type id;
+ id.input_format = "fc32";
+ id.num_inputs = 1;
+ id.output_format = "sc16_item32_be";
+ id.num_outputs = 1;
+
+ dummy_send_xport_class dummy_send_xport("big");
+
+ static const double TICK_RATE = 100e6;
+ static const double SAMP_RATE = 10e6;
+ static const size_t NUM_PKTS_TO_TEST = 30;
+
+ //create the super send packet handler
+ uhd::transport::sph::send_packet_handler handler(1);
+ handler.set_vrt_packer(&uhd::transport::vrt::if_hdr_pack_be);
+ handler.set_tick_rate(TICK_RATE);
+ handler.set_samp_rate(SAMP_RATE);
+ handler.set_xport_chan_get_buff(0, boost::bind(&dummy_send_xport_class::get_send_buff, &dummy_send_xport, _1));
+ handler.set_converter(id);
+ handler.set_max_samples_per_packet(20);
+
+ //allocate metadata and buffer
+ std::vector<std::complex<float> > buff(20*NUM_PKTS_TO_TEST);
+ uhd::tx_metadata_t metadata;
+ metadata.start_of_burst = true;
+ metadata.end_of_burst = true;
+ metadata.has_time_spec = true;
+ metadata.time_spec = uhd::time_spec_t(0.0);
+
+ //generate the test data
+ const size_t num_sent = handler.send(
+ &buff.front(), buff.size(), metadata, 1.0
+ );
+ BOOST_CHECK_EQUAL(num_sent, buff.size());
+
+ //check the sent packets
+ size_t num_accum_samps = 0;
+ uhd::transport::vrt::if_packet_info_t ifpi;
+ for (size_t i = 0; i < NUM_PKTS_TO_TEST; i++){
+ std::cout << "data check " << i << std::endl;
+ dummy_send_xport.pop_front_packet(ifpi);
+ BOOST_CHECK_EQUAL(ifpi.num_payload_words32, 20);
+ BOOST_CHECK(ifpi.has_tsf);
+ BOOST_CHECK_EQUAL(ifpi.tsf, num_accum_samps*TICK_RATE/SAMP_RATE);
+ BOOST_CHECK_EQUAL(ifpi.sob, i == 0);
+ BOOST_CHECK_EQUAL(ifpi.eob, i == NUM_PKTS_TO_TEST-1);
+ num_accum_samps += ifpi.num_payload_words32;
+ }
+}
diff --git a/host/tests/subdev_spec_test.cpp b/host/tests/subdev_spec_test.cpp
new file mode 100644
index 000000000..aa0b9a119
--- /dev/null
+++ b/host/tests/subdev_spec_test.cpp
@@ -0,0 +1,45 @@
+//
+// Copyright 2010-2011 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 <boost/test/unit_test.hpp>
+#include <uhd/usrp/subdev_spec.hpp>
+#include <boost/foreach.hpp>
+#include <iostream>
+
+BOOST_AUTO_TEST_CASE(test_subdevice_spec){
+ std::cout << "Testing subdevice specification..." << std::endl;
+
+ //load the subdev spec with something
+ uhd::usrp::subdev_spec_t sd_spec;
+ sd_spec.push_back(uhd::usrp::subdev_spec_pair_t("A", "AB"));
+ sd_spec.push_back(uhd::usrp::subdev_spec_pair_t("B", "AB"));
+
+ //convert to and from args string
+ std::cout << "Pretty Print: " << std::endl << sd_spec.to_pp_string();
+ std::string markup_str = sd_spec.to_string();
+ std::cout << "Markup String: " << markup_str << std::endl;
+ uhd::usrp::subdev_spec_t new_sd_spec(markup_str);
+
+ //they should be the same size
+ BOOST_REQUIRE_EQUAL(sd_spec.size(), new_sd_spec.size());
+
+ //the contents should match
+ for (size_t i = 0; i < sd_spec.size(); i++){
+ BOOST_CHECK_EQUAL(sd_spec.at(i).db_name, new_sd_spec.at(i).db_name);
+ BOOST_CHECK_EQUAL(sd_spec.at(i).sd_name, new_sd_spec.at(i).sd_name);
+ }
+}
diff --git a/host/tests/time_spec_test.cpp b/host/tests/time_spec_test.cpp
new file mode 100644
index 000000000..102b7cda3
--- /dev/null
+++ b/host/tests/time_spec_test.cpp
@@ -0,0 +1,99 @@
+//
+// Copyright 2010-2012 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 <boost/test/unit_test.hpp>
+#include <uhd/types/time_spec.hpp>
+#include <boost/foreach.hpp>
+#include <boost/thread.hpp> //sleep
+#include <iostream>
+
+BOOST_AUTO_TEST_CASE(test_time_spec_compare){
+ std::cout << "Testing time specification compare..." << std::endl;
+
+ BOOST_CHECK(uhd::time_spec_t(2.0) == uhd::time_spec_t(2.0));
+ BOOST_CHECK(uhd::time_spec_t(2.0) > uhd::time_spec_t(1.0));
+ BOOST_CHECK(uhd::time_spec_t(1.0) < uhd::time_spec_t(2.0));
+
+ BOOST_CHECK(uhd::time_spec_t(1.1) == uhd::time_spec_t(1.1));
+ BOOST_CHECK(uhd::time_spec_t(1.1) > uhd::time_spec_t(1.0));
+ BOOST_CHECK(uhd::time_spec_t(1.0) < uhd::time_spec_t(1.1));
+
+ BOOST_CHECK(uhd::time_spec_t(0.1) == uhd::time_spec_t(0.1));
+ BOOST_CHECK(uhd::time_spec_t(0.2) > uhd::time_spec_t(0.1));
+ BOOST_CHECK(uhd::time_spec_t(0.1) < uhd::time_spec_t(0.2));
+}
+
+#define CHECK_TS_EQUAL(lhs, rhs) \
+ BOOST_CHECK_CLOSE((lhs).get_real_secs(), (rhs).get_real_secs(), 0.001)
+
+BOOST_AUTO_TEST_CASE(test_time_spec_arithmetic){
+ std::cout << "Testing time specification arithmetic..." << std::endl;
+
+ CHECK_TS_EQUAL(uhd::time_spec_t(2.3) + uhd::time_spec_t(1.0), uhd::time_spec_t(3.3));
+ CHECK_TS_EQUAL(uhd::time_spec_t(2.3) - uhd::time_spec_t(1.0), uhd::time_spec_t(1.3));
+ CHECK_TS_EQUAL(uhd::time_spec_t(1.0) + uhd::time_spec_t(2.3), uhd::time_spec_t(3.3));
+ CHECK_TS_EQUAL(uhd::time_spec_t(1.0) - uhd::time_spec_t(2.3), uhd::time_spec_t(-1.3));
+}
+
+BOOST_AUTO_TEST_CASE(test_time_spec_parts){
+ std::cout << "Testing time specification parts..." << std::endl;
+
+ BOOST_CHECK_EQUAL(uhd::time_spec_t(1.1).get_full_secs(), 1);
+ BOOST_CHECK_CLOSE(uhd::time_spec_t(1.1).get_frac_secs(), 0.1, 0.001);
+ BOOST_CHECK_EQUAL(uhd::time_spec_t(1.1).to_ticks(100), 110);
+
+ BOOST_CHECK_EQUAL(uhd::time_spec_t(-1.1).get_full_secs(), -2);
+ BOOST_CHECK_CLOSE(uhd::time_spec_t(-1.1).get_frac_secs(), 0.9, 0.001);
+ BOOST_CHECK_EQUAL(uhd::time_spec_t(-1.1).to_ticks(100), -110);
+}
+
+BOOST_AUTO_TEST_CASE(test_time_spec_get_system_time){
+ std::cout << "Testing time specification get system time..." << std::endl;
+
+ //Not really checking for high resolution timing here,
+ //just need to check that system time is minimally working.
+
+ uhd::time_spec_t start = uhd::time_spec_t::get_system_time();
+ boost::this_thread::sleep(boost::posix_time::milliseconds(500));
+ uhd::time_spec_t stop = uhd::time_spec_t::get_system_time();
+
+ uhd::time_spec_t diff = stop - start;
+ std::cout << "start: " << start.get_real_secs() << std::endl;
+ std::cout << "stop: " << stop.get_real_secs() << std::endl;
+ std::cout << "diff: " << diff.get_real_secs() << std::endl;
+ BOOST_CHECK(diff.get_real_secs() > 0); //assert positive
+ BOOST_CHECK(diff.get_real_secs() < 1.0); //assert under 1s
+}
+
+BOOST_AUTO_TEST_CASE(test_time_spec_neg_values){
+ uhd::time_spec_t ts1(0.3);
+ uhd::time_spec_t ts2(1, -0.9);
+ std::cout << "ts1 " << ts1.get_real_secs() << std::endl;
+ std::cout << "ts2 " << ts2.get_real_secs() << std::endl;
+ BOOST_CHECK(ts1 > ts2);
+
+ uhd::time_spec_t tsa(430.001083);
+ uhd::time_spec_t tsb(429.999818);
+ uhd::time_spec_t tsc(0.3);
+ uhd::time_spec_t tsd = tsa - tsb;
+ std::cout << "tsa " << tsa.get_real_secs() << std::endl;
+ std::cout << "tsb " << tsb.get_real_secs() << std::endl;
+ std::cout << "tsc " << tsc.get_real_secs() << std::endl;
+ std::cout << "tsd " << tsd.get_real_secs() << std::endl;
+ BOOST_CHECK(tsa > tsb);
+ BOOST_CHECK(tsc > tsd);
+}
diff --git a/host/tests/vrt_test.cpp b/host/tests/vrt_test.cpp
new file mode 100644
index 000000000..066f1493b
--- /dev/null
+++ b/host/tests/vrt_test.cpp
@@ -0,0 +1,141 @@
+//
+// Copyright 2010-2011 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 <boost/test/unit_test.hpp>
+#include <uhd/transport/vrt_if_packet.hpp>
+#include <cstdlib>
+
+using namespace uhd::transport;
+
+static void pack_and_unpack(
+ vrt::if_packet_info_t &if_packet_info_in
+){
+ boost::uint32_t header_buff[vrt::max_if_hdr_words32];
+
+ //pack metadata into a vrt header
+ vrt::if_hdr_pack_be(
+ header_buff, if_packet_info_in
+ );
+
+ vrt::if_packet_info_t if_packet_info_out;
+ if_packet_info_out.num_packet_words32 = if_packet_info_in.num_packet_words32;
+
+ //unpack the vrt header back into metadata
+ vrt::if_hdr_unpack_be(
+ header_buff, if_packet_info_out
+ );
+
+ //check the the unpacked metadata is the same
+ BOOST_CHECK_EQUAL(if_packet_info_in.packet_count, if_packet_info_out.packet_count);
+ BOOST_CHECK_EQUAL(if_packet_info_in.num_header_words32, if_packet_info_out.num_header_words32);
+ BOOST_CHECK_EQUAL(if_packet_info_in.num_payload_words32, if_packet_info_out.num_payload_words32);
+ BOOST_CHECK_EQUAL(if_packet_info_in.has_sid, if_packet_info_out.has_sid);
+ if (if_packet_info_in.has_sid and if_packet_info_out.has_sid){
+ BOOST_CHECK_EQUAL(if_packet_info_in.sid, if_packet_info_out.sid);
+ }
+ BOOST_CHECK_EQUAL(if_packet_info_in.has_cid, if_packet_info_out.has_cid);
+ if (if_packet_info_in.has_cid and if_packet_info_out.has_cid){
+ BOOST_CHECK_EQUAL(if_packet_info_in.cid, if_packet_info_out.cid);
+ }
+ BOOST_CHECK_EQUAL(if_packet_info_in.has_tsi, if_packet_info_out.has_tsi);
+ if (if_packet_info_in.has_tsi and if_packet_info_out.has_tsi){
+ BOOST_CHECK_EQUAL(if_packet_info_in.tsi, if_packet_info_out.tsi);
+ }
+ BOOST_CHECK_EQUAL(if_packet_info_in.has_tsf, if_packet_info_out.has_tsf);
+ if (if_packet_info_in.has_tsf and if_packet_info_out.has_tsf){
+ BOOST_CHECK_EQUAL(if_packet_info_in.tsf, if_packet_info_out.tsf);
+ }
+ BOOST_CHECK_EQUAL(if_packet_info_in.has_tlr, if_packet_info_out.has_tlr);
+ if (if_packet_info_in.has_tlr and if_packet_info_out.has_tlr){
+ BOOST_CHECK_EQUAL(if_packet_info_in.tlr, if_packet_info_out.tlr);
+ }
+}
+
+/***********************************************************************
+ * Loopback test the vrt packer/unpacker with various packet info combos
+ * The trailer is not tested as it is not convenient to do so.
+ **********************************************************************/
+
+BOOST_AUTO_TEST_CASE(test_with_none){
+ vrt::if_packet_info_t if_packet_info;
+ if_packet_info.packet_count = 0;
+ if_packet_info.has_sid = false;
+ if_packet_info.has_cid = false;
+ if_packet_info.has_tsi = false;
+ if_packet_info.has_tsf = false;
+ if_packet_info.has_tlr = false;
+ if_packet_info.num_payload_words32 = 0;
+ pack_and_unpack(if_packet_info);
+}
+
+BOOST_AUTO_TEST_CASE(test_with_sid){
+ vrt::if_packet_info_t if_packet_info;
+ if_packet_info.packet_count = 1;
+ if_packet_info.has_sid = true;
+ if_packet_info.has_cid = false;
+ if_packet_info.has_tsi = false;
+ if_packet_info.has_tsf = false;
+ if_packet_info.has_tlr = false;
+ if_packet_info.sid = std::rand();
+ if_packet_info.num_payload_words32 = 1111;
+ pack_and_unpack(if_packet_info);
+}
+
+static const bool cid_enb = false;
+
+BOOST_AUTO_TEST_CASE(test_with_cid){
+ vrt::if_packet_info_t if_packet_info;
+ if_packet_info.packet_count = 2;
+ if_packet_info.has_sid = false;
+ if_packet_info.has_cid = cid_enb;
+ if_packet_info.has_tsi = false;
+ if_packet_info.has_tsf = false;
+ if_packet_info.has_tlr = false;
+ if_packet_info.cid = std::rand();
+ if_packet_info.num_payload_words32 = 2222;
+ pack_and_unpack(if_packet_info);
+}
+
+BOOST_AUTO_TEST_CASE(test_with_time){
+ vrt::if_packet_info_t if_packet_info;
+ if_packet_info.packet_count = 3;
+ if_packet_info.has_sid = false;
+ if_packet_info.has_cid = false;
+ if_packet_info.has_tsi = true;
+ if_packet_info.has_tsf = true;
+ if_packet_info.has_tlr = false;
+ if_packet_info.tsi = std::rand();
+ if_packet_info.tsf = std::rand();
+ if_packet_info.num_payload_words32 = 33333;
+ pack_and_unpack(if_packet_info);
+}
+
+BOOST_AUTO_TEST_CASE(test_with_all){
+ vrt::if_packet_info_t if_packet_info;
+ if_packet_info.packet_count = 4;
+ if_packet_info.has_sid = true;
+ if_packet_info.has_cid = cid_enb;
+ if_packet_info.has_tsi = true;
+ if_packet_info.has_tsf = true;
+ if_packet_info.has_tlr = false;
+ if_packet_info.sid = std::rand();
+ if_packet_info.cid = std::rand();
+ if_packet_info.tsi = std::rand();
+ if_packet_info.tsf = std::rand();
+ if_packet_info.num_payload_words32 = 44444;
+ pack_and_unpack(if_packet_info);
+}