summaryrefslogtreecommitdiffstats
path: root/host/tests
diff options
context:
space:
mode:
Diffstat (limited to 'host/tests')
-rw-r--r--host/tests/CMakeLists.txt2
-rw-r--r--host/tests/sph_recv_test.cpp715
-rw-r--r--host/tests/sph_send_test.cpp204
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;
+ }
+}