diff options
Diffstat (limited to 'host/tests/sph_recv_test.cpp')
-rw-r--r-- | host/tests/sph_recv_test.cpp | 732 |
1 files changed, 732 insertions, 0 deletions
diff --git a/host/tests/sph_recv_test.cpp b/host/tests/sph_recv_test.cpp new file mode 100644 index 000000000..1387e3b66 --- /dev/null +++ b/host/tests/sph_recv_test.cpp @@ -0,0 +1,732 @@ +// +// 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 overflow handler for testing + **********************************************************************/ +struct overflow_handler_type{ + overflow_handler_type(void){ + num_overflow = 0; + } + void handle(void){ + num_overflow++; + } + size_t num_overflow; +}; + +/*********************************************************************** + * A dummy managed receive buffer for testing + **********************************************************************/ +class dummy_mrb : public uhd::transport::managed_recv_buffer{ +public: + void release(void){ + //NOP + } + + sptr get_new(boost::shared_array<char> mem, size_t len){ + _mem = mem; + _len = len; + return make_managed_buffer(this); + } + +private: + const void *get_buff(void) const{return _mem.get();} + size_t get_size(void) const{return _len;} + + boost::shared_array<char> _mem; + size_t _len; +}; + +/*********************************************************************** + * A dummy transport class to fill with fake data + **********************************************************************/ +class dummy_recv_xport_class{ +public: + dummy_recv_xport_class(const 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.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(otw_type); + + //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, + 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)); + 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, + 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); + } + +} |