diff options
Diffstat (limited to 'host/tests/tx_streamer_test.cpp')
-rw-r--r-- | host/tests/tx_streamer_test.cpp | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/host/tests/tx_streamer_test.cpp b/host/tests/tx_streamer_test.cpp index 09c8357df..2288bd029 100644 --- a/host/tests/tx_streamer_test.cpp +++ b/host/tests/tx_streamer_test.cpp @@ -26,6 +26,7 @@ public: struct packet_info_t { bool eob = false; + bool eov = false; bool has_tsf = false; uint64_t tsf = 0; size_t payload_bytes = 0; @@ -158,6 +159,34 @@ pop_send_packet(mock_send_link::sptr send_link) return std::make_tuple(info, data, packet_samps, packet.first); } +//! Generates a non-biased random number in the range (low, high). +static size_t generate_rand(size_t low, size_t high) +{ + return (std::rand() % (high - low + 1)) + low; +} + +/*! + * Generates a vector of legal random EOV positions. + * `eovs` is a vector already sized to the desired number of EOV positions. + * The range [1, num_samps) will be broken into N=`eov.size()` + * non-overlapping adjacent ranges, and a random value within each range will + * be generated and stored in the vector. + */ +static void generate_random_eov_positions( + std::vector<size_t>& eovs, const size_t num_samps) +{ + UHD_ASSERT_THROW(!eovs.empty()); + + const size_t num_eovs = eovs.size(); + const size_t range_size = (num_samps - 1) / num_eovs; + size_t low = 1; + for (size_t i = 0; i < num_eovs; i++) { + const size_t high = low + range_size - 1; + eovs[i] = generate_rand(low, high); + low = high + 1; + } +} + /*! * Tests */ @@ -216,6 +245,250 @@ BOOST_AUTO_TEST_CASE(test_send_one_channel_one_packet) } } +BOOST_AUTO_TEST_CASE(test_send_one_channel_eov_lte_spp) +{ + const size_t NUM_PKTS_TO_TEST = 30; + const std::string format("fc32"); + + auto send_links = make_links(1); + auto streamer = make_tx_streamer(send_links, format); + + // Allocate metadata + uhd::tx_metadata_t metadata; + metadata.has_time_spec = true; + metadata.time_spec = uhd::time_spec_t(0.0); + + // Allocate buffer + const size_t num_samps = streamer->get_max_num_samps(); + std::vector<std::complex<float>> buff(num_samps); + + // Send buffer and check resultant packets + size_t num_accum_samps = 0; + + for (size_t i = 0; i < NUM_PKTS_TO_TEST; i++) { + std::cout << "sending packet " << i << std::endl; + + // Vary number of EOVs for each send + const size_t num_eovs = (i % 10) + 1; + std::vector<size_t> eovs(num_eovs); + generate_random_eov_positions(eovs, num_samps); + + metadata.eov_positions = eovs.data(); + metadata.eov_positions_size = eovs.size(); + + const size_t num_sent = streamer->send(&buff.front(), num_samps, metadata, 1.0); + BOOST_CHECK_EQUAL(num_sent, num_samps); + metadata.time_spec += uhd::time_spec_t(0, num_sent, SAMP_RATE); + + mock_tx_data_xport::packet_info_t info; + std::complex<uint16_t>* data; + size_t packet_samps; + boost::shared_array<uint8_t> frame_buff; + + // Check number of packets written (should be # of EOVs plus one) + size_t num_packets_written = send_links[0]->get_num_packets(); + BOOST_CHECK_EQUAL(num_packets_written, eovs.size() + 1); + + // Pop each packets and check size of each relative to EOV positions + size_t total_samps_popped = 0; + size_t eov_index = 0; + size_t last_eov_position = 0; + while (total_samps_popped < num_samps) { + std::tie(info, data, packet_samps, frame_buff) = + pop_send_packet(send_links[0]); + + // All but the last packet should have an EOV indication + if (eov_index < eovs.size()) { + BOOST_CHECK_EQUAL(eovs[eov_index] - last_eov_position, packet_samps); + BOOST_CHECK(info.eov); + last_eov_position = eovs[eov_index]; + } else { + BOOST_CHECK_EQUAL(num_samps - last_eov_position, packet_samps); + BOOST_CHECK(not info.eov); + } + + // Verify correctness of TSF data + BOOST_CHECK(info.has_tsf); + BOOST_CHECK_EQUAL(info.tsf, num_accum_samps * TICK_RATE / SAMP_RATE); + + eov_index++; + num_accum_samps += packet_samps; + total_samps_popped += packet_samps; + } + } +} + +BOOST_AUTO_TEST_CASE(test_send_one_channel_eov_gt_spp) +{ + const size_t NUM_PKTS_TO_TEST = 30; + const std::string format("fc32"); + + auto send_links = make_links(1); + auto streamer = make_tx_streamer(send_links, format); + + // Allocate metadata + uhd::tx_metadata_t metadata; + metadata.has_time_spec = true; + metadata.time_spec = uhd::time_spec_t(0.0); + + // Allocate buffer + const size_t spp = streamer->get_max_num_samps(); + const size_t num_samps = spp * 50; + std::vector<std::complex<float>> buff(num_samps); + + // Send buffer and check resultant packets + size_t num_accum_samps = 0; + + for (size_t i = 0; i < NUM_PKTS_TO_TEST; i++) { + std::cout << "sending packet " << i << std::endl; + + // Vary number of EOVs for each send + const size_t num_eovs = (i % 5) + 1; + std::vector<size_t> eovs(num_eovs); + generate_random_eov_positions(eovs, num_samps); + + metadata.eov_positions = eovs.data(); + metadata.eov_positions_size = eovs.size(); + + const size_t num_sent = streamer->send(&buff.front(), num_samps, metadata, 1.0); + BOOST_CHECK_EQUAL(num_sent, num_samps); + metadata.time_spec += uhd::time_spec_t(0, num_sent, SAMP_RATE); + + mock_tx_data_xport::packet_info_t info; + std::complex<uint16_t>* data; + size_t packet_samps; + boost::shared_array<uint8_t> frame_buff; + + size_t total_samps_popped = 0; + size_t eov_index = 0; + size_t last_eov_position = 0; + size_t distance_to_next_eov = eovs[eov_index] - last_eov_position; + size_t distance_to_end = num_samps; + while (total_samps_popped < num_samps) { + std::tie(info, data, packet_samps, frame_buff) = + pop_send_packet(send_links[0]); + + if (distance_to_next_eov <= spp) { + // Next EOV is within a single SPP: ensure packet is EOV + BOOST_CHECK_EQUAL(distance_to_next_eov, packet_samps); + BOOST_CHECK(info.eov); + last_eov_position = eovs[eov_index]; + eov_index++; + if (eov_index < eovs.size()) { + // NOTE: Addition of `packet_samps` is to compensate for + // its subtraction below + distance_to_next_eov = + eovs[eov_index] - last_eov_position + packet_samps; + } else { + // No more EOVs + distance_to_next_eov = std::numeric_limits<size_t>::max(); + } + } else if (distance_to_end <= spp) { + // End of data within a single SPP + BOOST_CHECK_EQUAL(distance_to_end, packet_samps); + BOOST_CHECK(not info.eov); + } else { + BOOST_CHECK(not info.eov); + } + + // Verify correctness of TSF data + BOOST_CHECK(info.has_tsf); + BOOST_CHECK_EQUAL(info.tsf, num_accum_samps * TICK_RATE / SAMP_RATE); + + distance_to_end -= packet_samps; + distance_to_next_eov -= packet_samps; + total_samps_popped += packet_samps; + num_accum_samps += packet_samps; + } + } +} + +BOOST_AUTO_TEST_CASE(test_send_one_channel_eov_corner_case) +{ + const std::string format("fc32"); + + auto send_links = make_links(1); + auto streamer = make_tx_streamer(send_links, format); + + // Allocate metadata + uhd::tx_metadata_t metadata; + metadata.has_time_spec = true; + metadata.time_spec = uhd::time_spec_t(0.0); + + // Allocate buffer + const size_t spp = streamer->get_max_num_samps(); + const size_t num_samps = spp * 2; + std::vector<std::complex<float>> buff(num_samps); + + // Mark every sample as an EOV :D + std::vector<size_t> eovs(num_samps); + for (size_t i = 0; i < num_samps; i++) { + eovs[i] = i + 1; + } + + metadata.eov_positions = eovs.data(); + metadata.eov_positions_size = eovs.size(); + + const size_t num_sent = streamer->send(&buff.front(), num_samps, metadata, 1.0); + BOOST_CHECK_EQUAL(num_sent, num_samps); + + mock_tx_data_xport::packet_info_t info; + std::complex<uint16_t>* data; + size_t packet_samps; + boost::shared_array<uint8_t> frame_buff; + + // Check all packets for EOV + BOOST_CHECK_EQUAL(send_links[0]->get_num_packets(), num_samps); + + for (size_t i = 0; i < num_samps; i++) { + std::tie(info, data, packet_samps, frame_buff) = pop_send_packet(send_links[0]); + BOOST_CHECK_EQUAL(packet_samps, 1); + BOOST_CHECK(info.eov); + } +} + +BOOST_AUTO_TEST_CASE(test_send_one_channel_eov_error_cases) +{ + const std::string format("fc32"); + + auto send_links = make_links(1); + auto streamer = make_tx_streamer(send_links, format); + + uhd::tx_metadata_t metadata; + metadata.has_time_spec = true; + metadata.time_spec = uhd::time_spec_t(0.0); + + const size_t spp = streamer->get_max_num_samps(); + const size_t num_samps = spp; + std::vector<std::complex<float>> buff(num_samps); + + // Error case: EOV of 0 + size_t eov = 0; + metadata.eov_positions = &eov; + metadata.eov_positions_size = 1; + + BOOST_CHECK_THROW( + streamer->send(&buff.front(), num_samps, metadata, 1.0), uhd::value_error); + + // Error case: Adjacent EOV values that are the same + std::vector<size_t> eovs{100, 100}; + metadata.eov_positions = eovs.data(); + metadata.eov_positions_size = eovs.size(); + + BOOST_CHECK_THROW( + streamer->send(&buff.front(), num_samps, metadata, 1.0), uhd::value_error); + + // Error case: EOV values not monotonically increasing + eovs = {50, 25}; + + BOOST_CHECK_THROW( + streamer->send(&buff.front(), num_samps, metadata, 1.0), uhd::value_error); + + // Error case: EOV values greater than nsamps_per_buff + BOOST_CHECK_THROW( + streamer->send(&buff.front(), 1, metadata, 1.0), uhd::value_error); +} + BOOST_AUTO_TEST_CASE(test_send_one_channel_multi_packet) { const size_t NUM_BUFFS_TO_TEST = 5; |