aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaulPavid <paul.david@ettus.com>2016-02-09 14:17:43 -0800
committerDaulPavid <paul.david@ettus.com>2016-02-12 13:32:38 -0800
commit35c6d742977fa03e840d70951c0a136720d8a2d0 (patch)
tree1ed57b259eeb883ec135ef96c833a52ef6b3d7f4
parent83c1493e031ddd0b5b80560f4345aaa089446f94 (diff)
downloaduhd-35c6d742977fa03e840d70951c0a136720d8a2d0.tar.gz
uhd-35c6d742977fa03e840d70951c0a136720d8a2d0.tar.bz2
uhd-35c6d742977fa03e840d70951c0a136720d8a2d0.zip
Corrected the UHD behavior in the event of a USB disconnect
-rw-r--r--host/examples/benchmark_rate.cpp6
-rw-r--r--host/lib/transport/libusb1_zero_copy.cpp4
-rw-r--r--host/lib/transport/super_recv_packet_handler.hpp6
-rw-r--r--host/tests/sph_recv_test.cpp115
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<buffer_type *>(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<dummy_mrb>(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<size_t> _lens;
std::vector<boost::shared_ptr<dummy_mrb> > _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_xport_class> 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<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];
+ }
+
+ // 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);
}