diff options
Diffstat (limited to 'host/tests')
| -rw-r--r-- | host/tests/CMakeLists.txt | 57 | ||||
| -rw-r--r-- | host/tests/addr_test.cpp | 81 | ||||
| -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 | 357 | ||||
| -rw-r--r-- | host/tests/dict_test.cpp | 72 | ||||
| -rw-r--r-- | host/tests/error_test.cpp | 93 | ||||
| -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 | 40 | ||||
| -rw-r--r-- | host/tests/property_test.cpp | 175 | ||||
| -rw-r--r-- | host/tests/ranges_test.cpp | 70 | ||||
| -rw-r--r-- | host/tests/sph_recv_test.cpp | 702 | ||||
| -rw-r--r-- | host/tests/sph_send_test.cpp | 192 | ||||
| -rw-r--r-- | host/tests/subdev_spec_test.cpp | 45 | ||||
| -rw-r--r-- | host/tests/time_spec_test.cpp | 99 | ||||
| -rw-r--r-- | host/tests/vrt_test.cpp | 141 | 
17 files changed, 2375 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..4b0226e3d --- /dev/null +++ b/host/tests/convert_test.cpp @@ -0,0 +1,357 @@ +// +// 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 <boost/assign/list_of.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, +    const int prio_in = -1, +    const int prio_out = -1 +){ +    //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, prio_in)(); +    c0->set_scalar(32767.); +    c0->conv(input0, output0, nsamps); + +    //convert back to host type +    convert::converter::sptr c1 = convert::get_converter(out_id, prio_out)(); +    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); + +    //make a list of all prio: best/generic combos +    typedef std::pair<int, int> int_pair_t; +    std::vector<int_pair_t> prios = boost::assign::list_of +        (int_pair_t(0, 0)) (int_pair_t(-1, 0)) +        (int_pair_t(0, -1)) (int_pair_t(-1, -1)) +    ; + +    //loopback foreach prio combo (generic vs best) +    BOOST_FOREACH(const int_pair_t &prio, prios){ +        loopback(nsamps, in_id, out_id, input, output, prio.first, prio.second); +        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..5a40029dc --- /dev/null +++ b/host/tests/sph_recv_test.cpp @@ -0,0 +1,702 @@ +// +// 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; +        return make(this, _mem.get(), len); +    } + +private: +    boost::shared_array<char> _mem; +}; + +/*********************************************************************** + * 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(boost::shared_ptr<dummy_mrb>(new 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::vector<boost::shared_ptr<dummy_mrb> > _mrbs; +    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..603b36c85 --- /dev/null +++ b/host/tests/sph_send_test.cpp @@ -0,0 +1,192 @@ +// +// 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 release(void){ +        //NOP +    } + +    sptr get_new(boost::shared_array<char> mem, size_t *len){ +        _mem = mem; +        return make(this, mem.get(), *len); +    } + +private: +    boost::shared_array<char> _mem; +}; + +/*********************************************************************** + * 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(boost::shared_ptr<dummy_msb>(new 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::vector<boost::shared_ptr<dummy_msb> > _msbs; +    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); +} | 
