diff options
Diffstat (limited to 'host/tests')
| -rw-r--r-- | host/tests/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | host/tests/sph_recv_test.cpp | 715 | ||||
| -rw-r--r-- | host/tests/sph_send_test.cpp | 204 | 
3 files changed, 921 insertions, 0 deletions
diff --git a/host/tests/CMakeLists.txt b/host/tests/CMakeLists.txt index b38afccf0..b7bcfb7d5 100644 --- a/host/tests/CMakeLists.txt +++ b/host/tests/CMakeLists.txt @@ -28,6 +28,8 @@ SET(test_sources      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 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; +    } +}  | 
