diff options
Diffstat (limited to 'host/lib/transport/libusb1_zero_copy.cpp')
-rw-r--r-- | host/lib/transport/libusb1_zero_copy.cpp | 91 |
1 files changed, 55 insertions, 36 deletions
diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index 3e67264cd..3532dc4aa 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-2013 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 @@ -21,6 +21,7 @@ #include <uhd/utils/msg.hpp> #include <uhd/exception.hpp> #include <boost/foreach.hpp> +#include <boost/make_shared.hpp> #include <boost/thread/thread.hpp> #include <list> @@ -35,6 +36,12 @@ static const size_t DEFAULT_XFER_SIZE = 32*512; //bytes #define LIBUSB_CALL #endif /*LIBUSB_CALL*/ +//! libusb_handle_events_timeout_completed is only in newer API +#ifndef HAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED + #define libusb_handle_events_timeout_completed(ctx, tx, completed)\ + libusb_handle_events_timeout(ctx, tx) +#endif + /*! * All libusb callback functions should be marked with the LIBUSB_CALL macro * to ensure that they are compiled with the same calling convention as libusb. @@ -42,7 +49,8 @@ static const size_t DEFAULT_XFER_SIZE = 32*512; //bytes //! helper function: handles all async callbacks static void LIBUSB_CALL libusb_async_cb(libusb_transfer *lut){ - *(static_cast<bool *>(lut->user_data)) = true; + int *completed = (int *)lut->user_data; + *completed = 1; } /*! @@ -60,14 +68,24 @@ static void LIBUSB_CALL libusb_async_cb(libusb_transfer *lut){ * \param completed a reference to the completed flag * \return true for completion, false for timeout */ -UHD_INLINE bool wait_for_completion(libusb_context *ctx, const double timeout, bool &completed){ +UHD_INLINE bool wait_for_completion(libusb_context *ctx, const double timeout, int &completed){ + //already completed by a previous call? + if (completed) return true; + + //perform a non-blocking event handle + timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 0; + libusb_handle_events_timeout_completed(ctx, &tv, &completed); + if (completed) return true; + + //finish the rest with a timeout loop const boost::system_time timeout_time = boost::get_system_time() + boost::posix_time::microseconds(long(timeout*1000000)); - while (not completed and (boost::get_system_time() < timeout_time)){ timeval tv; tv.tv_sec = 0; tv.tv_usec = 10000; /*10ms*/ - libusb_handle_events_timeout(ctx, &tv); + libusb_handle_events_timeout_completed(ctx, &tv, &completed); } return completed; @@ -82,34 +100,27 @@ class libusb_zero_copy_mrb : public managed_recv_buffer{ public: libusb_zero_copy_mrb(libusb_transfer *lut, const size_t frame_size): _ctx(libusb::session::get_global_session()->get_context()), - _lut(lut), _expired(false), _frame_size(frame_size) { /* NOP */ } + _lut(lut), _frame_size(frame_size) { /* NOP */ } void release(void){ - if (_expired) return; - completed = false; + completed = 0; _lut->length = _frame_size; //always reset length UHD_ASSERT_THROW(libusb_submit_transfer(_lut) == 0); - _expired = true; } sptr get_new(const double timeout, size_t &index){ if (wait_for_completion(_ctx, timeout, completed)){ index++; - _expired = false; - return make_managed_buffer(this); + return make(this, _lut->buffer, _lut->actual_length); } return managed_recv_buffer::sptr(); } - bool completed; + int completed; private: - const void *get_buff(void) const{return _lut->buffer;} - size_t get_size(void) const{return _lut->actual_length;} - libusb_context *_ctx; libusb_transfer *_lut; - bool _expired; const size_t _frame_size; }; @@ -122,35 +133,27 @@ class libusb_zero_copy_msb : public managed_send_buffer{ public: libusb_zero_copy_msb(libusb_transfer *lut, const size_t frame_size): _ctx(libusb::session::get_global_session()->get_context()), - _lut(lut), _expired(false), _frame_size(frame_size) { /* NOP */ } - - void commit(size_t len){ - if (_expired) return; - completed = false; - _lut->length = len; - if (len == 0) libusb_async_cb(_lut); - else UHD_ASSERT_THROW(libusb_submit_transfer(_lut) == 0); - _expired = true; + _lut(lut), _frame_size(frame_size) { completed = true; } + + void release(void){ + completed = 0; + _lut->length = size(); + UHD_ASSERT_THROW(libusb_submit_transfer(_lut) == 0); } sptr get_new(const double timeout, size_t &index){ if (wait_for_completion(_ctx, timeout, completed)){ index++; - _expired = false; - return make_managed_buffer(this); + return make(this, _lut->buffer, _frame_size); } return managed_send_buffer::sptr(); } - bool completed; + int completed; private: - void *get_buff(void) const{return _lut->buffer;} - size_t get_size(void) const{return _frame_size;} - libusb_context *_ctx; libusb_transfer *_lut; - bool _expired; const size_t _frame_size; }; @@ -181,13 +184,30 @@ public: _handle->claim_interface(recv_interface); _handle->claim_interface(send_interface); + //flush the buffers out of the recv endpoint + //limit the flushing to at most one second + for (size_t i = 0; i < 100; i++) + { + unsigned char buff[512]; + int transfered = 0; + const int status = libusb_bulk_transfer( + _handle->get(), // dev_handle + (recv_endpoint & 0x7f) | 0x80, // endpoint + static_cast<unsigned char *>(buff), + sizeof(buff), + &transfered, //bytes xfered + 10 //timeout ms + ); + if (status == LIBUSB_ERROR_TIMEOUT) break; + } + //allocate libusb transfer structs and managed receive buffers for (size_t i = 0; i < get_num_recv_frames(); i++){ libusb_transfer *lut = libusb_alloc_transfer(0); UHD_ASSERT_THROW(lut != NULL); - _mrb_pool.push_back(boost::shared_ptr<libusb_zero_copy_mrb>(new libusb_zero_copy_mrb(lut, this->get_recv_frame_size()))); + _mrb_pool.push_back(boost::make_shared<libusb_zero_copy_mrb>(lut, this->get_recv_frame_size())); libusb_fill_bulk_transfer( lut, // transfer @@ -210,7 +230,7 @@ public: libusb_transfer *lut = libusb_alloc_transfer(0); UHD_ASSERT_THROW(lut != NULL); - _msb_pool.push_back(boost::shared_ptr<libusb_zero_copy_msb>(new libusb_zero_copy_msb(lut, this->get_send_frame_size()))); + _msb_pool.push_back(boost::make_shared<libusb_zero_copy_msb>(lut, this->get_send_frame_size())); libusb_fill_bulk_transfer( lut, // transfer @@ -224,7 +244,6 @@ public: ); _all_luts.push_back(lut); - _msb_pool.back()->commit(0); } } @@ -237,7 +256,7 @@ public: } //process all transfers until timeout occurs - bool completed = false; + int completed = 0; wait_for_completion(ctx, 0.01, completed); //free all transfers |