From 35c6d742977fa03e840d70951c0a136720d8a2d0 Mon Sep 17 00:00:00 2001 From: DaulPavid Date: Tue, 9 Feb 2016 14:17:43 -0800 Subject: Corrected the UHD behavior in the event of a USB disconnect --- host/examples/benchmark_rate.cpp | 6 ++ host/lib/transport/libusb1_zero_copy.cpp | 4 +- host/lib/transport/super_recv_packet_handler.hpp | 6 +- host/tests/sph_recv_test.cpp | 115 ++++++++++++++++++++++- 4 files changed, 125 insertions(+), 6 deletions(-) diff --git a/host/examples/benchmark_rate.cpp b/host/examples/benchmark_rate.cpp index cc3ef04a4..f8c0342c0 100644 --- a/host/examples/benchmark_rate.cpp +++ b/host/examples/benchmark_rate.cpp @@ -80,6 +80,12 @@ void benchmark_rx_rate( try { num_rx_samps += rx_stream->recv(buffs, max_samps_per_packet, md)*rx_stream->get_num_channels(); } + catch (uhd::io_error &e) { + std::cerr << "Caught an IO exception. " << std::endl; + std::cerr << e.what() << std::endl; + + return; + } catch (...) { /* apparently, the boost thread interruption can sometimes result in throwing exceptions not of type boost::exception, this catch allows diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index b67b36d0a..53e345009 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -149,8 +149,8 @@ public: if (wait_for_completion(timeout)) { if (result.status != LIBUSB_TRANSFER_COMPLETED) - throw uhd::runtime_error(str(boost::format("usb %s transfer status: %d") - % _name % libusb_error_name(result.status))); + throw uhd::io_error(str(boost::format("usb %s transfer status: %d") + % _name % libusb_error_name(result.status))); result.completed = 0; return make(reinterpret_cast(this), _lut->buffer, (_is_recv)? result.actual_length : _frame_size); } diff --git a/host/lib/transport/super_recv_packet_handler.hpp b/host/lib/transport/super_recv_packet_handler.hpp index 0f1f7ff3a..8742d1d16 100644 --- a/host/lib/transport/super_recv_packet_handler.hpp +++ b/host/lib/transport/super_recv_packet_handler.hpp @@ -524,10 +524,10 @@ private: ); } - //handle the case when the get packet throws - catch(const std::exception &e){ + //handle the case where a bad header exists + catch(const uhd::value_error &e){ UHD_MSG(error) << boost::format( - "The receive packet handler caught an exception.\n%s" + "The receive packet handler caught a value exception.\n%s" ) % e.what() << std::endl; std::swap(curr_info, next_info); //save progress from curr -> next curr_info.metadata.error_code = rx_metadata_t::ERROR_CODE_BAD_PACKET; diff --git a/host/tests/sph_recv_test.cpp b/host/tests/sph_recv_test.cpp index 5ade52a9c..a22e7a7c2 100644 --- a/host/tests/sph_recv_test.cpp +++ b/host/tests/sph_recv_test.cpp @@ -62,10 +62,14 @@ private: **********************************************************************/ class dummy_recv_xport_class{ public: - dummy_recv_xport_class(const std::string &end){ + dummy_recv_xport_class(const std::string &end) : io_status(true) { _end = end; } + void set_io_status(bool status){ + io_status = status; + } + void push_back_packet( uhd::transport::vrt::if_packet_info_t &ifpi, const boost::uint32_t optional_msg_word = 0 @@ -83,6 +87,7 @@ public: } uhd::transport::managed_recv_buffer::sptr get_recv_buff(double){ + if (!io_status) throw uhd::io_error("IO error exception"); //simulate an IO error if (_mems.empty()) return uhd::transport::managed_recv_buffer::sptr(); //timeout _mrbs.push_back(boost::shared_ptr(new dummy_mrb())); uhd::transport::managed_recv_buffer::sptr mrb = _mrbs.back()->get_new(_mems.front(), _lens.front()); @@ -96,6 +101,7 @@ private: std::list _lens; std::vector > _mrbs; std::string _end; + bool io_status; }; //////////////////////////////////////////////////////////////////////// @@ -167,6 +173,10 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_one_channel_normal){ ); BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_TIMEOUT); } + + //simulate the transport failing + dummy_recv_xport.set_io_status(false); + BOOST_REQUIRE_THROW(handler.recv(&buff.front(), buff.size(), metadata, 1.0, true), uhd::io_error); } //////////////////////////////////////////////////////////////////////// @@ -249,6 +259,10 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_one_channel_sequence_error){ ); BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_TIMEOUT); } + + //simulate the transport failing + dummy_recv_xport.set_io_status(false); + BOOST_REQUIRE_THROW(handler.recv(&buff.front(), buff.size(), metadata, 1.0, true), uhd::io_error); } //////////////////////////////////////////////////////////////////////// @@ -341,6 +355,10 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_one_channel_inline_message){ ); BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_TIMEOUT); } + + //simulate the transport failing + dummy_recv_xport.set_io_status(false); + BOOST_REQUIRE_THROW(handler.recv(&buff.front(), buff.size(), metadata, 1.0, true), uhd::io_error); } //////////////////////////////////////////////////////////////////////// @@ -424,6 +442,12 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_normal){ BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_TIMEOUT); } + //simulate the transport failing + for (size_t ch = 0; ch < NCHANNELS; ch++){ + dummy_recv_xports[ch].set_io_status(false); + } + + BOOST_REQUIRE_THROW(handler.recv(buffs, NUM_SAMPS_PER_BUFF, metadata, 1.0, true), uhd::io_error); } //////////////////////////////////////////////////////////////////////// @@ -518,6 +542,13 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_sequence_error){ ); BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_TIMEOUT); } + + //simulate the transport failing + for (size_t ch = 0; ch < NCHANNELS; ch++){ + dummy_recv_xports[ch].set_io_status(false); + } + + BOOST_REQUIRE_THROW(handler.recv(buffs, NUM_SAMPS_PER_BUFF, metadata, 1.0, true), uhd::io_error); } //////////////////////////////////////////////////////////////////////// @@ -606,6 +637,82 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_time_error){ ); BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_TIMEOUT); } + + //simulate the transport failing + for (size_t ch = 0; ch < NCHANNELS; ch++){ + dummy_recv_xports[ch].set_io_status(false); + } + + BOOST_REQUIRE_THROW(handler.recv(buffs, NUM_SAMPS_PER_BUFF, metadata, 1.0, true), uhd::io_error); +} + +//////////////////////////////////////////////////////////////////////// +BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_exception){ +//////////////////////////////////////////////////////////////////////// + uhd::convert::id_type id; + id.input_format = "sc16_item32_be"; + id.num_inputs = 1; + id.output_format = "fc32"; + id.num_outputs = 1; + + uhd::transport::vrt::if_packet_info_t ifpi; + ifpi.packet_type = uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_DATA; + ifpi.num_payload_words32 = 0; + ifpi.packet_count = 0; + ifpi.sob = true; + ifpi.eob = false; + ifpi.has_sid = false; + ifpi.has_cid = false; + ifpi.has_tsi = true; + ifpi.has_tsf = true; + ifpi.tsi = 0; + ifpi.tsf = 0; + ifpi.has_tlr = false; + + static const double TICK_RATE = 100e6; + static const double SAMP_RATE = 10e6; + static const size_t NUM_PKTS_TO_TEST = 30; + static const size_t NUM_SAMPS_PER_BUFF = 20; + static const size_t NCHANNELS = 4; + + std::vector dummy_recv_xports(NCHANNELS, dummy_recv_xport_class("big")); + + //generate a bunch of packets + for (size_t i = 0; i < NUM_PKTS_TO_TEST; i++){ + ifpi.num_payload_words32 = 10 + i%10; + for (size_t ch = 0; ch < NCHANNELS; ch++){ + dummy_recv_xports[ch].push_back_packet(ifpi); + } + ifpi.packet_count++; + ifpi.tsf += ifpi.num_payload_words32*size_t(TICK_RATE/SAMP_RATE); + if (i == NUM_PKTS_TO_TEST/2){ + ifpi.tsf = 0; //simulate the user changing the time + } + } + + //create the super receive packet handler + uhd::transport::sph::recv_packet_handler handler(NCHANNELS); + handler.set_vrt_unpacker(&uhd::transport::vrt::if_hdr_unpack_be); + handler.set_tick_rate(TICK_RATE); + handler.set_samp_rate(SAMP_RATE); + for (size_t ch = 0; ch < NCHANNELS; ch++){ + handler.set_xport_chan_get_buff(ch, boost::bind(&dummy_recv_xport_class::get_recv_buff, &dummy_recv_xports[ch], _1)); + } + handler.set_converter(id); + + std::complex mem[NUM_SAMPS_PER_BUFF*NCHANNELS]; + std::vector *> buffs(NCHANNELS); + for (size_t ch = 0; ch < NCHANNELS; ch++){ + buffs[ch] = &mem[ch*NUM_SAMPS_PER_BUFF]; + } + + // simulate a failure on a channel (the last one) + uhd::rx_metadata_t metadata; + dummy_recv_xports[NCHANNELS-1].set_io_status(false); + + std::cout << "exception check" << std::endl; + + BOOST_REQUIRE_THROW(handler.recv(buffs, NUM_SAMPS_PER_BUFF, metadata, 1.0, true), uhd::io_error); } //////////////////////////////////////////////////////////////////////// @@ -701,4 +808,10 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_fragment){ BOOST_CHECK_EQUAL(metadata.error_code, uhd::rx_metadata_t::ERROR_CODE_TIMEOUT); } + //simulate the transport failing + for (size_t ch = 0; ch < NCHANNELS; ch++){ + dummy_recv_xports[ch].set_io_status(false); + } + + BOOST_REQUIRE_THROW(handler.recv(buffs, NUM_SAMPS_PER_BUFF, metadata, 1.0, true), uhd::io_error); } -- cgit v1.2.3