summaryrefslogtreecommitdiffstats
path: root/host/lib
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib')
-rw-r--r--host/lib/CMakeLists.txt3
-rw-r--r--host/lib/convert/CMakeLists.txt18
-rw-r--r--host/lib/transport/CMakeLists.txt10
-rw-r--r--host/lib/transport/libusb1_zero_copy.cpp492
-rw-r--r--host/lib/transport/udp_zero_copy_asio.cpp41
-rw-r--r--host/lib/transport/zero_copy.cpp114
-rw-r--r--host/lib/types/CMakeLists.txt15
-rw-r--r--host/lib/types/time_spec.cpp16
-rw-r--r--host/lib/usrp/dboard/db_rfx.cpp28
-rw-r--r--host/lib/usrp/multi_usrp.cpp74
-rw-r--r--host/lib/usrp/usrp1/io_impl.cpp137
-rw-r--r--host/lib/usrp/usrp2/dsp_impl.cpp6
-rw-r--r--host/lib/usrp/usrp2/fw_common.h5
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp5
-rw-r--r--host/lib/usrp/usrp2/mboard_impl.cpp29
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp2
-rw-r--r--host/lib/usrp/usrp2/usrp2_regs.cpp36
-rw-r--r--host/lib/usrp/usrp2/usrp2_regs.hpp36
-rw-r--r--host/lib/usrp/usrp_e100/io_impl.cpp48
-rw-r--r--host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp160
-rw-r--r--host/lib/utils/CMakeLists.txt18
21 files changed, 594 insertions, 699 deletions
diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt
index d2845ffda..c8a5dd51e 100644
--- a/host/lib/CMakeLists.txt
+++ b/host/lib/CMakeLists.txt
@@ -108,6 +108,9 @@ ADD_LIBRARY(uhd SHARED ${libuhd_sources})
TARGET_LINK_LIBRARIES(uhd ${Boost_LIBRARIES} ${libuhd_libs})
SET_TARGET_PROPERTIES(uhd PROPERTIES DEFINE_SYMBOL "UHD_DLL_EXPORTS")
SET_TARGET_PROPERTIES(uhd PROPERTIES SOVERSION ${UHD_VERSION_MAJOR})
+IF(DEFINED LIBUHD_OUTPUT_NAME)
+ SET_TARGET_PROPERTIES(uhd PROPERTIES OUTPUT_NAME ${LIBUHD_OUTPUT_NAME})
+ENDIF(DEFINED LIBUHD_OUTPUT_NAME)
INSTALL(TARGETS uhd
LIBRARY DESTINATION ${LIBRARY_DIR} # .so file
diff --git a/host/lib/convert/CMakeLists.txt b/host/lib/convert/CMakeLists.txt
index a9f977cdc..abc9c2707 100644
--- a/host/lib/convert/CMakeLists.txt
+++ b/host/lib/convert/CMakeLists.txt
@@ -22,15 +22,31 @@ INCLUDE(CheckIncludeFileCXX)
MESSAGE(STATUS "")
########################################################################
-# Check for SIMD headers
+# Check for SSE2 SIMD headers
########################################################################
+IF(CMAKE_COMPILER_IS_GNUCXX)
+ SET(EMMINTRIN_FLAGS -msse2)
+ELSEIF(MSVC)
+ SET(EMMINTRIN_FLAGS /arch:SSE2)
+ENDIF()
+
+SET(CMAKE_REQUIRED_FLAGS ${EMMINTRIN_FLAGS})
CHECK_INCLUDE_FILE_CXX(emmintrin.h HAVE_EMMINTRIN_H)
+UNSET(CMAKE_REQUIRED_FLAGS)
+
IF(HAVE_EMMINTRIN_H)
+ SET_SOURCE_FILES_PROPERTIES(
+ ${CMAKE_CURRENT_SOURCE_DIR}/convert_with_sse2.cpp
+ PROPERTIES COMPILE_FLAGS ${EMMINTRIN_FLAGS}
+ )
LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/convert_with_sse2.cpp
)
ENDIF(HAVE_EMMINTRIN_H)
+########################################################################
+# Check for NEON SIMD headers
+########################################################################
CHECK_INCLUDE_FILE_CXX(arm_neon.h HAVE_ARM_NEON_H)
IF(HAVE_ARM_NEON_H)
LIBUHD_APPEND_SOURCES(
diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt
index 8765c6703..a98bcc14e 100644
--- a/host/lib/transport/CMakeLists.txt
+++ b/host/lib/transport/CMakeLists.txt
@@ -55,14 +55,19 @@ CHECK_INCLUDE_FILE_CXX(winsock2.h HAVE_WINSOCK2_H)
IF(HAVE_IFADDRS_H)
MESSAGE(STATUS " Interface address discovery supported through getifaddrs.")
- ADD_DEFINITIONS(-DHAVE_IFADDRS_H)
+ SET(IF_ADDRS_DEFS HAVE_IFADDRS_H)
ELSEIF(HAVE_WINSOCK2_H)
MESSAGE(STATUS " Interface address discovery supported through SIO_GET_INTERFACE_LIST.")
- ADD_DEFINITIONS(-DHAVE_WINSOCK2_H)
+ SET(IF_ADDRS_DEFS HAVE_WINSOCK2_H)
ELSE(HAVE_IFADDRS_H)
MESSAGE(STATUS " Interface address discovery not supported.")
ENDIF(HAVE_IFADDRS_H)
+SET_SOURCE_FILES_PROPERTIES(
+ ${CMAKE_CURRENT_SOURCE_DIR}/if_addrs.cpp
+ PROPERTIES COMPILE_DEFINITIONS "${IF_ADDRS_DEFS}"
+)
+
########################################################################
# Append to the list of sources for lib uhd
########################################################################
@@ -77,5 +82,4 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/udp_simple.cpp
${CMAKE_CURRENT_SOURCE_DIR}/udp_zero_copy_asio.cpp
${CMAKE_CURRENT_SOURCE_DIR}/vrt_packet_handler.hpp
- ${CMAKE_CURRENT_SOURCE_DIR}/zero_copy.cpp
)
diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp
index 6fab5ae6f..87adece45 100644
--- a/host/lib/transport/libusb1_zero_copy.cpp
+++ b/host/lib/transport/libusb1_zero_copy.cpp
@@ -21,258 +21,88 @@
#include <uhd/transport/buffer_pool.hpp>
#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/assert.hpp>
+#include <boost/function.hpp>
#include <boost/foreach.hpp>
-#include <boost/thread.hpp>
-#include <vector>
+#include <boost/thread/thread.hpp>
+#include <list>
#include <iostream>
using namespace uhd;
using namespace uhd::transport;
-static const double CLEANUP_TIMEOUT = 0.2; //seconds
static const size_t DEFAULT_NUM_XFERS = 16; //num xfers
static const size_t DEFAULT_XFER_SIZE = 32*512; //bytes
/***********************************************************************
- * Helper functions
- ***********************************************************************/
-/*
- * Print the values of a libusb_transfer struct
- * http://libusb.sourceforge.net/api-1.0/structlibusb__transfer.html
- */
-void pp_transfer(libusb_transfer *lut)
-{
- std::cout << "Libusb transfer" << std::endl;
- std::cout << " flags: 0x" << std::hex << (unsigned int) lut->flags << std::endl;
- std::cout << " endpoint: 0x" << std::hex << (unsigned int) lut->endpoint << std::endl;
- std::cout << " type: 0x" << std::hex << (unsigned int) lut->type << std::endl;
- std::cout << " timeout: " << std::dec << lut->timeout << std::endl;
- std::cout << " status: 0x" << std::hex << lut->status << std::endl;
- std::cout << " length: " << std::dec << lut->length << std::endl;
- std::cout << " actual_length: " << std::dec << lut->actual_length << std::endl;
-}
-
-/***********************************************************************
- * USB asynchronous zero_copy endpoint
- * This endpoint implementation provides asynchronous I/O to libusb-1.0
- * devices. Each endpoint is directional and two can be combined to
- * create a bidirectional interface. It is a zero copy implementation
- * with respect to libusb, however, each send and recv requires a copy
- * operation from kernel to userspace; this is due to the usbfs
- * interface provided by the kernel.
+ * Reusable managed receiver buffer:
+ * - Associated with a particular libusb transfer struct.
+ * - Submits the transfer to libusb in the release method.
**********************************************************************/
-class usb_endpoint {
+class libusb_zero_copy_mrb : public managed_recv_buffer{
public:
- typedef boost::shared_ptr<usb_endpoint> sptr;
-
- usb_endpoint(
- libusb::device_handle::sptr handle,
- int endpoint,
- bool input,
- size_t transfer_size,
- size_t num_transfers
- );
-
- ~usb_endpoint(void);
+ libusb_zero_copy_mrb(libusb_transfer *lut):
+ _lut(lut), _expired(true) { /* NOP */ }
- // Exposed interface for submitting / retrieving transfer buffers
-
- //! Submit a new transfer that was presumably just filled or emptied.
- void submit(libusb_transfer *lut);
-
- /*!
- * Get an available transfer:
- * For inputs, this is a just filled transfer.
- * For outputs, this is a just emptied transfer.
- * \param timeout the timeout to wait for a lut
- * \return the transfer pointer or NULL if timeout
- */
- libusb_transfer *get_lut_with_wait(double timeout);
+ void release(void){
+ if (_expired) return;
+ UHD_ASSERT_THROW(libusb_submit_transfer(_lut) == 0);
+ _expired = true;
+ }
- //Callback use only
- void callback_handle_transfer(libusb_transfer *lut);
+ sptr get_new(void){
+ _expired = false;
+ return sptr(this, &libusb_zero_copy_mrb::fake_deleter);
+ }
private:
- libusb::device_handle::sptr _handle;
- int _endpoint;
- bool _input;
-
- //! hold a bounded buffer of completed transfers
- bounded_buffer<libusb_transfer *> _completed_list;
-
- //! a list of all transfer structs we allocated
- std::vector<libusb_transfer *> _all_luts;
+ static void fake_deleter(void *obj){
+ static_cast<libusb_zero_copy_mrb *>(obj)->release();
+ }
- //! memory allocated for the transfer buffers
- buffer_pool::sptr _buffer_pool;
+ const void *get_buff(void) const{return _lut->buffer;}
+ size_t get_size(void) const{return _lut->actual_length;}
- // Calls for processing asynchronous I/O
- libusb_transfer *allocate_transfer(void *mem, size_t len);
- void print_transfer_status(libusb_transfer *lut);
+ libusb_transfer *_lut;
+ bool _expired;
};
-
-/*
- * Callback function called when submitted transfers complete.
- * The endpoint upon which the transfer is part of is recovered
- * and the transfer moved from pending to completed state.
- * Callbacks occur during the reaping calls where libusb_handle_events()
- * is used. The callback only modifies the transfer state by moving
- * it from the pending to completed status list.
- * \param lut pointer to libusb_transfer
- */
-static void callback(libusb_transfer *lut){
- usb_endpoint *endpoint = (usb_endpoint *) lut->user_data;
- endpoint->callback_handle_transfer(lut);
-}
-
-
-/*
- * Accessor call to allow list access from callback space
- * \param pointer to libusb_transfer
- */
-void usb_endpoint::callback_handle_transfer(libusb_transfer *lut){
- _completed_list.push_with_haste(lut);
-}
-
-
-/*
- * Constructor
- * Allocate libusb transfers and mark as free. For IN endpoints,
- * submit the transfers so that they're ready to return when
- * data is available.
- */
-usb_endpoint::usb_endpoint(
- libusb::device_handle::sptr handle,
- int endpoint,
- bool input,
- size_t transfer_size,
- size_t num_transfers
-):
- _handle(handle),
- _endpoint(endpoint),
- _input(input),
- _completed_list(num_transfers)
-{
- _buffer_pool = buffer_pool::make(num_transfers, transfer_size);
- for (size_t i = 0; i < num_transfers; i++){
- _all_luts.push_back(allocate_transfer(_buffer_pool->at(i), transfer_size));
-
- //input luts are immediately submitted to be filled
- //output luts go into the completed list as free buffers
- if (_input) this->submit(_all_luts.back());
- else _completed_list.push_with_haste(_all_luts.back());
+/***********************************************************************
+ * Reusable managed send buffer:
+ * - Associated with a particular libusb transfer struct.
+ * - Submits the transfer to libusb in the commit method.
+ **********************************************************************/
+class libusb_zero_copy_msb : public managed_send_buffer{
+public:
+ libusb_zero_copy_msb(libusb_transfer *lut):
+ _lut(lut), _expired(true) { /* NOP */ }
+
+ void commit(size_t len){
+ if (_expired) return;
+ _lut->length = len;
+ UHD_ASSERT_THROW(libusb_submit_transfer(_lut) == 0);
+ _expired = true;
}
-}
-
-/*
- * Destructor
- * Make sure all the memory is freed. Cancel any pending transfers.
- * When all completed transfers are moved to the free list, release
- * the transfers. Libusb will deallocate the data buffer held by
- * each transfer.
- */
-usb_endpoint::~usb_endpoint(void){
- //cancel all transfers
- BOOST_FOREACH(libusb_transfer *lut, _all_luts){
- libusb_cancel_transfer(lut);
+ sptr get_new(void){
+ _expired = false;
+ return sptr(this, &libusb_zero_copy_msb::fake_deleter);
}
- //collect canceled transfers (drain the queue)
- while (this->get_lut_with_wait(CLEANUP_TIMEOUT) != NULL){};
-
- //free all transfers
- BOOST_FOREACH(libusb_transfer *lut, _all_luts){
- libusb_free_transfer(lut);
+private:
+ static void fake_deleter(void *obj){
+ static_cast<libusb_zero_copy_msb *>(obj)->commit(0);
}
-}
-
-
-/*
- * Allocate a libusb transfer
- * The allocated transfer - and buffer it contains - is repeatedly
- * submitted, reaped, and reused and should not be freed until shutdown.
- * \param mem a pointer to the buffer memory
- * \param len size of the individual buffer
- * \return pointer to an allocated libusb_transfer
- */
-libusb_transfer *usb_endpoint::allocate_transfer(void *mem, size_t len){
- libusb_transfer *lut = libusb_alloc_transfer(0);
- UHD_ASSERT_THROW(lut != NULL);
-
- unsigned int endpoint = ((_endpoint & 0x7f) | (_input ? 0x80 : 0));
- unsigned char *buff = reinterpret_cast<unsigned char *>(mem);
- libusb_transfer_cb_fn lut_callback = libusb_transfer_cb_fn(&callback);
-
- libusb_fill_bulk_transfer(lut, // transfer
- _handle->get(), // dev_handle
- endpoint, // endpoint
- buff, // buffer
- len, // length
- lut_callback, // callback
- this, // user_data
- 0); // timeout
- return lut;
-}
+ void *get_buff(void) const{return _lut->buffer;}
+ size_t get_size(void) const{return _lut->length;}
-/*
- * Asynchonous transfer submission
- * Submit a libusb transfer to libusb add pending status
- * \param lut pointer to libusb_transfer
- * \return true on success or false on error
- */
-void usb_endpoint::submit(libusb_transfer *lut){
- UHD_ASSERT_THROW(libusb_submit_transfer(lut) == 0);
-}
-
-/*
- * Print status errors of a completed transfer
- * \param lut pointer to an libusb_transfer
- */
-void usb_endpoint::print_transfer_status(libusb_transfer *lut){
- std::cout << "here " << lut->status << std::endl;
- switch (lut->status) {
- case LIBUSB_TRANSFER_COMPLETED:
- if (lut->actual_length < lut->length) {
- std::cerr << "USB: transfer completed with short write,"
- << " length = " << lut->length
- << " actual = " << lut->actual_length << std::endl;
- }
-
- if ((lut->actual_length < 0) || (lut->length < 0)) {
- std::cerr << "USB: transfer completed with invalid response"
- << std::endl;
- }
- break;
- case LIBUSB_TRANSFER_CANCELLED:
- break;
- case LIBUSB_TRANSFER_NO_DEVICE:
- std::cerr << "USB: device was disconnected" << std::endl;
- break;
- case LIBUSB_TRANSFER_OVERFLOW:
- std::cerr << "USB: device sent more data than requested" << std::endl;
- break;
- case LIBUSB_TRANSFER_TIMED_OUT:
- std::cerr << "USB: transfer timed out" << std::endl;
- break;
- case LIBUSB_TRANSFER_STALL:
- std::cerr << "USB: halt condition detected (stalled)" << std::endl;
- break;
- case LIBUSB_TRANSFER_ERROR:
- std::cerr << "USB: transfer failed" << std::endl;
- break;
- default:
- std::cerr << "USB: received unknown transfer status" << std::endl;
- }
-}
+ libusb_transfer *_lut;
+ bool _expired;
+};
-libusb_transfer *usb_endpoint::get_lut_with_wait(double timeout){
- boost::this_thread::disable_interruption di; //disable because the wait can throw
- libusb_transfer *lut = NULL;
- if (_completed_list.pop_with_timed_wait(lut, timeout)) return lut;
- return NULL;
+//! helper function: handles all async callbacks
+static void libusb_async_cb(libusb_transfer *lut){
+ (*static_cast<boost::function<void()> *>(lut->user_data))();
}
/***********************************************************************
@@ -286,16 +116,107 @@ public:
size_t recv_endpoint,
size_t send_endpoint,
const device_addr_t &hints
- );
+ ):
+ _handle(handle),
+ _recv_frame_size(size_t(hints.cast<double>("recv_frame_size", DEFAULT_XFER_SIZE))),
+ _num_recv_frames(size_t(hints.cast<double>("num_recv_frames", DEFAULT_NUM_XFERS))),
+ _send_frame_size(size_t(hints.cast<double>("send_frame_size", DEFAULT_XFER_SIZE))),
+ _num_send_frames(size_t(hints.cast<double>("num_send_frames", DEFAULT_NUM_XFERS))),
+ _recv_buffer_pool(buffer_pool::make(_num_recv_frames, _recv_frame_size)),
+ _send_buffer_pool(buffer_pool::make(_num_send_frames, _send_frame_size)),
+ _pending_recv_buffs(_num_recv_frames),
+ _pending_send_buffs(_num_send_frames)
+ {
+ _handle->claim_interface(2 /*in interface*/);
+ _handle->claim_interface(1 /*out interface*/);
+
+ //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(libusb_zero_copy_mrb(lut));
+ _callbacks.push_back(boost::bind(
+ &libusb_zero_copy_impl::handle_recv, this, &_mrb_pool.back()
+ ));
+
+ libusb_fill_bulk_transfer(
+ lut, // transfer
+ _handle->get(), // dev_handle
+ (recv_endpoint & 0x7f) | 0x80, // endpoint
+ static_cast<unsigned char *>(_recv_buffer_pool->at(i)), // buffer
+ this->get_recv_frame_size(), // length
+ libusb_transfer_cb_fn(&libusb_async_cb), // callback
+ static_cast<void *>(&_callbacks.back()), // user_data
+ 0 // timeout
+ );
+
+ _all_luts.push_back(lut);
+ _mrb_pool.back().get_new();
+ }
+
+ //allocate libusb transfer structs and managed send buffers
+ for (size_t i = 0; i < get_num_send_frames(); i++){
+
+ libusb_transfer *lut = libusb_alloc_transfer(0);
+ UHD_ASSERT_THROW(lut != NULL);
+
+ _msb_pool.push_back(libusb_zero_copy_msb(lut));
+ _callbacks.push_back(boost::bind(
+ &libusb_zero_copy_impl::handle_send, this, &_msb_pool.back()
+ ));
+
+ libusb_fill_bulk_transfer(
+ lut, // transfer
+ _handle->get(), // dev_handle
+ (send_endpoint & 0x7f) | 0x00, // endpoint
+ static_cast<unsigned char *>(_send_buffer_pool->at(i)), // buffer
+ this->get_send_frame_size(), // length
+ libusb_transfer_cb_fn(&libusb_async_cb), // callback
+ static_cast<void *>(&_callbacks.back()), // user_data
+ 0 // timeout
+ );
+
+ _all_luts.push_back(lut);
+ libusb_async_cb(lut);
+ }
+
+ //spawn the event handler threads
+ size_t concurrency = hints.cast<size_t>("concurrency_hint", 1);
+ for (size_t i = 0; i < concurrency; i++) _thread_group.create_thread(
+ boost::bind(&libusb_zero_copy_impl::run_event_loop, this)
+ );
+ }
~libusb_zero_copy_impl(void){
+ //shutdown the threads
_threads_running = false;
_thread_group.interrupt_all();
_thread_group.join_all();
+
+ //cancel and free all transfers
+ BOOST_FOREACH(libusb_transfer *lut, _all_luts){
+ libusb_cancel_transfer(lut);
+ libusb_free_transfer(lut);
+ }
}
- managed_recv_buffer::sptr get_recv_buff(double);
- managed_send_buffer::sptr get_send_buff(double);
+ managed_recv_buffer::sptr get_recv_buff(double timeout){
+ libusb_zero_copy_mrb *mrb = NULL;
+ if (_pending_recv_buffs.pop_with_timed_wait(mrb, timeout)){
+ return mrb->get_new();
+ }
+ return managed_recv_buffer::sptr();
+ }
+
+ managed_send_buffer::sptr get_send_buff(double timeout){
+ libusb_zero_copy_msb *msb = NULL;
+ if (_pending_send_buffs.pop_with_timed_wait(msb, timeout)){
+ return msb->get_new();
+ }
+ return managed_send_buffer::sptr();
+ }
size_t get_num_recv_frames(void) const { return _num_recv_frames; }
size_t get_num_send_frames(void) const { return _num_send_frames; }
@@ -304,125 +225,50 @@ public:
size_t get_send_frame_size(void) const { return _send_frame_size; }
private:
- void release(libusb_transfer *lut){
- _recv_ep->submit(lut);
+ //! Handle a bound async callback for recv
+ void handle_recv(libusb_zero_copy_mrb *mrb){
+ _pending_recv_buffs.push_with_haste(mrb);
}
- void commit(libusb_transfer *lut, size_t num_bytes){
- lut->length = num_bytes;
- try{
- _send_ep->submit(lut);
- }
- catch(const std::exception &e){
- std::cerr << "Error in commit: " << e.what() << std::endl;
- }
+ //! Handle a bound async callback for send
+ void handle_send(libusb_zero_copy_msb *msb){
+ _pending_send_buffs.push_with_haste(msb);
}
libusb::device_handle::sptr _handle;
const size_t _recv_frame_size, _num_recv_frames;
const size_t _send_frame_size, _num_send_frames;
- usb_endpoint::sptr _recv_ep, _send_ep;
- //event handler threads
+ //! Storage for transfer related objects
+ buffer_pool::sptr _recv_buffer_pool, _send_buffer_pool;
+ bounded_buffer<libusb_zero_copy_mrb *> _pending_recv_buffs;
+ bounded_buffer<libusb_zero_copy_msb *> _pending_send_buffs;
+ std::list<libusb_zero_copy_mrb> _mrb_pool;
+ std::list<libusb_zero_copy_msb> _msb_pool;
+ std::list<boost::function<void()> > _callbacks;
+
+ //! a list of all transfer structs we allocated
+ std::list<libusb_transfer *> _all_luts;
+
+ //! event handler threads
boost::thread_group _thread_group;
bool _threads_running;
void run_event_loop(void){
set_thread_priority_safe();
- libusb::session::sptr session = libusb::session::get_global_session();
+ libusb_context *context = libusb::session::get_global_session()->get_context();
_threads_running = true;
try{
while(_threads_running){
timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 100000; //100ms
- libusb_handle_events_timeout(session->get_context(), &tv);
+ libusb_handle_events_timeout(context, &tv);
}
} catch(const boost::thread_interrupted &){}
}
-};
-
-/*
- * Constructor
- * Initializes libusb, opens devices, and sets up interfaces for I/O.
- * Finally, creates endpoints for asynchronous I/O.
- */
-libusb_zero_copy_impl::libusb_zero_copy_impl(
- libusb::device_handle::sptr handle,
- size_t recv_endpoint,
- size_t send_endpoint,
- const device_addr_t &hints
-):
- _handle(handle),
- _recv_frame_size(size_t(hints.cast<double>("recv_frame_size", DEFAULT_XFER_SIZE))),
- _num_recv_frames(size_t(hints.cast<double>("num_recv_frames", DEFAULT_NUM_XFERS))),
- _send_frame_size(size_t(hints.cast<double>("send_frame_size", DEFAULT_XFER_SIZE))),
- _num_send_frames(size_t(hints.cast<double>("num_send_frames", DEFAULT_NUM_XFERS)))
-{
- _handle->claim_interface(2 /*in interface*/);
- _handle->claim_interface(1 /*out interface*/);
-
- _recv_ep = usb_endpoint::sptr(new usb_endpoint(
- _handle, // libusb device_handle
- recv_endpoint, // USB endpoint number
- true, // IN endpoint
- this->get_recv_frame_size(), // buffer size per transfer
- this->get_num_recv_frames() // number of libusb transfers
- ));
-
- _send_ep = usb_endpoint::sptr(new usb_endpoint(
- _handle, // libusb device_handle
- send_endpoint, // USB endpoint number
- false, // OUT endpoint
- this->get_send_frame_size(), // buffer size per transfer
- this->get_num_send_frames() // number of libusb transfers
- ));
-
- //spawn the event handler threads
- size_t concurrency = hints.cast<size_t>("concurrency_hint", 1);
- for (size_t i = 0; i < concurrency; i++) _thread_group.create_thread(
- boost::bind(&libusb_zero_copy_impl::run_event_loop, this)
- );
-}
-
-/*
- * Construct a managed receive buffer from a completed libusb transfer
- * (happy with buffer full of data) obtained from the receive endpoint.
- * Return empty pointer if no transfer is available (timeout or error).
- * \return pointer to a managed receive buffer
- */
-managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff(double timeout){
- libusb_transfer *lut = _recv_ep->get_lut_with_wait(timeout);
- if (lut == NULL) {
- return managed_recv_buffer::sptr();
- }
- else {
- return managed_recv_buffer::make_safe(
- lut->buffer, lut->actual_length,
- boost::bind(&libusb_zero_copy_impl::release, this, lut)
- );
- }
-}
-
-/*
- * Construct a managed send buffer from a free libusb transfer (with
- * empty buffer). Return empty pointer of no transfer is available
- * (timeout or error).
- * \return pointer to a managed send buffer
- */
-managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff(double timeout){
- libusb_transfer *lut = _send_ep->get_lut_with_wait(timeout);
- if (lut == NULL) {
- return managed_send_buffer::sptr();
- }
- else {
- return managed_send_buffer::make_safe(
- lut->buffer, this->get_send_frame_size(),
- boost::bind(&libusb_zero_copy_impl::commit, this, lut, _1)
- );
- }
-}
+};
/***********************************************************************
* USB zero_copy make functions
diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp
index 2794d383c..05352ffce 100644
--- a/host/lib/transport/udp_zero_copy_asio.cpp
+++ b/host/lib/transport/udp_zero_copy_asio.cpp
@@ -24,7 +24,7 @@
#include <boost/asio.hpp>
#include <boost/format.hpp>
#include <iostream>
-#include <vector>
+#include <list>
using namespace uhd;
using namespace uhd::transport;
@@ -40,20 +40,18 @@ static const size_t DEFAULT_NUM_FRAMES = 32;
**********************************************************************/
class udp_zero_copy_asio_mrb : public managed_recv_buffer{
public:
- typedef boost::shared_ptr<udp_zero_copy_asio_mrb> sptr;
typedef boost::function<void(udp_zero_copy_asio_mrb *)> release_cb_type;
udp_zero_copy_asio_mrb(void *mem, const release_cb_type &release_cb):
- _mem(mem), _release_cb(release_cb){/* NOP */}
+ _mem(mem), _len(0), _release_cb(release_cb){/* NOP */}
void release(void){
- if (_expired) return;
+ if (_len == 0) return;
this->_release_cb(this);
- _expired = true;
+ _len = 0;
}
sptr get_new(size_t len){
- _expired = false;
_len = len;
return sptr(this, &udp_zero_copy_asio_mrb::fake_deleter);
}
@@ -68,7 +66,6 @@ private:
const void *get_buff(void) const{return _mem;}
size_t get_size(void) const{return _len;}
- bool _expired;
void *_mem;
size_t _len;
release_cb_type _release_cb;
@@ -81,20 +78,18 @@ private:
**********************************************************************/
class udp_zero_copy_asio_msb : public managed_send_buffer{
public:
- typedef boost::shared_ptr<udp_zero_copy_asio_msb> sptr;
typedef boost::function<void(udp_zero_copy_asio_msb *, size_t)> commit_cb_type;
udp_zero_copy_asio_msb(void *mem, const commit_cb_type &commit_cb):
- _mem(mem), _commit_cb(commit_cb){/* NOP */}
+ _mem(mem), _len(0), _commit_cb(commit_cb){/* NOP */}
void commit(size_t len){
- if (_expired) return;
+ if (_len == 0) return;
this->_commit_cb(this, len);
- _expired = true;
+ _len = 0;
}
sptr get_new(size_t len){
- _expired = false;
_len = len;
return sptr(this, &udp_zero_copy_asio_msb::fake_deleter);
}
@@ -107,7 +102,6 @@ private:
void *get_buff(void) const{return _mem;}
size_t get_size(void) const{return _len;}
- bool _expired;
void *_mem;
size_t _len;
commit_cb_type _commit_cb;
@@ -135,7 +129,8 @@ public:
_num_send_frames(size_t(hints.cast<double>("num_send_frames", DEFAULT_NUM_FRAMES))),
_recv_buffer_pool(buffer_pool::make(_num_recv_frames, _recv_frame_size)),
_send_buffer_pool(buffer_pool::make(_num_send_frames, _send_frame_size)),
- _pending_recv_buffs(_num_recv_frames), _pending_send_buffs(_num_send_frames)
+ _pending_recv_buffs(_num_recv_frames),
+ _pending_send_buffs(_num_send_frames)
{
//std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl;
@@ -152,20 +147,18 @@ public:
//allocate re-usable managed receive buffers
for (size_t i = 0; i < get_num_recv_frames(); i++){
- _mrb_pool.push_back(udp_zero_copy_asio_mrb::sptr(
- new udp_zero_copy_asio_mrb(_recv_buffer_pool->at(i),
+ _mrb_pool.push_back(udp_zero_copy_asio_mrb(_recv_buffer_pool->at(i),
boost::bind(&udp_zero_copy_asio_impl::release, this, _1))
- ));
- handle_recv(_mrb_pool.back().get());
+ );
+ handle_recv(&_mrb_pool.back());
}
//allocate re-usable managed send buffers
for (size_t i = 0; i < get_num_send_frames(); i++){
- _msb_pool.push_back(udp_zero_copy_asio_msb::sptr(
- new udp_zero_copy_asio_msb(_send_buffer_pool->at(i),
+ _msb_pool.push_back(udp_zero_copy_asio_msb(_send_buffer_pool->at(i),
boost::bind(&udp_zero_copy_asio_impl::commit, this, _1, _2))
- ));
- handle_send(_msb_pool.back().get());
+ );
+ handle_send(&_msb_pool.back());
}
}
@@ -264,8 +257,8 @@ private:
buffer_pool::sptr _recv_buffer_pool, _send_buffer_pool;
bounded_buffer<udp_zero_copy_asio_mrb *> _pending_recv_buffs;
bounded_buffer<udp_zero_copy_asio_msb *> _pending_send_buffs;
- std::vector<udp_zero_copy_asio_msb::sptr> _msb_pool;
- std::vector<udp_zero_copy_asio_mrb::sptr> _mrb_pool;
+ std::list<udp_zero_copy_asio_msb> _msb_pool;
+ std::list<udp_zero_copy_asio_mrb> _mrb_pool;
//asio guts -> socket and service
asio::io_service _io_service;
diff --git a/host/lib/transport/zero_copy.cpp b/host/lib/transport/zero_copy.cpp
deleted file mode 100644
index b91eaae1d..000000000
--- a/host/lib/transport/zero_copy.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-//
-// Copyright 2010-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 <uhd/transport/zero_copy.hpp>
-
-using namespace uhd::transport;
-
-/***********************************************************************
- * Safe managed receive buffer
- **********************************************************************/
-static void release_nop(void){
- /* NOP */
-}
-
-class safe_managed_receive_buffer : public managed_recv_buffer{
-public:
- safe_managed_receive_buffer(
- const void *buff, size_t size, const release_fcn_t &release_fcn
- ):
- _buff(buff), _size(size), _release_fcn(release_fcn)
- {
- /* NOP */
- }
-
- ~safe_managed_receive_buffer(void){
- _release_fcn();
- }
-
- void release(void){
- release_fcn_t release_fcn = _release_fcn;
- _release_fcn = &release_nop;
- return release_fcn();
- }
-
-private:
- const void *get_buff(void) const{
- return _buff;
- }
-
- size_t get_size(void) const{
- return _size;
- }
-
- const void *_buff;
- size_t _size;
- release_fcn_t _release_fcn;
-};
-
-managed_recv_buffer::sptr managed_recv_buffer::make_safe(
- const void *buff, size_t size, const release_fcn_t &release_fcn
-){
- return sptr(new safe_managed_receive_buffer(buff, size, release_fcn));
-}
-
-/***********************************************************************
- * Safe managed send buffer
- **********************************************************************/
-static void commit_nop(size_t){
- /* NOP */
-}
-
-class safe_managed_send_buffer : public managed_send_buffer{
-public:
- safe_managed_send_buffer(
- void *buff, size_t size, const commit_fcn_t &commit_fcn
- ):
- _buff(buff), _size(size), _commit_fcn(commit_fcn)
- {
- /* NOP */
- }
-
- ~safe_managed_send_buffer(void){
- _commit_fcn(0);
- }
-
- void commit(size_t num_bytes){
- commit_fcn_t commit_fcn = _commit_fcn;
- _commit_fcn = &commit_nop;
- return commit_fcn(num_bytes);
- }
-
-private:
- void *get_buff(void) const{
- return _buff;
- }
-
- size_t get_size(void) const{
- return _size;
- }
-
- void *_buff;
- size_t _size;
- commit_fcn_t _commit_fcn;
-};
-
-safe_managed_send_buffer::sptr managed_send_buffer::make_safe(
- void *buff, size_t size, const commit_fcn_t &commit_fcn
-){
- return sptr(new safe_managed_send_buffer(buff, size, commit_fcn));
-}
diff --git a/host/lib/types/CMakeLists.txt b/host/lib/types/CMakeLists.txt
index ad625111e..957dfd345 100644
--- a/host/lib/types/CMakeLists.txt
+++ b/host/lib/types/CMakeLists.txt
@@ -58,19 +58,24 @@ CHECK_CXX_SOURCE_COMPILES("
IF(HAVE_CLOCK_GETTIME)
MESSAGE(STATUS " High resolution timing supported through clock_gettime.")
- ADD_DEFINITIONS(-DTIME_SPEC_USE_CLOCK_GETTIME)
- SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -lrt")
+ SET(TIME_SPEC_DEFS HAVE_CLOCK_GETTIME)
+ LIBUHD_APPEND_LIBS("-lrt")
ELSEIF(HAVE_MACH_ABSOLUTE_TIME)
MESSAGE(STATUS " High resolution timing supported through mach_absolute_time.")
- ADD_DEFINITIONS(-DTIME_SPEC_USE_MACH_ABSOLUTE_TIME)
+ SET(TIME_SPEC_DEFS HAVE_MACH_ABSOLUTE_TIME)
ELSEIF(HAVE_QUERY_PERFORMANCE_COUNTER)
MESSAGE(STATUS " High resolution timing supported through QueryPerformanceCounter.")
- ADD_DEFINITIONS(-DTIME_SPEC_USE_QUERY_PERFORMANCE_COUNTER)
+ SET(TIME_SPEC_DEFS HAVE_QUERY_PERFORMANCE_COUNTER)
ELSE()
MESSAGE(STATUS " High resolution timing supported though microsec_clock.")
- ADD_DEFINITIONS(-DTIME_SPEC_USE_MICROSEC_CLOCK)
+ SET(TIME_SPEC_DEFS HAVE_MICROSEC_CLOCK)
ENDIF()
+SET_SOURCE_FILES_PROPERTIES(
+ ${CMAKE_CURRENT_SOURCE_DIR}/time_spec.cpp
+ PROPERTIES COMPILE_DEFINITIONS "${TIME_SPEC_DEFS}"
+)
+
########################################################################
# This file included, use CMake directory variables
########################################################################
diff --git a/host/lib/types/time_spec.cpp b/host/lib/types/time_spec.cpp
index 4a41f0fb9..a785332c2 100644
--- a/host/lib/types/time_spec.cpp
+++ b/host/lib/types/time_spec.cpp
@@ -36,26 +36,26 @@ static UHD_INLINE time_spec_t time_spec_t_from_counts(intmax_t counts, intmax_t
return time_spec_t(time_t(divres.quot), double(divres.rem)/freq);
}
-#ifdef TIME_SPEC_USE_CLOCK_GETTIME
+#ifdef HAVE_CLOCK_GETTIME
#include <time.h>
time_spec_t time_spec_t::get_system_time(void){
timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts);
return time_spec_t(ts.tv_sec, ts.tv_nsec, 1e9);
}
-#endif /* TIME_SPEC_USE_CLOCK_GETTIME */
+#endif /* HAVE_CLOCK_GETTIME */
-#ifdef TIME_SPEC_USE_MACH_ABSOLUTE_TIME
+#ifdef HAVE_MACH_ABSOLUTE_TIME
#include <mach/mach_time.h>
time_spec_t time_spec_t::get_system_time(void){
mach_timebase_info_data_t info; mach_timebase_info(&info);
intmax_t nanosecs = mach_absolute_time()*info.numer/info.denom;
return time_spec_t_from_counts(nanosecs, intmax_t(1e9));
}
-#endif /* TIME_SPEC_USE_MACH_ABSOLUTE_TIME */
+#endif /* HAVE_MACH_ABSOLUTE_TIME */
-#ifdef TIME_SPEC_USE_QUERY_PERFORMANCE_COUNTER
+#ifdef HAVE_QUERY_PERFORMANCE_COUNTER
#include <Windows.h>
time_spec_t time_spec_t::get_system_time(void){
LARGE_INTEGER counts, freq;
@@ -63,10 +63,10 @@ time_spec_t time_spec_t::get_system_time(void){
QueryPerformanceFrequency(&freq);
return time_spec_t_from_counts(counts.QuadPart, freq.QuadPart);
}
-#endif /* TIME_SPEC_USE_QUERY_PERFORMANCE_COUNTER */
+#endif /* HAVE_QUERY_PERFORMANCE_COUNTER */
-#ifdef TIME_SPEC_USE_MICROSEC_CLOCK
+#ifdef HAVE_MICROSEC_CLOCK
#include <boost/date_time/posix_time/posix_time.hpp>
namespace pt = boost::posix_time;
time_spec_t time_spec_t::get_system_time(void){
@@ -78,7 +78,7 @@ time_spec_t time_spec_t::get_system_time(void){
double(pt::time_duration::ticks_per_second())
);
}
-#endif /* TIME_SPEC_USE_MICROSEC_CLOCK */
+#endif /* HAVE_MICROSEC_CLOCK */
/***********************************************************************
* Time spec constructors
diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp
index 3b0c562ee..3e3cf00f2 100644
--- a/host/lib/usrp/dboard/db_rfx.cpp
+++ b/host/lib/usrp/dboard/db_rfx.cpp
@@ -25,10 +25,6 @@
#define MIXER_ENB MIXER_IO
#define MIXER_DIS 0
-// Power constants
-#define POWER_UP 0
-#define POWER_DOWN POWER_IO
-
// Antenna constants
#define ANT_TX 0 //the tx line is transmitting
#define ANT_RX ANTSW_IO //the tx line is receiving
@@ -100,6 +96,7 @@ private:
double _rx_lo_freq, _tx_lo_freq;
std::string _rx_ant;
uhd::dict<std::string, double> _rx_gains;
+ boost::uint16_t _power_up;
void set_rx_lo_freq(double freq);
void set_tx_lo_freq(double freq);
@@ -130,7 +127,7 @@ private:
* Register the RFX dboards (min freq, max freq, rx div2, tx div2)
**********************************************************************/
static dboard_base::sptr make_rfx_flex400(dboard_base::ctor_args_t args){
- return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(400e6, 500e6), false, true));
+ return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(400e6, 500e6), true, true));
}
static dboard_base::sptr make_rfx_flex900(dboard_base::ctor_args_t args){
@@ -178,7 +175,8 @@ rfx_xcvr::rfx_xcvr(
_div2(map_list_of
(dboard_iface::UNIT_RX, rx_div2)
(dboard_iface::UNIT_TX, tx_div2)
- )
+ ),
+ _power_up((get_rx_id() == 0x0024 && get_tx_id() == 0x0028) ? POWER_IO : 0)
{
//enable the clocks that we need
this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, true);
@@ -192,15 +190,15 @@ rfx_xcvr::rfx_xcvr(
this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, output_enables);
//setup the tx atr (this does not change with antenna)
- this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE, POWER_UP | ANT_XX | MIXER_DIS);
- this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_RX_ONLY, POWER_UP | ANT_RX | MIXER_DIS);
- this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY, POWER_UP | ANT_TX | MIXER_ENB);
- this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, POWER_UP | ANT_TX | MIXER_ENB);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE, _power_up | ANT_XX | MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_RX_ONLY, _power_up | ANT_RX | MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY, _power_up | ANT_TX | MIXER_ENB);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, _power_up | ANT_TX | MIXER_ENB);
//setup the rx atr (this does not change with antenna)
- this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, POWER_UP | ANT_XX | MIXER_DIS);
- this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, POWER_UP | ANT_XX | MIXER_DIS);
- this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, POWER_UP | ANT_RX2| MIXER_ENB);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, _power_up | ANT_XX | MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, _power_up | ANT_XX | MIXER_DIS);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, _power_up | ANT_RX2| MIXER_ENB);
//set some default values
set_rx_lo_freq((_freq_range.start() + _freq_range.stop())/2.0);
@@ -226,7 +224,7 @@ void rfx_xcvr::set_rx_ant(const std::string &ant){
//set the rx atr regs that change with antenna setting
this->get_iface()->set_atr_reg(
dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY,
- POWER_UP | MIXER_ENB | ((ant == "TX/RX")? ANT_TXRX : ANT_RX2)
+ _power_up | MIXER_ENB | ((ant == "TX/RX")? ANT_TXRX : ANT_RX2)
);
//shadow the setting
@@ -363,7 +361,7 @@ double rfx_xcvr::set_lo_freq(
regs.a_counter = A;
regs.b_counter = B;
regs.cp_gain_1 = adf4360_regs_t::CP_GAIN_1_SET1;
- regs.divide_by_2_output = (_div2[unit])?
+ regs.divide_by_2_output = (_div2[unit] && (get_rx_id() != 0x0024)) ? // Special case RFX400 RX Mixer divides by two
adf4360_regs_t::DIVIDE_BY_2_OUTPUT_DIV2 :
adf4360_regs_t::DIVIDE_BY_2_OUTPUT_FUND ;
regs.divide_by_2_prescaler = adf4360_regs_t::DIVIDE_BY_2_PRESCALER_FUND;
diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp
index 73bac029d..5130d3ae8 100644
--- a/host/lib/usrp/multi_usrp.cpp
+++ b/host/lib/usrp/multi_usrp.cpp
@@ -85,17 +85,14 @@ public:
//----------- rx side of life ----------------------------------
for (size_t m = 0, chan = 0; m < get_num_mboards(); m++){
- buff += str(boost::format(
- " RX DSP %d: %s\n"
- ) % m
- % _rx_dsp(m)[DSP_PROP_NAME].as<std::string>()
- );
for (; chan < (m + 1)*get_rx_subdev_spec(m).size(); chan++){
buff += str(boost::format(
" RX Channel: %u\n"
+ " RX DSP: %s\n"
" RX Dboard: %s\n"
" RX Subdev: %s\n"
) % chan
+ % _rx_dsp(chan)[DSP_PROP_NAME].as<std::string>()
% _rx_dboard(chan)[DBOARD_PROP_NAME].as<std::string>()
% _rx_subdev(chan)[SUBDEV_PROP_NAME].as<std::string>()
);
@@ -104,17 +101,14 @@ public:
//----------- tx side of life ----------------------------------
for (size_t m = 0, chan = 0; m < get_num_mboards(); m++){
- buff += str(boost::format(
- " TX DSP %d: %s\n"
- ) % m
- % _tx_dsp(m)[DSP_PROP_NAME].as<std::string>()
- );
for (; chan < (m + 1)*get_tx_subdev_spec(m).size(); chan++){
buff += str(boost::format(
" TX Channel: %u\n"
+ " TX DSP: %s\n"
" TX Dboard: %s\n"
" TX Subdev: %s\n"
) % chan
+ % _tx_dsp(chan)[DSP_PROP_NAME].as<std::string>()
% _tx_dboard(chan)[DBOARD_PROP_NAME].as<std::string>()
% _tx_subdev(chan)[SUBDEV_PROP_NAME].as<std::string>()
);
@@ -194,9 +188,13 @@ public:
return true;
}
- void issue_stream_cmd(const stream_cmd_t &stream_cmd){
- for (size_t m = 0; m < get_num_mboards(); m++){
- _mboard(m)[MBOARD_PROP_STREAM_CMD] = stream_cmd;
+ void issue_stream_cmd(const stream_cmd_t &stream_cmd, size_t chan){
+ if (chan != ALL_CHANS){
+ _rx_dsp(chan)[DSP_PROP_STREAM_CMD] = stream_cmd;
+ return;
+ }
+ for (size_t c = 0; m < get_rx_num_channels(); m++){
+ issue_stream_cmd(stream_cmd, c);
}
}
@@ -248,28 +246,32 @@ public:
}
void set_rx_rate(double rate){
- for (size_t m = 0; m < get_num_mboards(); m++){
- _rx_dsp(m)[DSP_PROP_HOST_RATE] = rate;
+ if (chan != ALL_CHANS){
+ _rx_dsp(chan)[DSP_PROP_HOST_RATE] = rate;
+ do_samp_rate_warning_message(rate, get_rx_rate(chan), "RX");
+ return;
+ }
+ for (size_t c = 0; m < get_rx_num_channels(); m++){
+ set_rx_rate(rate, c);
}
- do_samp_rate_warning_message(rate, get_rx_rate(), "RX");
}
- double get_rx_rate(void){
- return _rx_dsp(0)[DSP_PROP_HOST_RATE].as<double>();
+ double get_rx_rate(size_t chan){
+ return _rx_dsp(chan)[DSP_PROP_HOST_RATE].as<double>();
}
tune_result_t set_rx_freq(const tune_request_t &tune_request, size_t chan){
- tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan/rx_cpm()), chan%rx_cpm(), tune_request);
+ tune_result_t r = tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), chan%rx_cpm(), tune_request);
do_tune_freq_warning_message(tune_request.target_freq, get_rx_freq(chan), "RX");
return r;
}
double get_rx_freq(size_t chan){
- return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan/rx_cpm()), chan%rx_cpm());
+ return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), chan%rx_cpm());
}
freq_range_t get_rx_freq_range(size_t chan){
- return add_dsp_shift(_rx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _rx_dsp(chan/rx_cpm()));
+ return add_dsp_shift(_rx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _rx_dsp(chan));
}
void set_rx_gain(double gain, const std::string &name, size_t chan){
@@ -346,28 +348,32 @@ public:
}
void set_tx_rate(double rate){
- for (size_t m = 0; m < get_num_mboards(); m++){
- _tx_dsp(m)[DSP_PROP_HOST_RATE] = rate;
+ if (chan != ALL_CHANS){
+ _tx_dsp(chan)[DSP_PROP_HOST_RATE] = rate;
+ do_samp_rate_warning_message(rate, get_tx_rate(chan), "TX");
+ return;
+ }
+ for (size_t c = 0; m < get_tx_num_channels(); m++){
+ set_tx_rate(rate, c);
}
- do_samp_rate_warning_message(rate, get_tx_rate(), "TX");
}
- double get_tx_rate(void){
- return _tx_dsp(0)[DSP_PROP_HOST_RATE].as<double>();
+ double get_tx_rate(size_t chan){
+ return _tx_dsp(chan)[DSP_PROP_HOST_RATE].as<double>();
}
tune_result_t set_tx_freq(const tune_request_t &tune_request, size_t chan){
- tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan/tx_cpm()), chan%tx_cpm(), tune_request);
+ tune_result_t r = tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), chan%tx_cpm(), tune_request);
do_tune_freq_warning_message(tune_request.target_freq, get_tx_freq(chan), "TX");
return r;
}
double get_tx_freq(size_t chan){
- return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan/tx_cpm()), chan%tx_cpm());
+ return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), chan%tx_cpm());
}
freq_range_t get_tx_freq_range(size_t chan){
- return add_dsp_shift(_tx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _tx_dsp(chan/tx_cpm()));
+ return add_dsp_shift(_tx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _tx_dsp(chan));
}
void set_tx_gain(double gain, const std::string &name, size_t chan){
@@ -445,11 +451,13 @@ private:
std::string mb_name = (*_dev)[DEVICE_PROP_MBOARD_NAMES].as<prop_names_t>().at(mboard);
return (*_dev)[named_prop_t(DEVICE_PROP_MBOARD, mb_name)];
}
- wax::obj _rx_dsp(size_t mboard){
- return _mboard(mboard)[MBOARD_PROP_RX_DSP];
+ wax::obj _rx_dsp(size_t chan){
+ prop_names_t dsp_names = _mboard(chan/rx_cpm())[MBOARD_PROP_RX_DSP_NAMES].as<prop_names_t>();
+ return _mboard(chan/rx_cpm())[named_prop_t(MBOARD_PROP_RX_DSP, dsp_names.at(chan%rx_cpm())];
}
- wax::obj _tx_dsp(size_t mboard){
- return _mboard(mboard)[MBOARD_PROP_TX_DSP];
+ wax::obj _tx_dsp(size_t chan){
+ prop_names_t dsp_names = _mboard(chan/tx_cpm())[MBOARD_PROP_TX_DSP_NAMES].as<prop_names_t>();
+ return _mboard(chan/tx_cpm())[named_prop_t(MBOARD_PROP_TX_DSP, dsp_names.at(chan%tx_cpm())];
}
wax::obj _rx_dboard(size_t chan){
std::string db_name = get_rx_subdev_spec(chan/rx_cpm()).at(chan%rx_cpm()).db_name;
diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp
index 88cbab073..8beeccf8f 100644
--- a/host/lib/usrp/usrp1/io_impl.cpp
+++ b/host/lib/usrp/usrp1/io_impl.cpp
@@ -37,21 +37,64 @@ static const size_t alignment_padding = 512;
/***********************************************************************
* Helper struct to associate an offset with a buffer
**********************************************************************/
-class offset_send_buffer{
-public:
- typedef boost::shared_ptr<offset_send_buffer> sptr;
+struct offset_send_buffer{
+ offset_send_buffer(void){
+ /* NOP */
+ }
- static sptr make(managed_send_buffer::sptr buff, size_t offset = 0){
- return sptr(new offset_send_buffer(buff, offset));
+ offset_send_buffer(managed_send_buffer::sptr buff, size_t offset = 0):
+ buff(buff), offset(offset)
+ {
+ /* NOP */
}
//member variables
managed_send_buffer::sptr buff;
size_t offset; /* in bytes */
+};
+
+/***********************************************************************
+ * Reusable managed send buffer to handle aligned commits
+ **********************************************************************/
+class offset_managed_send_buffer : public managed_send_buffer{
+public:
+ typedef boost::function<void(offset_send_buffer&, offset_send_buffer&, size_t)> commit_cb_type;
+ offset_managed_send_buffer(const commit_cb_type &commit_cb):
+ _expired(true), _commit_cb(commit_cb)
+ {
+ /* NOP */
+ }
+
+ bool expired(void){return _expired;}
+
+ void commit(size_t size){
+ if (_expired) return;
+ this->_commit_cb(_curr_buff, _next_buff, size);
+ _expired = true;
+ }
+
+ sptr get_new(
+ offset_send_buffer &curr_buff,
+ offset_send_buffer &next_buff
+ ){
+ _expired = false;
+ _curr_buff = curr_buff;
+ _next_buff = next_buff;
+ return sptr(this, &offset_managed_send_buffer::fake_deleter);
+ }
private:
- offset_send_buffer(managed_send_buffer::sptr buff, size_t offset):
- buff(buff), offset(offset){/* NOP */}
+ static void fake_deleter(void *){
+ //dont do anything and assume the bastard committed it
+ //static_cast<offset_managed_send_buffer *>(obj)->commit(0);
+ }
+
+ void *get_buff(void) const{return _curr_buff.buff->cast<char *>() + _curr_buff.offset;}
+ size_t get_size(void) const{return _curr_buff.buff->size() - _curr_buff.offset;}
+
+ bool _expired;
+ offset_send_buffer _curr_buff, _next_buff;
+ commit_cb_type _commit_cb;
};
/***********************************************************************
@@ -60,10 +103,12 @@ private:
struct usrp1_impl::io_impl{
io_impl(zero_copy_if::sptr data_transport):
data_transport(data_transport),
+ get_recv_buffs_fcn(boost::bind(&usrp1_impl::io_impl::get_recv_buffs, this, _1)),
+ get_send_buffs_fcn(boost::bind(&usrp1_impl::io_impl::get_send_buffs, this, _1)),
underflow_poll_samp_count(0),
overflow_poll_samp_count(0),
- curr_buff_committed(true),
- curr_buff(offset_send_buffer::make(data_transport->get_send_buff()))
+ curr_buff(offset_send_buffer(data_transport->get_send_buff())),
+ omsb(boost::bind(&usrp1_impl::io_impl::commit_send_buff, this, _1, _2, _3))
{
/* NOP */
}
@@ -74,6 +119,13 @@ struct usrp1_impl::io_impl{
zero_copy_if::sptr data_transport;
+ //timeouts set on calls to recv/send (passed into get buffs methods)
+ double recv_timeout, send_timeout;
+
+ //bound callbacks for get buffs (bound once here, not in fast-path)
+ vrt_packet_handler::get_recv_buffs_t get_recv_buffs_fcn;
+ vrt_packet_handler::get_send_buffs_t get_send_buffs_fcn;
+
//state management for the vrt packet handler code
vrt_packet_handler::recv_state packet_handler_recv_state;
vrt_packet_handler::send_state packet_handler_send_state;
@@ -86,11 +138,16 @@ struct usrp1_impl::io_impl{
//all of this to ensure only aligned lengths are committed
//NOTE: you must commit before getting a new buffer
//since the vrt packet handler obeys this, we are ok
- bool curr_buff_committed;
- offset_send_buffer::sptr curr_buff;
- void commit_send_buff(offset_send_buffer::sptr, offset_send_buffer::sptr, size_t);
+ offset_send_buffer curr_buff;
+ offset_managed_send_buffer omsb;
+ void commit_send_buff(offset_send_buffer&, offset_send_buffer&, size_t);
void flush_send_buff(void);
- bool get_send_buffs(vrt_packet_handler::managed_send_buffs_t &, double);
+ bool get_send_buffs(vrt_packet_handler::managed_send_buffs_t &);
+ bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs){
+ UHD_ASSERT_THROW(buffs.size() == 1);
+ buffs[0] = data_transport->get_recv_buff(recv_timeout);
+ return buffs[0].get() != NULL;
+ }
};
/*!
@@ -99,12 +156,12 @@ struct usrp1_impl::io_impl{
* Commit the current buffer at multiples of alignment.
*/
void usrp1_impl::io_impl::commit_send_buff(
- offset_send_buffer::sptr curr,
- offset_send_buffer::sptr next,
+ offset_send_buffer &curr,
+ offset_send_buffer &next,
size_t num_bytes
){
//total number of bytes now in the current buffer
- size_t bytes_in_curr_buffer = curr->offset + num_bytes;
+ size_t bytes_in_curr_buffer = curr.offset + num_bytes;
//calculate how many to commit and remainder
size_t num_bytes_remaining = bytes_in_curr_buffer % alignment_padding;
@@ -112,17 +169,16 @@ void usrp1_impl::io_impl::commit_send_buff(
//copy the remainder into the next buffer
std::memcpy(
- next->buff->cast<char *>() + next->offset,
- curr->buff->cast<char *>() + num_bytes_to_commit,
+ next.buff->cast<char *>() + next.offset,
+ curr.buff->cast<char *>() + num_bytes_to_commit,
num_bytes_remaining
);
//update the offset into the next buffer
- next->offset += num_bytes_remaining;
+ next.offset += num_bytes_remaining;
//commit the current buffer
- curr->buff->commit(num_bytes_to_commit);
- curr_buff_committed = true;
+ curr.buff->commit(num_bytes_to_commit);
}
/*!
@@ -130,14 +186,14 @@ void usrp1_impl::io_impl::commit_send_buff(
*/
void usrp1_impl::io_impl::flush_send_buff(void){
//calculate the number of bytes to alignment
- size_t bytes_to_pad = (-1*curr_buff->offset)%alignment_padding;
+ size_t bytes_to_pad = (-1*curr_buff.offset)%alignment_padding;
//send at least alignment_padding to guarantee zeros are sent
if (bytes_to_pad == 0) bytes_to_pad = alignment_padding;
//get the buffer, clear, and commit (really current buffer)
vrt_packet_handler::managed_send_buffs_t buffs(1);
- if (this->get_send_buffs(buffs, 0.1)){
+ if (this->get_send_buffs(buffs)){
std::memset(buffs[0]->cast<void *>(), 0, bytes_to_pad);
buffs[0]->commit(bytes_to_pad);
}
@@ -148,25 +204,19 @@ void usrp1_impl::io_impl::flush_send_buff(void){
* Always grab the next send buffer so we can timeout here.
*/
bool usrp1_impl::io_impl::get_send_buffs(
- vrt_packet_handler::managed_send_buffs_t &buffs, double timeout
+ vrt_packet_handler::managed_send_buffs_t &buffs
){
- UHD_ASSERT_THROW(curr_buff_committed and buffs.size() == 1);
+ UHD_ASSERT_THROW(omsb.expired() and buffs.size() == 1);
//try to get a new managed buffer with timeout
- offset_send_buffer::sptr next_buff(offset_send_buffer::make(data_transport->get_send_buff(timeout)));
- if (not next_buff->buff.get()) return false; /* propagate timeout here */
-
- //calculate the buffer pointer and size given the offset
- //references to the buffers are held in the bound function
- buffs[0] = managed_send_buffer::make_safe(
- curr_buff->buff->cast<char *>() + curr_buff->offset,
- curr_buff->buff->size() - curr_buff->offset,
- boost::bind(&usrp1_impl::io_impl::commit_send_buff, this, curr_buff, next_buff, _1)
- );
+ offset_send_buffer next_buff(data_transport->get_send_buff(send_timeout));
+ if (not next_buff.buff.get()) return false; /* propagate timeout here */
+
+ //make a new managed buffer with the offset buffs
+ buffs[0] = omsb.get_new(curr_buff, next_buff);
//store the next buffer for the next call
curr_buff = next_buff;
- curr_buff_committed = false;
return true;
}
@@ -226,6 +276,7 @@ size_t usrp1_impl::send(
){
if (_soft_time_ctrl->send_pre(metadata, timeout)) return num_samps;
+ _io_impl->send_timeout = timeout;
size_t num_samps_sent = vrt_packet_handler::send(
_io_impl->packet_handler_send_state, //last state of the send handler
buffs, num_samps, //buffer to fill
@@ -233,7 +284,7 @@ size_t usrp1_impl::send(
io_type, _tx_otw_type, //input and output types to convert
_clock_ctrl->get_master_clock_freq(), //master clock tick rate
&usrp1_bs_vrt_packer,
- boost::bind(&usrp1_impl::io_impl::get_send_buffs, _io_impl.get(), _1, timeout),
+ _io_impl->get_send_buffs_fcn,
get_max_send_samps_per_packet(),
0, //vrt header offset
_tx_subdev_spec.size() //num channels
@@ -281,15 +332,6 @@ static void usrp1_bs_vrt_unpacker(
if_packet_info.has_tlr = false;
}
-static bool get_recv_buffs(
- zero_copy_if::sptr zc_if, double timeout,
- vrt_packet_handler::managed_recv_buffs_t &buffs
-){
- UHD_ASSERT_THROW(buffs.size() == 1);
- buffs[0] = zc_if->get_recv_buff(timeout);
- return buffs[0].get() != NULL;
-}
-
size_t usrp1_impl::get_max_recv_samps_per_packet(void) const {
return _data_transport->get_recv_frame_size()
/ _rx_otw_type.get_sample_size()
@@ -302,6 +344,7 @@ size_t usrp1_impl::recv(
rx_metadata_t &metadata, const io_type_t &io_type,
recv_mode_t recv_mode, double timeout
){
+ _io_impl->recv_timeout = timeout;
size_t num_samps_recvd = vrt_packet_handler::recv(
_io_impl->packet_handler_recv_state, //last state of the recv handler
buffs, num_samps, //buffer to fill
@@ -309,7 +352,7 @@ size_t usrp1_impl::recv(
io_type, _rx_otw_type, //input and output types to convert
_clock_ctrl->get_master_clock_freq(), //master clock tick rate
&usrp1_bs_vrt_unpacker,
- boost::bind(&get_recv_buffs, _data_transport, timeout, _1),
+ _io_impl->get_recv_buffs_fcn,
&vrt_packet_handler::handle_overflow_nop,
0, //vrt header offset
_rx_subdev_spec.size() //num channels
diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp
index 8340f7cdd..5cf48fe96 100644
--- a/host/lib/usrp/usrp2/dsp_impl.cpp
+++ b/host/lib/usrp/usrp2/dsp_impl.cpp
@@ -98,7 +98,7 @@ void usrp2_mboard_impl::ddc_set(const wax::obj &key_, const wax::obj &val){
case DSP_PROP_FREQ_SHIFT:{
double new_freq = val.as<double>();
- _iface->poke32(_iface->regs.dsp_rx_freq,
+ _iface->poke32(_iface->regs.dsp0_rx_freq,
dsp_type1::calc_cordic_word_and_update(new_freq, get_master_clock_freq())
);
_ddc_freq = new_freq; //shadow
@@ -110,11 +110,11 @@ void usrp2_mboard_impl::ddc_set(const wax::obj &key_, const wax::obj &val){
_ddc_decim = pick_closest_rate(extact_rate, _allowed_decim_and_interp_rates);
//set the decimation
- _iface->poke32(_iface->regs.dsp_rx_decim_rate, dsp_type1::calc_cic_filter_word(_ddc_decim));
+ _iface->poke32(_iface->regs.dsp0_rx_decim_rate, dsp_type1::calc_cic_filter_word(_ddc_decim));
//set the scaling
static const boost::int16_t default_rx_scale_iq = 1024;
- _iface->poke32(_iface->regs.dsp_rx_scale_iq,
+ _iface->poke32(_iface->regs.dsp0_rx_scale_iq,
dsp_type1::calc_iq_scale_word(default_rx_scale_iq, default_rx_scale_iq)
);
}
diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h
index a22f805e1..33c0b728a 100644
--- a/host/lib/usrp/usrp2/fw_common.h
+++ b/host/lib/usrp/usrp2/fw_common.h
@@ -31,7 +31,7 @@ extern "C" {
//fpga and firmware compatibility numbers
#define USRP2_FPGA_COMPAT_NUM 4
-#define USRP2_FW_COMPAT_NUM 8
+#define USRP2_FW_COMPAT_NUM 9
//used to differentiate control packets over data port
#define USRP2_INVALID_VRT_HEADER 0
@@ -40,8 +40,9 @@ extern "C" {
// Dynamic and/or private ports: 49152-65535
#define USRP2_UDP_CTRL_PORT 49152
//#define USRP2_UDP_UPDATE_PORT 49154
-#define USRP2_UDP_DATA_PORT 49156
+#define USRP2_UDP_DSP0_PORT 49156
#define USRP2_UDP_ERR0_PORT 49157
+#define USRP2_UDP_DSP1_PORT 49158
////////////////////////////////////////////////////////////////////////
// I2C addresses
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index 67b52db71..b20b6652e 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -121,13 +121,12 @@ struct usrp2_impl::io_impl{
io_impl(size_t send_frame_size, const std::vector<zero_copy_if::sptr> &xports):
xports(xports),
+ get_recv_buffs_fcn(boost::bind(&usrp2_impl::io_impl::get_recv_buffs, this, _1)),
+ get_send_buffs_fcn(boost::bind(&usrp2_impl::io_impl::get_send_buffs, this, _1)),
packet_handler_recv_state(xports.size()),
packet_handler_send_state(xports.size()),
async_msg_fifo(100/*messages deep*/)
{
- get_recv_buffs_fcn = boost::bind(&usrp2_impl::io_impl::get_recv_buffs, this, _1);
- get_send_buffs_fcn = boost::bind(&usrp2_impl::io_impl::get_send_buffs, this, _1);
-
for (size_t i = 0; i < xports.size(); i++){
fc_mons.push_back(flow_control_monitor::sptr(
new flow_control_monitor(usrp2_impl::sram_bytes/send_frame_size)
diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp
index 397fae636..5fbbfc0ee 100644
--- a/host/lib/usrp/usrp2/mboard_impl.cpp
+++ b/host/lib/usrp/usrp2/mboard_impl.cpp
@@ -87,17 +87,17 @@ usrp2_mboard_impl::usrp2_mboard_impl(
}
//setup the vrt rx registers
- _iface->poke32(_iface->regs.rx_ctrl_clear_overrun, 1); //reset
- _iface->poke32(_iface->regs.rx_ctrl_nsamps_per_pkt, recv_samps_per_packet);
- _iface->poke32(_iface->regs.rx_ctrl_nchannels, 1);
- _iface->poke32(_iface->regs.rx_ctrl_vrt_header, 0
+ _iface->poke32(_iface->regs.rx_ctrl0_clear_overrun, 1); //reset
+ _iface->poke32(_iface->regs.rx_ctrl0_nsamps_per_pkt, recv_samps_per_packet);
+ _iface->poke32(_iface->regs.rx_ctrl0_nchannels, 1);
+ _iface->poke32(_iface->regs.rx_ctrl0_vrt_header, 0
| (0x1 << 28) //if data with stream id
| (0x1 << 26) //has trailer
| (0x3 << 22) //integer time other
| (0x1 << 20) //fractional time sample count
);
- _iface->poke32(_iface->regs.rx_ctrl_vrt_stream_id, usrp2_impl::RECV_SID);
- _iface->poke32(_iface->regs.rx_ctrl_vrt_trailer, 0);
+ _iface->poke32(_iface->regs.rx_ctrl0_vrt_stream_id, usrp2_impl::RECV_SID);
+ _iface->poke32(_iface->regs.rx_ctrl0_vrt_trailer, 0);
_iface->poke32(_iface->regs.time64_tps, size_t(get_master_clock_freq()));
//init the tx control registers
@@ -164,7 +164,7 @@ usrp2_mboard_impl::usrp2_mboard_impl(
this->issue_ddc_stream_cmd(stream_cmd);
data_transport->get_recv_buff().get(); //recv with timeout for lingering
data_transport->get_recv_buff().get(); //recv with timeout for expected
- _iface->poke32(_iface->regs.rx_ctrl_clear_overrun, 1); //resets sequence
+ _iface->poke32(_iface->regs.rx_ctrl0_clear_overrun, 1); //resets sequence
}
usrp2_mboard_impl::~usrp2_mboard_impl(void){
@@ -273,9 +273,9 @@ void usrp2_mboard_impl::handle_overflow(void){
void usrp2_mboard_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){
_continuous_streaming = stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS;
- _iface->poke32(_iface->regs.rx_ctrl_stream_cmd, dsp_type1::calc_stream_cmd_word(stream_cmd));
- _iface->poke32(_iface->regs.rx_ctrl_time_secs, boost::uint32_t(stream_cmd.time_spec.get_full_secs()));
- _iface->poke32(_iface->regs.rx_ctrl_time_ticks, stream_cmd.time_spec.get_tick_count(get_master_clock_freq()));
+ _iface->poke32(_iface->regs.rx_ctrl0_stream_cmd, dsp_type1::calc_stream_cmd_word(stream_cmd));
+ _iface->poke32(_iface->regs.rx_ctrl0_time_secs, boost::uint32_t(stream_cmd.time_spec.get_full_secs()));
+ _iface->poke32(_iface->regs.rx_ctrl0_time_ticks, stream_cmd.time_spec.get_tick_count(get_master_clock_freq()));
}
/***********************************************************************
@@ -399,10 +399,13 @@ void usrp2_mboard_impl::set(const wax::obj &key, const wax::obj &val){
_rx_subdev_spec = val.as<subdev_spec_t>();
verify_rx_subdev_spec(_rx_subdev_spec, this->get_link());
//sanity check
- UHD_ASSERT_THROW(_rx_subdev_spec.size() == 1);
+ UHD_ASSERT_THROW(_rx_subdev_spec.size() <= 2);
//set the mux
- _iface->poke32(_iface->regs.dsp_rx_mux, dsp_type1::calc_rx_mux_word(
- _dboard_manager->get_rx_subdev(_rx_subdev_spec.front().sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()
+ if (_rx_subdev_spec.size() >= 1) _iface->poke32(_iface->regs.dsp0_rx_mux, dsp_type1::calc_rx_mux_word(
+ _dboard_manager->get_rx_subdev(_rx_subdev_spec[0].sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()
+ ));
+ if (_rx_subdev_spec.size() >= 2)_iface->poke32(_iface->regs.dsp1_rx_mux, dsp_type1::calc_rx_mux_word(
+ _dboard_manager->get_rx_subdev(_rx_subdev_spec[1].sd_name)[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()
));
return;
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index 9ce0f7359..d40a96364 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -220,7 +220,7 @@ static device::sptr usrp2_make(const device_addr_t &device_addr){
dev_addr_i["addr"], num2str(USRP2_UDP_CTRL_PORT)
));
data_transports.push_back(udp_zero_copy::make(
- dev_addr_i["addr"], num2str(USRP2_UDP_DATA_PORT), dsp_xport_hints
+ dev_addr_i["addr"], num2str(USRP2_UDP_DSP0_PORT), dsp_xport_hints
));
err0_transports.push_back(udp_zero_copy::make(
dev_addr_i["addr"], num2str(USRP2_UDP_ERR0_PORT), device_addr_t()
diff --git a/host/lib/usrp/usrp2/usrp2_regs.cpp b/host/lib/usrp/usrp2/usrp2_regs.cpp
index 84907c32e..2159c4276 100644
--- a/host/lib/usrp/usrp2/usrp2_regs.cpp
+++ b/host/lib/usrp/usrp2/usrp2_regs.cpp
@@ -38,8 +38,10 @@ usrp2_regs_t usrp2_get_regs(bool use_n2xx_map) {
x.sr_udp_sm = 96;
x.sr_tx_dsp = 208;
x.sr_tx_ctrl = 224;
- x.sr_rx_dsp = 160;
- x.sr_rx_ctrl = 176;
+ x.sr_rx_dsp0 = 160;
+ x.sr_rx_ctrl0 = 176;
+ x.sr_rx_dsp1 = 240;
+ x.sr_rx_ctrl1 = 32;
x.sr_time64 = 192;
x.sr_simtimer = 198;
x.sr_last = 255;
@@ -68,12 +70,12 @@ usrp2_regs_t usrp2_get_regs(bool use_n2xx_map) {
x.dsp_tx_scale_iq = sr_addr(misc_output_base, x.sr_tx_dsp + 1);
x.dsp_tx_interp_rate = sr_addr(misc_output_base, x.sr_tx_dsp + 2);
x.dsp_tx_mux = sr_addr(misc_output_base, x.sr_tx_dsp + 4);
- x.dsp_rx_freq = sr_addr(misc_output_base, x.sr_rx_dsp + 0);
- x.dsp_rx_scale_iq = sr_addr(misc_output_base, x.sr_rx_dsp + 1);
- x.dsp_rx_decim_rate = sr_addr(misc_output_base, x.sr_rx_dsp + 2);
- x.dsp_rx_dcoffset_i = sr_addr(misc_output_base, x.sr_rx_dsp + 3);
- x.dsp_rx_dcoffset_q = sr_addr(misc_output_base, x.sr_rx_dsp + 4);
- x.dsp_rx_mux = sr_addr(misc_output_base, x.sr_rx_dsp + 5);
+ x.dsp0_rx_freq = sr_addr(misc_output_base, x.sr_rx_dsp0 + 0);
+ x.dsp0_rx_scale_iq = sr_addr(misc_output_base, x.sr_rx_dsp0 + 1);
+ x.dsp0_rx_decim_rate = sr_addr(misc_output_base, x.sr_rx_dsp0 + 2);
+ x.dsp0_rx_dcoffset_i = sr_addr(misc_output_base, x.sr_rx_dsp0 + 3);
+ x.dsp0_rx_dcoffset_q = sr_addr(misc_output_base, x.sr_rx_dsp0 + 4);
+ x.dsp0_rx_mux = sr_addr(misc_output_base, x.sr_rx_dsp0 + 5);
x.gpio_io = gpio_base + 0;
x.gpio_ddr = gpio_base + 4;
x.gpio_tx_sel = gpio_base + 8;
@@ -86,15 +88,15 @@ usrp2_regs_t usrp2_get_regs(bool use_n2xx_map) {
x.atr_inrx_rxside = atr_base + 10;
x.atr_full_txside = atr_base + 12;
x.atr_full_rxside = atr_base + 14;
- x.rx_ctrl_stream_cmd = sr_addr(misc_output_base, x.sr_rx_ctrl + 0);
- x.rx_ctrl_time_secs = sr_addr(misc_output_base, x.sr_rx_ctrl + 1);
- x.rx_ctrl_time_ticks = sr_addr(misc_output_base, x.sr_rx_ctrl + 2);
- x.rx_ctrl_clear_overrun = sr_addr(misc_output_base, x.sr_rx_ctrl + 3);
- x.rx_ctrl_vrt_header = sr_addr(misc_output_base, x.sr_rx_ctrl + 4);
- x.rx_ctrl_vrt_stream_id = sr_addr(misc_output_base, x.sr_rx_ctrl + 5);
- x.rx_ctrl_vrt_trailer = sr_addr(misc_output_base, x.sr_rx_ctrl + 6);
- x.rx_ctrl_nsamps_per_pkt = sr_addr(misc_output_base, x.sr_rx_ctrl + 7);
- x.rx_ctrl_nchannels = sr_addr(misc_output_base, x.sr_rx_ctrl + 8);
+ x.rx_ctrl0_stream_cmd = sr_addr(misc_output_base, x.sr_rx_ctrl0 + 0);
+ x.rx_ctrl0_time_secs = sr_addr(misc_output_base, x.sr_rx_ctrl0 + 1);
+ x.rx_ctrl0_time_ticks = sr_addr(misc_output_base, x.sr_rx_ctrl0 + 2);
+ x.rx_ctrl0_clear_overrun = sr_addr(misc_output_base, x.sr_rx_ctrl0 + 3);
+ x.rx_ctrl0_vrt_header = sr_addr(misc_output_base, x.sr_rx_ctrl0 + 4);
+ x.rx_ctrl0_vrt_stream_id = sr_addr(misc_output_base, x.sr_rx_ctrl0 + 5);
+ x.rx_ctrl0_vrt_trailer = sr_addr(misc_output_base, x.sr_rx_ctrl0 + 6);
+ x.rx_ctrl0_nsamps_per_pkt = sr_addr(misc_output_base, x.sr_rx_ctrl0 + 7);
+ x.rx_ctrl0_nchannels = sr_addr(misc_output_base, x.sr_rx_ctrl0 + 8);
x.tx_ctrl_num_chan = sr_addr(misc_output_base, x.sr_tx_ctrl + 0);
x.tx_ctrl_clear_state = sr_addr(misc_output_base, x.sr_tx_ctrl + 1);
x.tx_ctrl_report_sid = sr_addr(misc_output_base, x.sr_tx_ctrl + 2);
diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp
index 977b342cb..e150528a7 100644
--- a/host/lib/usrp/usrp2/usrp2_regs.hpp
+++ b/host/lib/usrp/usrp2/usrp2_regs.hpp
@@ -38,8 +38,10 @@ typedef struct {
int sr_udp_sm;
int sr_tx_dsp;
int sr_tx_ctrl;
- int sr_rx_dsp;
- int sr_rx_ctrl;
+ int sr_rx_dsp0;
+ int sr_rx_ctrl0;
+ int sr_rx_dsp1;
+ int sr_rx_ctrl1;
int sr_time64;
int sr_simtimer;
int sr_last;
@@ -68,12 +70,12 @@ typedef struct {
int dsp_tx_scale_iq;
int dsp_tx_interp_rate;
int dsp_tx_mux;
- int dsp_rx_freq;
- int dsp_rx_scale_iq;
- int dsp_rx_decim_rate;
- int dsp_rx_dcoffset_i;
- int dsp_rx_dcoffset_q;
- int dsp_rx_mux;
+ int dsp0_rx_freq;
+ int dsp0_rx_scale_iq;
+ int dsp0_rx_decim_rate;
+ int dsp0_rx_dcoffset_i;
+ int dsp0_rx_dcoffset_q;
+ int dsp0_rx_mux;
int gpio_base;
int gpio_io;
int gpio_ddr;
@@ -88,15 +90,15 @@ typedef struct {
int atr_inrx_rxside;
int atr_full_txside;
int atr_full_rxside;
- int rx_ctrl_stream_cmd;
- int rx_ctrl_time_secs;
- int rx_ctrl_time_ticks;
- int rx_ctrl_clear_overrun;
- int rx_ctrl_vrt_header;
- int rx_ctrl_vrt_stream_id;
- int rx_ctrl_vrt_trailer;
- int rx_ctrl_nsamps_per_pkt;
- int rx_ctrl_nchannels;
+ int rx_ctrl0_stream_cmd;
+ int rx_ctrl0_time_secs;
+ int rx_ctrl0_time_ticks;
+ int rx_ctrl0_clear_overrun;
+ int rx_ctrl0_vrt_header;
+ int rx_ctrl0_vrt_stream_id;
+ int rx_ctrl0_vrt_trailer;
+ int rx_ctrl0_nsamps_per_pkt;
+ int rx_ctrl0_nchannels;
int tx_ctrl_num_chan;
int tx_ctrl_clear_state;
int tx_ctrl_report_sid;
diff --git a/host/lib/usrp/usrp_e100/io_impl.cpp b/host/lib/usrp/usrp_e100/io_impl.cpp
index 5fb2da7b8..fc6aaeaee 100644
--- a/host/lib/usrp/usrp_e100/io_impl.cpp
+++ b/host/lib/usrp/usrp_e100/io_impl.cpp
@@ -48,13 +48,10 @@ static const bool recv_debug = false;
* - vrt packet handler states
**********************************************************************/
struct usrp_e100_impl::io_impl{
- //state management for the vrt packet handler code
- vrt_packet_handler::recv_state packet_handler_recv_state;
- vrt_packet_handler::send_state packet_handler_send_state;
- zero_copy_if::sptr data_xport;
- bool continuous_streaming;
io_impl(usrp_e100_iface::sptr iface):
data_xport(usrp_e100_make_mmap_zero_copy(iface)),
+ get_recv_buffs_fcn(boost::bind(&usrp_e100_impl::io_impl::get_recv_buffs, this, _1)),
+ get_send_buffs_fcn(boost::bind(&usrp_e100_impl::io_impl::get_send_buffs, this, _1)),
recv_pirate_booty(data_xport->get_num_recv_frames()),
async_msg_fifo(100/*messages deep*/)
{
@@ -67,12 +64,34 @@ struct usrp_e100_impl::io_impl{
recv_pirate_crew.join_all();
}
- bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs, double timeout){
+ bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs){
UHD_ASSERT_THROW(buffs.size() == 1);
boost::this_thread::disable_interruption di; //disable because the wait can throw
- return recv_pirate_booty.pop_with_timed_wait(buffs.front(), timeout);
+ return recv_pirate_booty.pop_with_timed_wait(buffs.front(), recv_timeout);
}
+ bool get_send_buffs(vrt_packet_handler::managed_send_buffs_t &buffs){
+ UHD_ASSERT_THROW(buffs.size() == 1);
+ buffs[0] = data_xport->get_send_buff(send_timeout);
+ return buffs[0].get() != NULL;
+ }
+
+ //The data transport is listed first so that it is deconstructed last,
+ //which is after the states and booty which may hold managed buffers.
+ zero_copy_if::sptr data_xport;
+
+ //bound callbacks for get buffs (bound once here, not in fast-path)
+ vrt_packet_handler::get_recv_buffs_t get_recv_buffs_fcn;
+ vrt_packet_handler::get_send_buffs_t get_send_buffs_fcn;
+
+ //timeouts set on calls to recv/send (passed into get buffs methods)
+ double recv_timeout, send_timeout;
+
+ //state management for the vrt packet handler code
+ vrt_packet_handler::recv_state packet_handler_recv_state;
+ vrt_packet_handler::send_state packet_handler_send_state;
+ bool continuous_streaming;
+
//a pirate's life is the life for me!
void recv_pirate_loop(usrp_e100_clock_ctrl::sptr);
bounded_buffer<managed_recv_buffer::sptr> recv_pirate_booty;
@@ -204,15 +223,6 @@ void usrp_e100_impl::handle_overrun(size_t){
/***********************************************************************
* Data Send
**********************************************************************/
-bool get_send_buffs(
- zero_copy_if::sptr trans, double timeout,
- vrt_packet_handler::managed_send_buffs_t &buffs
-){
- UHD_ASSERT_THROW(buffs.size() == 1);
- buffs[0] = trans->get_send_buff(timeout);
- return buffs[0].get() != NULL;
-}
-
size_t usrp_e100_impl::get_max_send_samps_per_packet(void) const{
static const size_t hdr_size = 0
+ vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
@@ -227,6 +237,7 @@ size_t usrp_e100_impl::send(
const tx_metadata_t &metadata, const io_type_t &io_type,
send_mode_t send_mode, double timeout
){
+ _io_impl->send_timeout = timeout;
return vrt_packet_handler::send(
_io_impl->packet_handler_send_state, //last state of the send handler
buffs, num_samps, //buffer to fill
@@ -234,7 +245,7 @@ size_t usrp_e100_impl::send(
io_type, _send_otw_type, //input and output types to convert
_clock_ctrl->get_fpga_clock_rate(), //master clock tick rate
uhd::transport::vrt::if_hdr_pack_le,
- boost::bind(&get_send_buffs, _io_impl->data_xport, timeout, _1),
+ _io_impl->get_send_buffs_fcn,
get_max_send_samps_per_packet()
);
}
@@ -257,6 +268,7 @@ size_t usrp_e100_impl::recv(
rx_metadata_t &metadata, const io_type_t &io_type,
recv_mode_t recv_mode, double timeout
){
+ _io_impl->recv_timeout = timeout;
return vrt_packet_handler::recv(
_io_impl->packet_handler_recv_state, //last state of the recv handler
buffs, num_samps, //buffer to fill
@@ -264,7 +276,7 @@ size_t usrp_e100_impl::recv(
io_type, _recv_otw_type, //input and output types to convert
_clock_ctrl->get_fpga_clock_rate(), //master clock tick rate
uhd::transport::vrt::if_hdr_unpack_le,
- boost::bind(&usrp_e100_impl::io_impl::get_recv_buffs, _io_impl.get(), _1, timeout),
+ _io_impl->get_recv_buffs_fcn,
boost::bind(&usrp_e100_impl::handle_overrun, this, _1)
);
}
diff --git a/host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp b/host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp
index 4e0137fdb..c155d426a 100644
--- a/host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp
+++ b/host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp
@@ -22,7 +22,7 @@
#include <sys/mman.h> //mmap
#include <unistd.h> //getpagesize
#include <poll.h> //poll
-#include <boost/bind.hpp>
+#include <vector>
#include <iostream>
using namespace uhd;
@@ -33,6 +33,82 @@ static const bool sp_verbose = false; //slow-path verbose
static const size_t poll_breakout = 10; //how many poll timeouts constitute a full timeout
/***********************************************************************
+ * Reusable managed receiver buffer:
+ * - The buffer knows how to claim and release a frame.
+ **********************************************************************/
+class usrp_e100_mmap_zero_copy_mrb : public managed_recv_buffer{
+public:
+ usrp_e100_mmap_zero_copy_mrb(void *mem, ring_buffer_info *info):
+ _mem(mem), _info(info) { /* NOP */ }
+
+ void release(void){
+ if (_info->flags != RB_USER_PROCESS) return;
+ if (fp_verbose) std::cout << "recv buff: release" << std::endl;
+ _info->flags = RB_KERNEL; //release the frame
+ }
+
+ bool ready(void){return _info->flags & RB_USER;}
+
+ sptr get_new(void){
+ if (fp_verbose) std::cout << " make_recv_buff: " << get_size() << std::endl;
+ _info->flags = RB_USER_PROCESS; //claim the frame
+ return sptr(this, &usrp_e100_mmap_zero_copy_mrb::fake_deleter);
+ }
+
+private:
+ static void fake_deleter(void *obj){
+ static_cast<usrp_e100_mmap_zero_copy_mrb *>(obj)->release();
+ }
+
+ const void *get_buff(void) const{return _mem;}
+ size_t get_size(void) const{return _info->len;}
+
+ void *_mem;
+ ring_buffer_info *_info;
+};
+
+/***********************************************************************
+ * Reusable managed send buffer:
+ * - The buffer knows how to claim and release a frame.
+ **********************************************************************/
+class usrp_e100_mmap_zero_copy_msb : public managed_send_buffer{
+public:
+ usrp_e100_mmap_zero_copy_msb(void *mem, ring_buffer_info *info, size_t len, int fd):
+ _mem(mem), _info(info), _len(len), _fd(fd) { /* NOP */ }
+
+ void commit(size_t len){
+ if (_info->flags != RB_USER_PROCESS) return;
+ if (fp_verbose) std::cout << "send buff: commit " << len << std::endl;
+ _info->len = len;
+ _info->flags = RB_USER; //release the frame
+ if (::write(_fd, NULL, 0) < 0){ //notifies the kernel
+ std::cerr << UHD_THROW_SITE_INFO("write error") << std::endl;
+ }
+ }
+
+ bool ready(void){return _info->flags & RB_KERNEL;}
+
+ sptr get_new(void){
+ if (fp_verbose) std::cout << " make_send_buff: " << get_size() << std::endl;
+ _info->flags = RB_USER_PROCESS; //claim the frame
+ return sptr(this, &usrp_e100_mmap_zero_copy_msb::fake_deleter);
+ }
+
+private:
+ static void fake_deleter(void *obj){
+ static_cast<usrp_e100_mmap_zero_copy_msb *>(obj)->commit(0);
+ }
+
+ void *get_buff(void) const{return _mem;}
+ size_t get_size(void) const{return _len;}
+
+ void *_mem;
+ ring_buffer_info *_info;
+ size_t _len;
+ int _fd;
+};
+
+/***********************************************************************
* The zero copy interface implementation
**********************************************************************/
class usrp_e100_mmap_zero_copy_impl : public zero_copy_if{
@@ -81,13 +157,32 @@ public:
std::cout << "send_buff_off: " << send_buff_off << std::endl;
}
+ //pointers to sections in the mapped memory
+ ring_buffer_info (*recv_info)[], (*send_info)[];
+ char *recv_buff, *send_buff;
+
//set the internal pointers for info and buffers
typedef ring_buffer_info (*rbi_pta)[];
char *rb_ptr = reinterpret_cast<char *>(_mapped_mem);
- _recv_info = reinterpret_cast<rbi_pta>(rb_ptr + recv_info_off);
- _recv_buff = rb_ptr + recv_buff_off;
- _send_info = reinterpret_cast<rbi_pta>(rb_ptr + send_info_off);
- _send_buff = rb_ptr + send_buff_off;
+ recv_info = reinterpret_cast<rbi_pta>(rb_ptr + recv_info_off);
+ recv_buff = rb_ptr + recv_buff_off;
+ send_info = reinterpret_cast<rbi_pta>(rb_ptr + send_info_off);
+ send_buff = rb_ptr + send_buff_off;
+
+ //initialize the managed receive buffers
+ for (size_t i = 0; i < get_num_recv_frames(); i++){
+ _mrb_pool.push_back(usrp_e100_mmap_zero_copy_mrb(
+ recv_buff + get_recv_frame_size()*i, (*recv_info) + i
+ ));
+ }
+
+ //initialize the managed send buffers
+ for (size_t i = 0; i < get_num_recv_frames(); i++){
+ _msb_pool.push_back(usrp_e100_mmap_zero_copy_msb(
+ send_buff + get_send_frame_size()*i, (*send_info) + i,
+ get_send_frame_size(), _fd
+ ));
+ }
}
~usrp_e100_mmap_zero_copy_impl(void){
@@ -97,13 +192,10 @@ public:
managed_recv_buffer::sptr get_recv_buff(double timeout){
if (fp_verbose) std::cout << "get_recv_buff: " << _recv_index << std::endl;
-
- //grab pointers to the info and buffer
- ring_buffer_info *info = (*_recv_info) + _recv_index;
- void *mem = _recv_buff + _frame_size*_recv_index;
+ usrp_e100_mmap_zero_copy_mrb &mrb = _mrb_pool[_recv_index];
//poll/wait for a ready frame
- if (not (info->flags & RB_USER)){
+ if (not mrb.ready()){
for (size_t i = 0; i < poll_breakout; i++){
pollfd pfd;
pfd.fd = _fd;
@@ -115,18 +207,11 @@ public:
return managed_recv_buffer::sptr(); //timed-out for real
} found_user_frame:
- //the process has claimed the frame
- info->flags = RB_USER_PROCESS;
-
//increment the index for the next call
- if (++_recv_index == size_t(_rb_size.num_rx_frames)) _recv_index = 0;
+ if (++_recv_index == get_num_recv_frames()) _recv_index = 0;
//return the managed buffer for this frame
- if (fp_verbose) std::cout << " make_recv_buff: " << info->len << std::endl;
- return managed_recv_buffer::make_safe(
- mem, info->len,
- boost::bind(&usrp_e100_mmap_zero_copy_impl::release, this, info)
- );
+ return mrb.get_new();
}
size_t get_num_recv_frames(void) const{
@@ -139,13 +224,10 @@ public:
managed_send_buffer::sptr get_send_buff(double timeout){
if (fp_verbose) std::cout << "get_send_buff: " << _send_index << std::endl;
-
- //grab pointers to the info and buffer
- ring_buffer_info *info = (*_send_info) + _send_index;
- void *mem = _send_buff + _frame_size*_send_index;
+ usrp_e100_mmap_zero_copy_msb &msb = _msb_pool[_send_index];
//poll/wait for a ready frame
- if (not (info->flags & RB_KERNEL)){
+ if (not msb.ready()){
pollfd pfd;
pfd.fd = _fd;
pfd.events = POLLOUT;
@@ -155,14 +237,10 @@ public:
}
//increment the index for the next call
- if (++_send_index == size_t(_rb_size.num_tx_frames)) _send_index = 0;
+ if (++_send_index == get_num_send_frames()) _send_index = 0;
//return the managed buffer for this frame
- if (fp_verbose) std::cout << " make_send_buff: " << _frame_size << std::endl;
- return managed_send_buffer::make_safe(
- mem, _frame_size,
- boost::bind(&usrp_e100_mmap_zero_copy_impl::commit, this, info, _1)
- );
+ return msb.get_new();
}
size_t get_num_send_frames(void) const{
@@ -174,21 +252,7 @@ public:
}
private:
-
- void release(ring_buffer_info *info){
- if (fp_verbose) std::cout << "recv buff: release" << std::endl;
- info->flags = RB_KERNEL;
- }
-
- void commit(ring_buffer_info *info, size_t len){
- if (fp_verbose) std::cout << "send buff: commit " << len << std::endl;
- info->len = len;
- info->flags = RB_USER;
- if (::write(_fd, NULL, 0) < 0){
- std::cerr << UHD_THROW_SITE_INFO("write error") << std::endl;
- }
- }
-
+ //file descriptor for mmap
int _fd;
//the mapped memory itself
@@ -198,9 +262,9 @@ private:
usrp_e_ring_buffer_size_t _rb_size;
size_t _frame_size, _map_size;
- //pointers to sections in the mapped memory
- ring_buffer_info (*_recv_info)[], (*_send_info)[];
- char *_recv_buff, *_send_buff;
+ //re-usable managed buffers
+ std::vector<usrp_e100_mmap_zero_copy_mrb> _mrb_pool;
+ std::vector<usrp_e100_mmap_zero_copy_msb> _msb_pool;
//indexes into sub-sections of mapped memory
size_t _recv_index, _send_index;
diff --git a/host/lib/utils/CMakeLists.txt b/host/lib/utils/CMakeLists.txt
index 5fa5b4d6d..743528189 100644
--- a/host/lib/utils/CMakeLists.txt
+++ b/host/lib/utils/CMakeLists.txt
@@ -48,14 +48,19 @@ CHECK_CXX_SOURCE_COMPILES("
IF(HAVE_PTHREAD_SETSCHEDPARAM)
MESSAGE(STATUS " Priority scheduling supported through pthread_setschedparam.")
- ADD_DEFINITIONS(-DHAVE_PTHREAD_SETSCHEDPARAM)
+ SET(THREAD_PRIO_DEFS HAVE_PTHREAD_SETSCHEDPARAM)
ELSEIF(HAVE_WIN_SETTHREADPRIORITY)
MESSAGE(STATUS " Priority scheduling supported through windows SetThreadPriority.")
- ADD_DEFINITIONS(-DHAVE_WIN_SETTHREADPRIORITY)
+ SET(THREAD_PRIO_DEFS HAVE_WIN_SETTHREADPRIORITY)
ELSE(HAVE_PTHREAD_SETSCHEDPARAM)
MESSAGE(STATUS " Priority scheduling not supported.")
ENDIF(HAVE_PTHREAD_SETSCHEDPARAM)
+SET_SOURCE_FILES_PROPERTIES(
+ ${CMAKE_CURRENT_SOURCE_DIR}/thread_priority.cpp
+ PROPERTIES COMPILE_DEFINITIONS "${THREAD_PRIO_DEFS}"
+)
+
########################################################################
# Setup defines for module loading
########################################################################
@@ -68,15 +73,20 @@ CHECK_INCLUDE_FILE_CXX(windows.h HAVE_WINDOWS_H)
IF(HAVE_DLFCN_H)
MESSAGE(STATUS " Module loading supported through dlopen.")
- ADD_DEFINITIONS(-DHAVE_DLFCN_H)
+ SET(LOAD_MODULES_DEFS HAVE_DLFCN_H)
LIBUHD_APPEND_LIBS(${CMAKE_DL_LIBS})
ELSEIF(HAVE_WINDOWS_H)
MESSAGE(STATUS " Module loading supported through LoadLibrary.")
- ADD_DEFINITIONS(-DHAVE_WINDOWS_H)
+ SET(LOAD_MODULES_DEFS HAVE_WINDOWS_H)
ELSE(HAVE_DLFCN_H)
MESSAGE(STATUS " Module loading not supported.")
ENDIF(HAVE_DLFCN_H)
+SET_SOURCE_FILES_PROPERTIES(
+ ${CMAKE_CURRENT_SOURCE_DIR}/load_modules.cpp
+ PROPERTIES COMPILE_DEFINITIONS "${LOAD_MODULES_DEFS}"
+)
+
########################################################################
# Append sources
########################################################################