diff options
Diffstat (limited to 'host/tests')
-rw-r--r-- | host/tests/CMakeLists.txt | 58 | ||||
-rw-r--r-- | host/tests/addr_test.cpp | 80 | ||||
-rw-r--r-- | host/tests/buffer_test.cpp | 64 | ||||
-rw-r--r-- | host/tests/byteswap_test.cpp | 39 | ||||
-rw-r--r-- | host/tests/convert_test.cpp | 262 | ||||
-rw-r--r-- | host/tests/dict_test.cpp | 72 | ||||
-rw-r--r-- | host/tests/error_test.cpp | 59 | ||||
-rw-r--r-- | host/tests/gain_group_test.cpp | 122 | ||||
-rw-r--r-- | host/tests/module_test.cpp | 26 | ||||
-rw-r--r-- | host/tests/msg_test.cpp | 37 | ||||
-rw-r--r-- | host/tests/ranges_test.cpp | 57 | ||||
-rw-r--r-- | host/tests/sph_recv_test.cpp | 715 | ||||
-rw-r--r-- | host/tests/sph_send_test.cpp | 204 | ||||
-rw-r--r-- | host/tests/subdev_spec_test.cpp | 45 | ||||
-rw-r--r-- | host/tests/time_spec_test.cpp | 80 | ||||
-rw-r--r-- | host/tests/tune_helper_test.cpp | 251 | ||||
-rw-r--r-- | host/tests/vrt_test.cpp | 141 | ||||
-rw-r--r-- | host/tests/wax_test.cpp | 104 |
18 files changed, 2416 insertions, 0 deletions
diff --git a/host/tests/CMakeLists.txt b/host/tests/CMakeLists.txt new file mode 100644 index 000000000..b7bcfb7d5 --- /dev/null +++ b/host/tests/CMakeLists.txt @@ -0,0 +1,58 @@ +# +# 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 + ranges_test.cpp + sph_recv_test.cpp + sph_send_test.cpp + subdev_spec_test.cpp + time_spec_test.cpp + tune_helper_test.cpp + vrt_test.cpp + wax_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_DATA_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..01a7ab607 --- /dev/null +++ b/host/tests/addr_test.cpp @@ -0,0 +1,80 @@ +// +// 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["key2"] = "val2"; + + //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..d828ed64a --- /dev/null +++ b/host/tests/convert_test.cpp @@ -0,0 +1,262 @@ +// +// Copyright 2011-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/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) if ((std::abs(a) > (f))) \ + BOOST_CHECK_CLOSE_FRACTION(a, b, f) + +/*********************************************************************** + * Loopback runner: + * convert input buffer into intermediate buffer + * convert intermediate buffer into output buffer + **********************************************************************/ +template <typename Range> static void loopback( + size_t nsamps, + const io_type_t &io_type, + const otw_type_t &otw_type, + 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::get_converter_cpu_to_otw( + io_type, otw_type, input0.size(), output0.size() + )(input0, output0, nsamps, 32767.); + + //convert back to host type + convert::get_converter_otw_to_cpu( + io_type, otw_type, input1.size(), output1.size() + )(input1, output1, nsamps, 1/32767.); +} + +/*********************************************************************** + * Test short conversion + **********************************************************************/ +static void test_convert_types_sc16( + size_t nsamps, + const io_type_t &io_type, + const otw_type_t &otw_type +){ + //fill the input samples + std::vector<sc16_t> input(nsamps), output(nsamps); + BOOST_FOREACH(sc16_t &in, input) in = sc16_t( + std::rand()-(RAND_MAX/2), + std::rand()-(RAND_MAX/2) + ); + + //run the loopback and test + loopback(nsamps, io_type, otw_type, input, output); + BOOST_CHECK_EQUAL_COLLECTIONS(input.begin(), input.end(), output.begin(), output.end()); +} + +BOOST_AUTO_TEST_CASE(test_convert_types_be_sc16){ + io_type_t io_type(io_type_t::COMPLEX_INT16); + otw_type_t otw_type; + otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; + otw_type.width = 16; + + //try various lengths to test edge cases + for (size_t nsamps = 1; nsamps < 16; nsamps++){ + test_convert_types_sc16(nsamps, io_type, otw_type); + } +} + +BOOST_AUTO_TEST_CASE(test_convert_types_le_sc16){ + io_type_t io_type(io_type_t::COMPLEX_INT16); + otw_type_t otw_type; + otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; + otw_type.width = 16; + + //try various lengths to test edge cases + for (size_t nsamps = 1; nsamps < 16; nsamps++){ + test_convert_types_sc16(nsamps, io_type, otw_type); + } +} + +/*********************************************************************** + * Test float conversion + **********************************************************************/ +template <typename data_type> +static void test_convert_types_for_floats( + size_t nsamps, + const io_type_t &io_type, + const otw_type_t &otw_type +){ + 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, + (std::rand()/value_type(RAND_MAX/2)) - 1 + ); + + //run the loopback and test + loopback(nsamps, io_type, otw_type, input, output); + for (size_t i = 0; i < nsamps; i++){ + MY_CHECK_CLOSE(input[i].real(), output[i].real(), value_type(0.01)); + MY_CHECK_CLOSE(input[i].imag(), output[i].imag(), value_type(0.01)); + } +} + +BOOST_AUTO_TEST_CASE(test_convert_types_be_fc32){ + io_type_t io_type(io_type_t::COMPLEX_FLOAT32); + otw_type_t otw_type; + otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; + otw_type.width = 16; + + //try various lengths to test edge cases + for (size_t nsamps = 1; nsamps < 16; nsamps++){ + test_convert_types_for_floats<fc32_t>(nsamps, io_type, otw_type); + } +} + +BOOST_AUTO_TEST_CASE(test_convert_types_le_fc32){ + io_type_t io_type(io_type_t::COMPLEX_FLOAT32); + otw_type_t otw_type; + otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; + otw_type.width = 16; + + //try various lengths to test edge cases + for (size_t nsamps = 1; nsamps < 16; nsamps++){ + test_convert_types_for_floats<fc32_t>(nsamps, io_type, otw_type); + } +} + +BOOST_AUTO_TEST_CASE(test_convert_types_be_fc64){ + io_type_t io_type(io_type_t::COMPLEX_FLOAT64); + otw_type_t otw_type; + otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; + otw_type.width = 16; + + //try various lengths to test edge cases + for (size_t nsamps = 1; nsamps < 16; nsamps++){ + test_convert_types_for_floats<fc64_t>(nsamps, io_type, otw_type); + } +} + +BOOST_AUTO_TEST_CASE(test_convert_types_le_fc64){ + io_type_t io_type(io_type_t::COMPLEX_FLOAT64); + otw_type_t otw_type; + otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; + otw_type.width = 16; + + //try various lengths to test edge cases + for (size_t nsamps = 1; nsamps < 16; nsamps++){ + test_convert_types_for_floats<fc64_t>(nsamps, io_type, otw_type); + } +} + +/*********************************************************************** + * Test float to short conversion loopback + **********************************************************************/ +BOOST_AUTO_TEST_CASE(test_convert_types_fc32_to_sc16){ + io_type_t io_type_in(io_type_t::COMPLEX_FLOAT32); + io_type_t io_type_out(io_type_t::COMPLEX_INT16); + + otw_type_t otw_type; + otw_type.byteorder = otw_type_t::BO_NATIVE; + otw_type.width = 16; + + 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::get_converter_cpu_to_otw( + io_type_in, otw_type, input0.size(), output0.size() + )(input0, output0, nsamps, 32767.); + + //convert intermediate to short + convert::get_converter_otw_to_cpu( + io_type_out, otw_type, input1.size(), output1.size() + )(input1, output1, nsamps, 1/32767.); + + //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){ + io_type_t io_type_in(io_type_t::COMPLEX_INT16); + io_type_t io_type_out(io_type_t::COMPLEX_FLOAT32); + + otw_type_t otw_type; + otw_type.byteorder = otw_type_t::BO_NATIVE; + otw_type.width = 16; + + 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::get_converter_cpu_to_otw( + io_type_in, otw_type, input0.size(), output0.size() + )(input0, output0, nsamps, 32767.); + + //convert intermediate to float + convert::get_converter_otw_to_cpu( + io_type_out, otw_type, input1.size(), output1.size() + )(input1, output1, nsamps, 1/32767.); + + //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)); + } +} 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..983f0150c --- /dev/null +++ b/host/tests/error_test.cpp @@ -0,0 +1,59 @@ +// +// 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; + } +} 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..c05139ea9 --- /dev/null +++ b/host/tests/msg_test.cpp @@ -0,0 +1,37 @@ +// +// 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" + ; + std::cerr << "---end print test ---" << std::endl; +} diff --git a/host/tests/ranges_test.cpp b/host/tests/ranges_test.cpp new file mode 100644 index 000000000..5f6de4645 --- /dev/null +++ b/host/tests/ranges_test.cpp @@ -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/>. +// + +#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); +} diff --git a/host/tests/sph_recv_test.cpp b/host/tests/sph_recv_test.cpp new file mode 100644 index 000000000..6bb5d1175 --- /dev/null +++ b/host/tests/sph_recv_test.cpp @@ -0,0 +1,715 @@ +// +// 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 "../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 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 uhd::otw_type_t &otw_type){ + _otw_type = otw_type; + } + + 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 (_otw_type.byteorder == uhd::otw_type_t::BO_BIG_ENDIAN){ + uhd::transport::vrt::if_hdr_pack_be(reinterpret_cast<boost::uint32_t *>(_mems.back().get()), ifpi); + } + if (_otw_type.byteorder == uhd::otw_type_t::BO_LITTLE_ENDIAN){ + 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 + uhd::otw_type_t _otw_type; +}; + +//////////////////////////////////////////////////////////////////////// +BOOST_AUTO_TEST_CASE(test_sph_recv_one_channel_normal){ +//////////////////////////////////////////////////////////////////////// + uhd::otw_type_t otw_type; + otw_type.width = 16; + otw_type.shift = 0; + otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; + + dummy_recv_xport_class dummy_recv_xport(otw_type); + 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(otw_type); + + //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, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::RECV_MODE_ONE_PACKET, 1.0 + ); + 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(0, 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, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::RECV_MODE_ONE_PACKET, 1.0 + ); + 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::otw_type_t otw_type; + otw_type.width = 16; + otw_type.shift = 0; + otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; + + dummy_recv_xport_class dummy_recv_xport(otw_type); + 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(otw_type); + + //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, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::RECV_MODE_ONE_PACKET, 1.0 + ); + 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(0, 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(0, 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, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::RECV_MODE_ONE_PACKET, 1.0 + ); + 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::otw_type_t otw_type; + otw_type.width = 16; + otw_type.shift = 0; + otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; + + dummy_recv_xport_class dummy_recv_xport(otw_type); + 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); + + //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); + ifpi.packet_count++; + ifpi.packet_type = uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_DATA; + } + } + + //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(otw_type); + + //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, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::RECV_MODE_ONE_PACKET, 1.0 + ); + 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(0, 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, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::RECV_MODE_ONE_PACKET, 1.0 + ); + 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(0, num_accum_samps, SAMP_RATE)); + } + } + + //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, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::RECV_MODE_ONE_PACKET, 1.0 + ); + BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_TIMEOUT); + } +} + +//////////////////////////////////////////////////////////////////////// +BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_normal){ +//////////////////////////////////////////////////////////////////////// + uhd::otw_type_t otw_type; + otw_type.width = 16; + otw_type.shift = 0; + otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; + + 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(otw_type)); + + //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(otw_type); + + //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, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::RECV_MODE_ONE_PACKET, 1.0 + ); + 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(0, 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, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::RECV_MODE_ONE_PACKET, 1.0 + ); + 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::otw_type_t otw_type; + otw_type.width = 16; + otw_type.shift = 0; + otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; + + 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(otw_type)); + + //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(otw_type); + + //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, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::RECV_MODE_ONE_PACKET, 1.0 + ); + 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(0, 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(0, 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, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::RECV_MODE_ONE_PACKET, 1.0 + ); + 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::otw_type_t otw_type; + otw_type.width = 16; + otw_type.shift = 0; + otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; + + 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(otw_type)); + + //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(otw_type); + + //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, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::RECV_MODE_ONE_PACKET, 1.0 + ); + 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(0, 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, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::RECV_MODE_ONE_PACKET, 1.0 + ); + BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_TIMEOUT); + } +} + +//////////////////////////////////////////////////////////////////////// +BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_fragment){ +//////////////////////////////////////////////////////////////////////// + uhd::otw_type_t otw_type; + otw_type.width = 16; + otw_type.shift = 0; + otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; + + 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(otw_type)); + + //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(otw_type); + + //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, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::RECV_MODE_ONE_PACKET, 1.0 + ); + 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(0, 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, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::RECV_MODE_ONE_PACKET, 1.0 + ); + 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(0, 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, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::RECV_MODE_ONE_PACKET, 1.0 + ); + 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..ed2f54371 --- /dev/null +++ b/host/tests/sph_send_test.cpp @@ -0,0 +1,204 @@ +// +// 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 "../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 uhd::otw_type_t &otw_type){ + _otw_type = otw_type; + } + + void pop_front_packet( + uhd::transport::vrt::if_packet_info_t &ifpi + ){ + ifpi.num_packet_words32 = _lens.front()/sizeof(boost::uint32_t); + if (_otw_type.byteorder == uhd::otw_type_t::BO_BIG_ENDIAN){ + uhd::transport::vrt::if_hdr_unpack_be(reinterpret_cast<boost::uint32_t *>(_mems.front().get()), ifpi); + } + if (_otw_type.byteorder == uhd::otw_type_t::BO_LITTLE_ENDIAN){ + 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 + uhd::otw_type_t _otw_type; +}; + +//////////////////////////////////////////////////////////////////////// +BOOST_AUTO_TEST_CASE(test_sph_send_one_channel_one_packet_mode){ +//////////////////////////////////////////////////////////////////////// + uhd::otw_type_t otw_type; + otw_type.width = 16; + otw_type.shift = 0; + otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; + + dummy_send_xport_class dummy_send_xport(otw_type); + + 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(otw_type); + 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, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::SEND_MODE_ONE_PACKET, 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_tsi); + BOOST_CHECK(ifpi.has_tsf); + BOOST_CHECK_EQUAL(ifpi.tsi, 0); + 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::otw_type_t otw_type; + otw_type.width = 16; + otw_type.shift = 0; + otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; + + dummy_send_xport_class dummy_send_xport(otw_type); + + 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(otw_type); + 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, + uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::SEND_MODE_FULL_BUFF, 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_tsi); + BOOST_CHECK(ifpi.has_tsf); + BOOST_CHECK_EQUAL(ifpi.tsi, 0); + 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..e57bbced1 --- /dev/null +++ b/host/tests/time_spec_test.cpp @@ -0,0 +1,80 @@ +// +// 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/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).get_tick_count(100), 10); + + 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).get_tick_count(100), -10); +} + +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 +} diff --git a/host/tests/tune_helper_test.cpp b/host/tests/tune_helper_test.cpp new file mode 100644 index 000000000..9147cd310 --- /dev/null +++ b/host/tests/tune_helper_test.cpp @@ -0,0 +1,251 @@ +// +// 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/tune_helper.hpp> +#include <uhd/usrp/subdev_props.hpp> +#include <uhd/usrp/dsp_props.hpp> +#include <uhd/usrp/dsp_utils.hpp> +#include <iostream> + +using namespace uhd; +using namespace uhd::usrp; + +/*********************************************************************** + * Dummy properties objects + **********************************************************************/ +class dummy_subdev : public wax::obj{ +public: + dummy_subdev(double resolution): + _resolution(resolution) + { + /* NOP */ + } +private: + void get(const wax::obj &key, wax::obj &val){ + switch(key.as<subdev_prop_t>()){ + + case SUBDEV_PROP_FREQ: + val = _freq; + return; + + case SUBDEV_PROP_USE_LO_OFFSET: + val = false; + return; + + default: UHD_THROW_PROP_GET_ERROR(); + } + } + + void set(const wax::obj &key, const wax::obj &val){ + switch(key.as<subdev_prop_t>()){ + case SUBDEV_PROP_FREQ: + _freq = _resolution*int(val.as<double>()/_resolution); + return; + + default: UHD_THROW_PROP_SET_ERROR(); + } + } + + double _freq, _resolution; +}; + +class dummy_subdev_basic : public wax::obj{ +private: + void get(const wax::obj &key, wax::obj &val){ + switch(key.as<subdev_prop_t>()){ + + case SUBDEV_PROP_FREQ: + val = double(0.0); //always zero + return; + + case SUBDEV_PROP_USE_LO_OFFSET: + val = false; + return; + + default: UHD_THROW_PROP_GET_ERROR(); + } + } + + void set(const wax::obj &key, const wax::obj &){ + switch(key.as<subdev_prop_t>()){ + case SUBDEV_PROP_FREQ: + // do nothing + return; + + default: UHD_THROW_PROP_SET_ERROR(); + } + } +}; + +class dummy_subdev_bw : public wax::obj{ +private: + void get(const wax::obj &key, wax::obj &val){ + switch(key.as<subdev_prop_t>()){ + + case SUBDEV_PROP_FREQ: + val = _freq; + return; + + case SUBDEV_PROP_USE_LO_OFFSET: + val = true; + return; + + case SUBDEV_PROP_BANDWIDTH: + val = _bandwidth; + return; + + default: UHD_THROW_PROP_GET_ERROR(); + } + } + + void set(const wax::obj &key, const wax::obj &val){ + switch(key.as<subdev_prop_t>()){ + case SUBDEV_PROP_FREQ: + _freq = val.as<double>(); + return; + + case SUBDEV_PROP_BANDWIDTH: + _bandwidth = val.as<double>(); + return; + + default: UHD_THROW_PROP_SET_ERROR(); + } + } + + double _freq, _bandwidth; +}; + +class dummy_dsp : public wax::obj{ +public: + dummy_dsp(double codec_rate): + _codec_rate(codec_rate) + { + /* NOP */ + } +private: + void get(const wax::obj &key_, wax::obj &val){ + named_prop_t key = named_prop_t::extract(key_); + switch(key.as<dsp_prop_t>()){ + case DSP_PROP_CODEC_RATE: + val = _codec_rate; + return; + + case DSP_PROP_HOST_RATE: + val = _host_rate; + return; + + case DSP_PROP_FREQ_SHIFT: + val = _freq_shift; + return; + + default: UHD_THROW_PROP_GET_ERROR(); + } + } + + void set(const wax::obj &key_, const wax::obj &val){ + named_prop_t key = named_prop_t::extract(key_); + switch(key.as<dsp_prop_t>()){ + case DSP_PROP_FREQ_SHIFT: + _freq_shift = val.as<double>(); + dsp_type1::calc_cordic_word_and_update(_freq_shift, _codec_rate); + return; + + case DSP_PROP_HOST_RATE: + _host_rate = val.as<double>(); + return; + + default: UHD_THROW_PROP_SET_ERROR(); + } + } + + double _codec_rate, _freq_shift, _host_rate; +}; + +/*********************************************************************** + * Test cases + **********************************************************************/ +static const double tolerance = 0.001; + +BOOST_AUTO_TEST_CASE(test_tune_helper_rx){ + dummy_subdev subdev(1e6); + dummy_dsp dsp(100e6); + + std::cout << "Testing tune helper RX automatic IF offset" << std::endl; + tune_result_t tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.3451e9); + std::cout << tr.to_pp_string() << std::endl; + BOOST_CHECK_CLOSE(tr.actual_rf_freq, 2.345e9, tolerance); + BOOST_CHECK_CLOSE(tr.actual_dsp_freq, -100e3, tolerance); + + double freq_derived = derive_freq_from_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link()); + BOOST_CHECK_CLOSE(freq_derived, 2.3451e9, tolerance); +} + +BOOST_AUTO_TEST_CASE(test_tune_helper_tx){ + dummy_subdev subdev(1e6); + dummy_dsp dsp(100e6); + + std::cout << "Testing tune helper TX automatic IF offset" << std::endl; + tune_result_t tr = tune_tx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.3451e9); + std::cout << tr.to_pp_string() << std::endl; + BOOST_CHECK_CLOSE(tr.actual_rf_freq, 2.345e9, tolerance); + BOOST_CHECK_CLOSE(tr.actual_dsp_freq, 100e3, tolerance); + + double freq_derived = derive_freq_from_tx_subdev_and_dsp(subdev.get_link(), dsp.get_link()); + BOOST_CHECK_CLOSE(freq_derived, 2.3451e9, tolerance); +} + +BOOST_AUTO_TEST_CASE(test_tune_helper_rx_nyquist){ + dummy_subdev_basic subdev; + dummy_dsp dsp(100e6); + + std::cout << "Testing tune helper RX dummy basic board" << std::endl; + tune_result_t tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 55e6); + std::cout << tr.to_pp_string() << std::endl; + BOOST_CHECK_CLOSE(tr.actual_rf_freq, 0.0, tolerance); + BOOST_CHECK_CLOSE(tr.actual_dsp_freq, 45e6, tolerance); + + double freq_derived = derive_freq_from_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link()); + BOOST_CHECK_CLOSE(freq_derived, -45e6, tolerance); +} + +BOOST_AUTO_TEST_CASE(test_tune_helper_rx_lo_off){ + dummy_subdev_bw subdev; + dummy_dsp dsp(100e6); + tune_result_t tr; + + std::cout << "Testing tune helper RX automatic LO offset B >> fs" << std::endl; + subdev[SUBDEV_PROP_BANDWIDTH] = double(40e6); + dsp[DSP_PROP_HOST_RATE] = double(4e6); + tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.45e9); + std::cout << tr.to_pp_string() << std::endl; + BOOST_CHECK_CLOSE(tr.actual_rf_freq, 2.45e9+4e6/2, tolerance); + + std::cout << "Testing tune helper RX automatic LO offset B > fs" << std::endl; + subdev[SUBDEV_PROP_BANDWIDTH] = double(40e6); + dsp[DSP_PROP_HOST_RATE] = double(25e6); + tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.45e9); + std::cout << tr.to_pp_string() << std::endl; + BOOST_CHECK_CLOSE(tr.actual_rf_freq, 2.45e9+(40e6-25e6)/2, tolerance); + + std::cout << "Testing tune helper RX automatic LO offset B < fs" << std::endl; + subdev[SUBDEV_PROP_BANDWIDTH] = double(20e6); + dsp[DSP_PROP_HOST_RATE] = double(25e6); + tr = tune_rx_subdev_and_dsp(subdev.get_link(), dsp.get_link(), 2.45e9); + std::cout << tr.to_pp_string() << std::endl; + BOOST_CHECK_CLOSE(tr.actual_rf_freq, 2.45e9, tolerance); +} 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); +} diff --git a/host/tests/wax_test.cpp b/host/tests/wax_test.cpp new file mode 100644 index 000000000..18730e0c2 --- /dev/null +++ b/host/tests/wax_test.cpp @@ -0,0 +1,104 @@ +// +// 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 <boost/shared_ptr.hpp> +#include <uhd/wax.hpp> +#include <iostream> + +enum opt_a_t{OPTION_A_0, OPTION_A_1}; +enum opt_b_t{OPTION_B_0, OPTION_B_1}; + +BOOST_AUTO_TEST_CASE(test_enums){ + wax::obj opta = OPTION_A_0; + BOOST_CHECK_THROW(opta.as<opt_b_t>(), std::exception); + BOOST_CHECK_EQUAL(opta.as<opt_a_t>(), OPTION_A_0); +} + +/*********************************************************************** + * demo class for wax framework + **********************************************************************/ +class wax_demo : public wax::obj{ +public: + typedef boost::shared_ptr<wax_demo> sptr; + + wax_demo(size_t sub_demos, size_t len){ + d_nums = std::vector<float>(len); + if (sub_demos != 0){ + for (size_t i = 0; i < len; i++){ + d_subs.push_back(sptr(new wax_demo(sub_demos-1, len))); + } + } + } + ~wax_demo(void){ + /* NOP */ + } +private: + std::vector<float> d_nums; + std::vector<sptr> d_subs; + + void get(const wax::obj &key, wax::obj &value){ + if (d_subs.size() == 0){ + value = d_nums[key.as<size_t>()]; + }else{ + value = d_subs[key.as<size_t>()]->get_link(); + } + } + void set(const wax::obj &key, const wax::obj &value){ + if (d_subs.size() == 0){ + d_nums[key.as<size_t>()] = value.as<float>(); + }else{ + throw std::runtime_error("cant set to a wax demo with sub demos"); + } + } +}; + +BOOST_AUTO_TEST_CASE(test_chaining){ + wax_demo wd(2, 1); + std::cout << "chain 1" << std::endl; + wd[size_t(0)]; + std::cout << "chain 2" << std::endl; + wd[size_t(0)][size_t(0)]; + std::cout << "chain 3" << std::endl; + wd[size_t(0)][size_t(0)][size_t(0)]; +} + +BOOST_AUTO_TEST_CASE(test_set_get){ + wax_demo wd(2, 10); + std::cout << "set and get all" << std::endl; + for (size_t i = 0; i < 10; i++){ + for (size_t j = 0; j < 10; j++){ + for (size_t k = 0; k < 10; k++){ + float val = float(i * j * k + i + j + k); + //std::cout << i << " " << j << " " << k << std::endl; + wd[i][j][k] = val; + BOOST_CHECK_EQUAL(val, wd[i][j][k].as<float>()); + } + } + } +} + +BOOST_AUTO_TEST_CASE(test_proxy){ + wax_demo wd(2, 1); + std::cout << "store proxy" << std::endl; + wax::obj p = wd[size_t(0)][size_t(0)]; + p[size_t(0)] = float(5); + + std::cout << "assign proxy" << std::endl; + wax::obj a = p[size_t(0)]; + BOOST_CHECK_EQUAL(a.as<float>(), float(5)); +} |