summaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
Diffstat (limited to 'host')
-rw-r--r--host/LICENSE4
-rw-r--r--host/include/uhd/transport/nirio/nirio_fifo.h6
-rw-r--r--host/include/uhd/transport/nirio/nirio_fifo.ipp234
-rw-r--r--host/include/uhd/transport/nirio/nirio_quirks.h4
-rw-r--r--host/include/uhd/usrp/multi_usrp.hpp8
-rw-r--r--host/lib/convert/convert_impl.cpp1
-rw-r--r--host/lib/usrp/b100/b100_impl.cpp1
-rw-r--r--host/lib/usrp/b100/b100_impl.hpp1
-rw-r--r--host/lib/usrp/b200/b200_impl.cpp1
-rw-r--r--host/lib/usrp/b200/b200_impl.hpp4
-rw-r--r--host/lib/usrp/multi_usrp.cpp41
-rw-r--r--host/lib/usrp/usrp1/usrp1_impl.cpp2
-rw-r--r--host/lib/usrp/usrp1/usrp1_impl.hpp1
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp1
-rw-r--r--host/lib/usrp/x300/x300_impl.cpp9
-rw-r--r--host/lib/usrp/x300/x300_impl.hpp4
-rw-r--r--host/lib/usrp/x300/x300_io_impl.cpp35
17 files changed, 238 insertions, 119 deletions
diff --git a/host/LICENSE b/host/LICENSE
index 9aa03b39b..b91233b22 100644
--- a/host/LICENSE
+++ b/host/LICENSE
@@ -1,3 +1,7 @@
+This LICENSE file applies only to this directory and all subdirectories. Other
+top-level directories in the UHD(tm) Software distribution are not necessarily
+covered by this license.
+
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
diff --git a/host/include/uhd/transport/nirio/nirio_fifo.h b/host/include/uhd/transport/nirio/nirio_fifo.h
index f7abb396f..fc1de245d 100644
--- a/host/include/uhd/transport/nirio/nirio_fifo.h
+++ b/host/include/uhd/transport/nirio/nirio_fifo.h
@@ -104,16 +104,20 @@ public:
uint32_t& num_remaining);
private: //Methods
- bool _is_initialized();
datatype_info_t _get_datatype_info();
nirio_status _get_transfer_count(uint64_t& transfer_count);
nirio_status _ensure_transfer_completed(uint32_t timeout_ms);
private: //Members
+ enum fifo_state_t {
+ UNMAPPED, MAPPED, STARTED
+ };
+
std::string _name;
fifo_direction_t _fifo_direction;
uint32_t _fifo_channel;
datatype_info_t _datatype_info;
+ fifo_state_t _state;
size_t _acquired_pending;
nirio_driver_iface::rio_mmap_t _mem_map;
boost::recursive_mutex _mutex;
diff --git a/host/include/uhd/transport/nirio/nirio_fifo.ipp b/host/include/uhd/transport/nirio/nirio_fifo.ipp
index 80a0c2a89..437e3a1fc 100644
--- a/host/include/uhd/transport/nirio/nirio_fifo.ipp
+++ b/host/include/uhd/transport/nirio/nirio_fifo.ipp
@@ -31,6 +31,7 @@ nirio_fifo<data_t>::nirio_fifo(
_fifo_direction(direction),
_fifo_channel(fifo_instance),
_datatype_info(_get_datatype_info()),
+ _state(UNMAPPED),
_acquired_pending(0),
_mem_map(),
_riok_proxy_ptr(&riok_proxy),
@@ -61,28 +62,37 @@ nirio_status nirio_fifo<data_t>::initialize(
if (!_riok_proxy_ptr) return NiRio_Status_ResourceNotInitialized;
boost::unique_lock<boost::recursive_mutex> lock(_mutex);
- nirio_driver_iface::nirio_syncop_in_params_t in = {};
- nirio_driver_iface::nirio_syncop_out_params_t out = {};
+ if (_state == UNMAPPED) {
+ nirio_driver_iface::nirio_syncop_in_params_t in = {};
+ nirio_driver_iface::nirio_syncop_out_params_t out = {};
- //Forcefully stop the fifo if it is running
- in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
- in.subfunction = nirio_driver_iface::NIRIO_FIFO::STOP;
- status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
+ //Forcefully stop the fifo if it is running
+ in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
+ in.subfunction = nirio_driver_iface::NIRIO_FIFO::STOP;
+ in.params.fifo.channel = _fifo_channel;
+ _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out)); //Cleanup operation. Ignore status.
- in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
- in.subfunction = nirio_driver_iface::NIRIO_FIFO::CONFIGURE;
+ //Configure the FIFO now that we know it is stopped
+ in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
+ in.subfunction = nirio_driver_iface::NIRIO_FIFO::CONFIGURE;
+ in.params.fifo.channel = _fifo_channel;
+ in.params.fifo.op.config.requestedDepth = static_cast<uint32_t>(requested_depth);
+ in.params.fifo.op.config.requiresActuals = 1;
+ status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
- in.params.fifo.channel = _fifo_channel;
- in.params.fifo.op.config.requestedDepth = static_cast<uint32_t>(requested_depth);
- in.params.fifo.op.config.requiresActuals = 1;
+ if (nirio_status_fatal(status)) return status;
- status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
- if (nirio_status_fatal(status)) return status;
+ actual_depth = out.params.fifo.op.config.actualDepth;
+ actual_size = out.params.fifo.op.config.actualSize;
- actual_depth = out.params.fifo.op.config.actualDepth;
- actual_size = out.params.fifo.op.config.actualSize;
+ status = _riok_proxy_ptr->map_fifo_memory(_fifo_channel, actual_size, _mem_map);
- status = _riok_proxy_ptr->map_fifo_memory(_fifo_channel, actual_size, _mem_map);
+ if (nirio_status_not_fatal(status)) {
+ _state = MAPPED;
+ }
+ } else {
+ status = NiRio_Status_SoftwareFault;
+ }
return status;
}
@@ -90,9 +100,13 @@ template <typename data_t>
void nirio_fifo<data_t>::finalize()
{
boost::unique_lock<boost::recursive_mutex> lock(_mutex);
- if (!_mem_map.is_null()) {
- stop();
+
+ //If the FIFO is started, the stop will change the state to MAPPED.
+ stop();
+
+ if (_state == MAPPED) {
_riok_proxy_ptr->unmap_fifo_memory(_mem_map);
+ _state = UNMAPPED; //Assume teardown succeeded
}
}
@@ -104,16 +118,25 @@ nirio_status nirio_fifo<data_t>::start()
boost::unique_lock<boost::recursive_mutex> lock(_mutex);
- nirio_driver_iface::nirio_syncop_in_params_t in = {};
- nirio_driver_iface::nirio_syncop_out_params_t out = {};
+ if (_state == STARTED) {
+ //Do nothing. Already started.
+ } else if (_state == MAPPED) {
+ nirio_driver_iface::nirio_syncop_in_params_t in = {};
+ nirio_driver_iface::nirio_syncop_out_params_t out = {};
- in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
- in.subfunction = nirio_driver_iface::NIRIO_FIFO::START;
+ in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
+ in.subfunction = nirio_driver_iface::NIRIO_FIFO::START;
- status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
- if (nirio_status_not_fatal(status)) {
- _acquired_pending = 0;
- _expected_xfer_count = 0;
+ in.params.fifo.channel = _fifo_channel;
+
+ status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
+ if (nirio_status_not_fatal(status)) {
+ _state = STARTED;
+ _acquired_pending = 0;
+ _expected_xfer_count = 0;
+ }
+ } else {
+ status = NiRio_Status_ResourceNotInitialized;
}
return status;
}
@@ -125,15 +148,22 @@ nirio_status nirio_fifo<data_t>::stop()
if (!_riok_proxy_ptr) return NiRio_Status_ResourceNotInitialized;
boost::unique_lock<boost::recursive_mutex> lock(_mutex);
- if (_acquired_pending > 0) release(_acquired_pending);
- nirio_driver_iface::nirio_syncop_in_params_t in = {};
- nirio_driver_iface::nirio_syncop_out_params_t out = {};
+ if (_state == STARTED) {
+ if (_acquired_pending > 0) release(_acquired_pending);
+
+ nirio_driver_iface::nirio_syncop_in_params_t in = {};
+ nirio_driver_iface::nirio_syncop_out_params_t out = {};
- in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
- in.subfunction = nirio_driver_iface::NIRIO_FIFO::STOP;
+ in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
+ in.subfunction = nirio_driver_iface::NIRIO_FIFO::STOP;
- status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
+ in.params.fifo.channel = _fifo_channel;
+
+ status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
+
+ _state = MAPPED; //Assume teardown succeeded
+ }
return status;
}
@@ -151,36 +181,40 @@ nirio_status nirio_fifo<data_t>::acquire(
boost::unique_lock<boost::recursive_mutex> lock(_mutex);
- nirio_driver_iface::nirio_syncop_in_params_t in = {};
- uint32_t stuffed[2];
- nirio_driver_iface::nirio_syncop_out_params_t out = {};
- init_syncop_out_params(out, stuffed, sizeof(stuffed));
-
- in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
- in.subfunction = nirio_driver_iface::NIRIO_FIFO::WAIT;
-
- in.params.fifo.channel = _fifo_channel;
- in.params.fifo.op.wait.elementsRequested = static_cast<uint32_t>(elements_requested);
- in.params.fifo.op.wait.scalarType = static_cast<uint32_t>(_datatype_info.scalar_type);
- in.params.fifo.op.wait.bitWidth = _datatype_info.width * 8;
- in.params.fifo.op.wait.output = _fifo_direction == OUTPUT_FIFO;
- in.params.fifo.op.wait.timeout = timeout;
-
- status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
-
- if (nirio_status_not_fatal(status)) {
- elements = static_cast<data_t*>(out.params.fifo.op.wait.elements.pointer);
- elements_acquired = stuffed[0];
- elements_remaining = stuffed[1];
- _acquired_pending = elements_acquired;
-
- if (UHD_NIRIO_RX_FIFO_XFER_CHECK_EN &&
- _riok_proxy_ptr->get_rio_quirks().rx_fifo_xfer_check_en() &&
- get_direction() == INPUT_FIFO
- ) {
- _expected_xfer_count += static_cast<uint64_t>(elements_requested * sizeof(data_t));
- status = _ensure_transfer_completed(timeout);
+ if (_state == STARTED) {
+ nirio_driver_iface::nirio_syncop_in_params_t in = {};
+ uint32_t stuffed[2];
+ nirio_driver_iface::nirio_syncop_out_params_t out = {};
+ init_syncop_out_params(out, stuffed, sizeof(stuffed));
+
+ in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
+ in.subfunction = nirio_driver_iface::NIRIO_FIFO::WAIT;
+
+ in.params.fifo.channel = _fifo_channel;
+ in.params.fifo.op.wait.elementsRequested = static_cast<uint32_t>(elements_requested);
+ in.params.fifo.op.wait.scalarType = static_cast<uint32_t>(_datatype_info.scalar_type);
+ in.params.fifo.op.wait.bitWidth = _datatype_info.width * 8;
+ in.params.fifo.op.wait.output = _fifo_direction == OUTPUT_FIFO;
+ in.params.fifo.op.wait.timeout = timeout;
+
+ status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
+
+ if (nirio_status_not_fatal(status)) {
+ elements = static_cast<data_t*>(out.params.fifo.op.wait.elements.pointer);
+ elements_acquired = stuffed[0];
+ elements_remaining = stuffed[1];
+ _acquired_pending = elements_acquired;
+
+ if (UHD_NIRIO_RX_FIFO_XFER_CHECK_EN &&
+ _riok_proxy_ptr->get_rio_quirks().rx_fifo_xfer_check_en() &&
+ get_direction() == INPUT_FIFO
+ ) {
+ _expected_xfer_count += static_cast<uint64_t>(elements_requested * sizeof(data_t));
+ status = _ensure_transfer_completed(timeout);
+ }
}
+ } else {
+ status = NiRio_Status_ResourceNotInitialized;
}
return status;
@@ -194,17 +228,21 @@ nirio_status nirio_fifo<data_t>::release(const size_t elements)
boost::unique_lock<boost::recursive_mutex> lock(_mutex);
- nirio_driver_iface::nirio_syncop_in_params_t in = {};
- nirio_driver_iface::nirio_syncop_out_params_t out = {};
+ if (_state == STARTED) {
+ nirio_driver_iface::nirio_syncop_in_params_t in = {};
+ nirio_driver_iface::nirio_syncop_out_params_t out = {};
- in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
- in.subfunction = nirio_driver_iface::NIRIO_FIFO::GRANT;
+ in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
+ in.subfunction = nirio_driver_iface::NIRIO_FIFO::GRANT;
- in.params.fifo.channel = _fifo_channel;
- in.params.fifo.op.grant.elements = static_cast<uint32_t>(elements);
+ in.params.fifo.channel = _fifo_channel;
+ in.params.fifo.op.grant.elements = static_cast<uint32_t>(elements);
- status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
- _acquired_pending = 0;
+ status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
+ _acquired_pending = 0;
+ } else {
+ status = NiRio_Status_ResourceNotInitialized;
+ }
return status;
}
@@ -222,23 +260,27 @@ nirio_status nirio_fifo<data_t>::read(
boost::unique_lock<boost::recursive_mutex> lock(_mutex);
- nirio_driver_iface::nirio_syncop_in_params_t in = {};
- nirio_driver_iface::nirio_syncop_out_params_t out = {};
- init_syncop_out_params(out, buf, num_elements * _datatype_info.width);
+ if (_state == STARTED) {
+ nirio_driver_iface::nirio_syncop_in_params_t in = {};
+ nirio_driver_iface::nirio_syncop_out_params_t out = {};
+ init_syncop_out_params(out, buf, num_elements * _datatype_info.width);
- in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
- in.subfunction = nirio_driver_iface::NIRIO_FIFO::READ;
+ in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
+ in.subfunction = nirio_driver_iface::NIRIO_FIFO::READ;
- in.params.fifo.channel = _fifo_channel;
- in.params.fifo.op.readWithDataType.timeout = timeout;
- in.params.fifo.op.readWithDataType.scalarType = static_cast<uint32_t>(_datatype_info.scalar_type);
- in.params.fifo.op.readWithDataType.bitWidth = _datatype_info.width * 8;
+ in.params.fifo.channel = _fifo_channel;
+ in.params.fifo.op.readWithDataType.timeout = timeout;
+ in.params.fifo.op.readWithDataType.scalarType = static_cast<uint32_t>(_datatype_info.scalar_type);
+ in.params.fifo.op.readWithDataType.bitWidth = _datatype_info.width * 8;
- status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
+ status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
- if (nirio_status_not_fatal(status) || status == NiRio_Status_FifoTimeout) {
- num_read = out.params.fifo.op.read.numberRead;
- num_remaining = out.params.fifo.op.read.numberRemaining;
+ if (nirio_status_not_fatal(status) || status == NiRio_Status_FifoTimeout) {
+ num_read = out.params.fifo.op.read.numberRead;
+ num_remaining = out.params.fifo.op.read.numberRemaining;
+ }
+ } else {
+ status = NiRio_Status_ResourceNotInitialized;
}
return status;
@@ -256,22 +298,26 @@ nirio_status nirio_fifo<data_t>::write(
boost::unique_lock<boost::recursive_mutex> lock(_mutex);
- nirio_driver_iface::nirio_syncop_in_params_t in = {};
- init_syncop_in_params(in, buf, num_elements * _datatype_info.width);
- nirio_driver_iface::nirio_syncop_out_params_t out = {};
+ if (_state == STARTED) {
+ nirio_driver_iface::nirio_syncop_in_params_t in = {};
+ init_syncop_in_params(in, buf, num_elements * _datatype_info.width);
+ nirio_driver_iface::nirio_syncop_out_params_t out = {};
- in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
- in.subfunction = nirio_driver_iface::NIRIO_FIFO::WRITE;
+ in.function = nirio_driver_iface::NIRIO_FUNC::FIFO;
+ in.subfunction = nirio_driver_iface::NIRIO_FIFO::WRITE;
- in.params.fifo.channel = _fifo_channel;
- in.params.fifo.op.writeWithDataType.timeout = timeout;
- in.params.fifo.op.readWithDataType.scalarType = static_cast<uint32_t>(_datatype_info.scalar_type);
- in.params.fifo.op.readWithDataType.bitWidth = _datatype_info.width * 8;
+ in.params.fifo.channel = _fifo_channel;
+ in.params.fifo.op.writeWithDataType.timeout = timeout;
+ in.params.fifo.op.readWithDataType.scalarType = static_cast<uint32_t>(_datatype_info.scalar_type);
+ in.params.fifo.op.readWithDataType.bitWidth = _datatype_info.width * 8;
- status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
+ status = _riok_proxy_ptr->sync_operation(&in, sizeof(in), &out, sizeof(out));
- if (nirio_status_not_fatal(status) || status == NiRio_Status_FifoTimeout) {
- num_remaining = out.params.fifo.op.write.numberRemaining;
+ if (nirio_status_not_fatal(status) || status == NiRio_Status_FifoTimeout) {
+ num_remaining = out.params.fifo.op.write.numberRemaining;
+ }
+ } else {
+ status = NiRio_Status_ResourceNotInitialized;
}
return status;
diff --git a/host/include/uhd/transport/nirio/nirio_quirks.h b/host/include/uhd/transport/nirio/nirio_quirks.h
index 326eeeb8c..ed4f72e7f 100644
--- a/host/include/uhd/transport/nirio/nirio_quirks.h
+++ b/host/include/uhd/transport/nirio/nirio_quirks.h
@@ -24,8 +24,8 @@
//Quirk#1: We need to verify RX zero-copy data transfers from the RIO
// driver if we are in full duplex mode.
-// This option allows disabling this quirk by compiling it out.
-#define UHD_NIRIO_RX_FIFO_XFER_CHECK_EN 1
+// This option allows enabling this quirk.
+#define UHD_NIRIO_RX_FIFO_XFER_CHECK_EN 0
namespace uhd { namespace niusrprio {
diff --git a/host/include/uhd/usrp/multi_usrp.hpp b/host/include/uhd/usrp/multi_usrp.hpp
index aac40efe5..883e4da3d 100644
--- a/host/include/uhd/usrp/multi_usrp.hpp
+++ b/host/include/uhd/usrp/multi_usrp.hpp
@@ -119,14 +119,10 @@ public:
virtual device::sptr get_device(void) = 0;
//! Convenience method to get a RX streamer. See also uhd::device::get_rx_stream().
- rx_streamer::sptr get_rx_stream(const stream_args_t &args){
- return this->get_device()->get_rx_stream(args);
- }
+ virtual rx_streamer::sptr get_rx_stream(const stream_args_t &args) = 0;
//! Convenience method to get a TX streamer. See also uhd::device::get_rx_stream().
- tx_streamer::sptr get_tx_stream(const stream_args_t &args){
- return this->get_device()->get_tx_stream(args);
- }
+ virtual tx_streamer::sptr get_tx_stream(const stream_args_t &args) = 0;
/*!
* Returns identifying information about this USRP's configuration.
diff --git a/host/lib/convert/convert_impl.cpp b/host/lib/convert/convert_impl.cpp
index dc7f8f9dc..c7907ed83 100644
--- a/host/lib/convert/convert_impl.cpp
+++ b/host/lib/convert/convert_impl.cpp
@@ -134,6 +134,7 @@ UHD_STATIC_BLOCK(convert_register_item_sizes){
convert::register_bytes_per_item("sc64", sizeof(std::complex<boost::int64_t>));
convert::register_bytes_per_item("sc32", sizeof(std::complex<boost::int32_t>));
convert::register_bytes_per_item("sc16", sizeof(std::complex<boost::int16_t>));
+ convert::register_bytes_per_item("sc12", 3 * sizeof(std::complex<boost::int8_t>));
convert::register_bytes_per_item("sc8", sizeof(std::complex<boost::int8_t>));
//register standard real types
diff --git a/host/lib/usrp/b100/b100_impl.cpp b/host/lib/usrp/b100/b100_impl.cpp
index a47856b07..cb32a596c 100644
--- a/host/lib/usrp/b100/b100_impl.cpp
+++ b/host/lib/usrp/b100/b100_impl.cpp
@@ -515,6 +515,7 @@ b100_impl::b100_impl(const device_addr_t &device_addr){
_tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(subdev_spec_t("A:" + _tree->list(mb_path / "dboards/A/tx_frontends").at(0)));
_tree->access<std::string>(mb_path / "clock_source/value").set("internal");
_tree->access<std::string>(mb_path / "time_source/value").set("none");
+ _tree->create<double>(mb_path / "link_max_rate").set(B100_MAX_RATE_USB2);
}
b100_impl::~b100_impl(void){
diff --git a/host/lib/usrp/b100/b100_impl.hpp b/host/lib/usrp/b100/b100_impl.hpp
index 7d71d5ec3..b6752681e 100644
--- a/host/lib/usrp/b100/b100_impl.hpp
+++ b/host/lib/usrp/b100/b100_impl.hpp
@@ -54,6 +54,7 @@ static const boost::uint32_t B100_CTRL_MSG_SID = 20;
static const double B100_DEFAULT_TICK_RATE = 64e6;
static const size_t B100_MAX_PKT_BYTE_LIMIT = 2048;
static const std::string B100_EEPROM_MAP_KEY = "B100";
+static const size_t B100_MAX_RATE_USB2 = 32000000; // bytes/s
#define I2C_ADDR_TX_A (I2C_DEV_EEPROM | 0x4)
#define I2C_ADDR_RX_A (I2C_DEV_EEPROM | 0x5)
diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp
index 9dd3a424d..84310a9fe 100644
--- a/host/lib/usrp/b200/b200_impl.cpp
+++ b/host/lib/usrp/b200/b200_impl.cpp
@@ -250,6 +250,7 @@ b200_impl::b200_impl(const device_addr_t &device_addr)
ctrl_xport_args
);
while (_ctrl_transport->get_recv_buff(0.0)){} //flush ctrl xport
+ _tree->create<double>(mb_path / "link_max_rate").set((usb_speed == 3) ? B200_MAX_RATE_USB3 : B200_MAX_RATE_USB2);
////////////////////////////////////////////////////////////////////
// Async task structure
diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp
index 7d98a8f8d..c3508c550 100644
--- a/host/lib/usrp/b200/b200_impl.hpp
+++ b/host/lib/usrp/b200/b200_impl.hpp
@@ -47,11 +47,13 @@
static const boost::uint8_t B200_FW_COMPAT_NUM_MAJOR = 0x04;
static const boost::uint8_t B200_FW_COMPAT_NUM_MINOR = 0x00;
static const boost::uint16_t B200_FPGA_COMPAT_NUM = 0x03;
-static const double B200_LINK_RATE_BPS = (5e9)/8; //practical link rate (5 Gbps)
static const double B200_BUS_CLOCK_RATE = 100e6;
static const double B200_DEFAULT_TICK_RATE = 32e6;
static const boost::uint32_t B200_GPSDO_ST_NONE = 0x83;
+static const size_t B200_MAX_RATE_USB2 = 32000000; // bytes/s
+static const size_t B200_MAX_RATE_USB3 = 500000000; // bytes/s
+
#define FLIP_SID(sid) (((sid)<<16)|((sid)>>16))
static const boost::uint32_t B200_CTRL0_MSG_SID = 0x00000010;
diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp
index f08709669..4883b2410 100644
--- a/host/lib/usrp/multi_usrp.cpp
+++ b/host/lib/usrp/multi_usrp.cpp
@@ -24,6 +24,7 @@
#include <uhd/usrp/dboard_id.hpp>
#include <uhd/usrp/mboard_eeprom.hpp>
#include <uhd/usrp/dboard_eeprom.hpp>
+#include <uhd/convert.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/thread.hpp>
#include <boost/foreach.hpp>
@@ -103,6 +104,8 @@ static meta_range_t make_overall_tune_range(
return range;
}
+
+
/***********************************************************************
* Gain helper functions
**********************************************************************/
@@ -589,6 +592,11 @@ public:
/*******************************************************************
* RX methods
******************************************************************/
+ rx_streamer::sptr get_rx_stream(const stream_args_t &args) {
+ _check_link_rate(args, false);
+ return this->get_device()->get_rx_stream(args);
+ }
+
void set_rx_subdev_spec(const subdev_spec_t &spec, size_t mboard){
if (mboard != ALL_MBOARDS){
_tree->access<subdev_spec_t>(mb_root(mboard) / "rx_subdev_spec").set(spec);
@@ -770,6 +778,11 @@ public:
/*******************************************************************
* TX methods
******************************************************************/
+ tx_streamer::sptr get_tx_stream(const stream_args_t &args) {
+ _check_link_rate(args, true);
+ return this->get_device()->get_tx_stream(args);
+ }
+
void set_tx_subdev_spec(const subdev_spec_t &spec, size_t mboard){
if (mboard != ALL_MBOARDS){
_tree->access<subdev_spec_t>(mb_root(mboard) / "tx_subdev_spec").set(spec);
@@ -1178,6 +1191,34 @@ private:
}
return gg;
}
+
+ //! \param is_tx True for tx
+ // Assumption is that all mboards use the same link
+ bool _check_link_rate(const stream_args_t &args, bool is_tx) {
+ bool link_rate_is_ok = true;
+ size_t bytes_per_sample = convert::get_bytes_per_item(args.otw_format);
+ double max_link_rate = 0;
+ double sum_rate = 0;
+ BOOST_FOREACH(const size_t chan, args.channels) {
+ mboard_chan_pair mcp = is_tx ? tx_chan_to_mcp(chan) : rx_chan_to_mcp(chan);
+ if (_tree->exists(mb_root(mcp.mboard) / "link_max_rate")) {
+ max_link_rate = std::max(
+ max_link_rate,
+ _tree->access<double>(mb_root(mcp.mboard) / "link_max_rate").get()
+ );
+ }
+ sum_rate += is_tx ? get_tx_rate(chan) : get_rx_rate(chan);
+ }
+ if (max_link_rate > 0 and (max_link_rate / bytes_per_sample) < sum_rate) {
+ UHD_MSG(warning) << boost::format(
+ "The total sum of rates (%f MSps on %u channels) exceeds the maximum capacity of the connection.\n"
+ "This can cause %s."
+ ) % (sum_rate/1e6) % args.channels.size() % (is_tx ? "underruns (U)" : "overflows (O)") << std::endl;
+ link_rate_is_ok = false;
+ }
+
+ return link_rate_is_ok;
+ }
};
/***********************************************************************
diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp
index 3b902b343..3eaac9839 100644
--- a/host/lib/usrp/usrp1/usrp1_impl.cpp
+++ b/host/lib/usrp/usrp1/usrp1_impl.cpp
@@ -409,7 +409,7 @@ usrp1_impl::usrp1_impl(const device_addr_t &device_addr){
_tree->access<subdev_spec_t>(mb_path / "rx_subdev_spec").set(_rx_subdev_spec);
if (_tree->list(mb_path / "tx_dsps").size() > 0)
_tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(_tx_subdev_spec);
-
+ _tree->create<double>(mb_path / "link_max_rate").set(USRP1_MAX_RATE_USB2);
}
usrp1_impl::~usrp1_impl(void){
diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp
index da9fe8b16..012bc0794 100644
--- a/host/lib/usrp/usrp1/usrp1_impl.hpp
+++ b/host/lib/usrp/usrp1/usrp1_impl.hpp
@@ -39,6 +39,7 @@
#define INCLUDED_USRP1_IMPL_HPP
static const std::string USRP1_EEPROM_MAP_KEY = "B000";
+static const size_t USRP1_MAX_RATE_USB2 = 32000000; // bytes/s
#define FR_RB_CAPS 3
#define FR_MODE 13
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index 16d9b9a54..25f661656 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -442,6 +442,7 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
_mbc[mb].spiface = _mbc[mb].iface;
break;
}
+ _tree->create<double>(mb_path / "link_max_rate").set(USRP2_LINK_RATE_BPS);
////////////////////////////////////////////////////////////////
// setup the mboard eeprom
diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp
index e492b2238..f5e53678c 100644
--- a/host/lib/usrp/x300/x300_impl.cpp
+++ b/host/lib/usrp/x300/x300_impl.cpp
@@ -392,6 +392,8 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)
//Tell the quirks object which FIFOs carry TX stream data
const uint32_t tx_data_fifos[2] = {X300_RADIO_DEST_PREFIX_TX, X300_RADIO_DEST_PREFIX_TX + 3};
mb.rio_fpga_interface->get_kernel_proxy().get_rio_quirks().register_tx_streams(tx_data_fifos);
+
+ _tree->create<double>(mb_path / "link_max_rate").set(X300_MAX_RATE_PCIE);
}
BOOST_FOREACH(const std::string &key, dev_addr.keys())
@@ -456,6 +458,8 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)
<< "UHD will use the auto-detected max frame size for this connection."
<< std::endl;
}
+
+ _tree->create<double>(mb_path / "link_max_rate").set(X300_MAX_RATE_10GIGE);
}
//create basic communication
@@ -1133,11 +1137,14 @@ x300_impl::both_xports_t x300_impl::make_transport(
if (mb.loaded_fpga_image == "HGS") {
if (mb.router_dst_here == X300_XB_DST_E0) {
eth_data_rec_frame_size = X300_1GE_DATA_FRAME_MAX_SIZE;
+ _tree->access<double>("/mboards/"+boost::lexical_cast<std::string>(mb_index) / "link_max_rate").set(X300_MAX_RATE_1GIGE);
} else if (mb.router_dst_here == X300_XB_DST_E1) {
eth_data_rec_frame_size = X300_10GE_DATA_FRAME_MAX_SIZE;
+ _tree->access<double>("/mboards/"+boost::lexical_cast<std::string>(mb_index) / "link_max_rate").set(X300_MAX_RATE_10GIGE);
}
} else if (mb.loaded_fpga_image == "XGS") {
- eth_data_rec_frame_size = X300_10GE_DATA_FRAME_MAX_SIZE;
+ eth_data_rec_frame_size = X300_10GE_DATA_FRAME_MAX_SIZE;
+ _tree->access<double>("/mboards/"+boost::lexical_cast<std::string>(mb_index) / "link_max_rate").set(X300_MAX_RATE_10GIGE);
}
if (eth_data_rec_frame_size == 0) {
diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp
index 692427f31..4b3efc845 100644
--- a/host/lib/usrp/x300/x300_impl.hpp
+++ b/host/lib/usrp/x300/x300_impl.hpp
@@ -85,6 +85,10 @@ static const size_t X300_RX_MAX_HDR_LEN = // bytes
+ sizeof(uhd::transport::vrt::if_packet_info_t().sid) // SID
+ sizeof(uhd::transport::vrt::if_packet_info_t().tsf); // Timestamp
+static const size_t X300_MAX_RATE_PCIE = 800000000; // bytes/s
+static const size_t X300_MAX_RATE_10GIGE = 800000000; // bytes/s
+static const size_t X300_MAX_RATE_1GIGE = 100000000; // bytes/s
+
#define X300_RADIO_DEST_PREFIX_TX 0
#define X300_RADIO_DEST_PREFIX_CTRL 1
#define X300_RADIO_DEST_PREFIX_RX 2
diff --git a/host/lib/usrp/x300/x300_io_impl.cpp b/host/lib/usrp/x300/x300_io_impl.cpp
index 09ed1d705..9263c9b44 100644
--- a/host/lib/usrp/x300/x300_io_impl.cpp
+++ b/host/lib/usrp/x300/x300_io_impl.cpp
@@ -242,6 +242,8 @@ struct x300_tx_fc_guts_t
boost::shared_ptr<x300_impl::async_md_type> old_async_queue;
};
+#define X300_ASYNC_EVENT_CODE_FLOW_CTRL 0
+
static size_t get_tx_flow_control_window(size_t frame_size, const device_addr_t& tx_args)
{
double hw_buff_size = tx_args.cast<double>("send_buff_size", X300_TX_HW_BUFF_SIZE);
@@ -283,23 +285,28 @@ static void handle_tx_async_msgs(boost::shared_ptr<x300_tx_fc_guts_t> guts, zero
return;
}
- //catch the flow control packets and react
- if (endian_conv(packet_buff[if_packet_info.num_header_words32+0]) == 0)
- {
- const size_t seq = endian_conv(packet_buff[if_packet_info.num_header_words32+1]);
- guts->seq_queue.push_with_haste(seq);
- return;
- }
-
//fill in the async metadata
async_metadata_t metadata;
load_metadata_from_buff(
endian_conv, metadata, if_packet_info, packet_buff,
clock->get_master_clock_rate(), guts->stream_channel);
- guts->async_queue->push_with_pop_on_full(metadata);
- metadata.channel = guts->device_channel;
- guts->old_async_queue->push_with_pop_on_full(metadata);
- standard_async_msg_prints(metadata);
+
+ //The FC response and the burst ack are two indicators that the radio
+ //consumed packets. Use them to update the FC metadata
+ if (metadata.event_code == X300_ASYNC_EVENT_CODE_FLOW_CTRL or
+ metadata.event_code == async_metadata_t::EVENT_CODE_BURST_ACK
+ ) {
+ const size_t seq = metadata.user_payload[0];
+ guts->seq_queue.push_with_pop_on_full(seq);
+ }
+
+ //FC responses don't propagate up to the user so filter them here
+ if (metadata.event_code != X300_ASYNC_EVENT_CODE_FLOW_CTRL) {
+ guts->async_queue->push_with_pop_on_full(metadata);
+ metadata.channel = guts->device_channel;
+ guts->old_async_queue->push_with_pop_on_full(metadata);
+ standard_async_msg_prints(metadata);
+ }
}
static managed_send_buffer::sptr get_tx_buff_with_flowctrl(
@@ -319,7 +326,9 @@ static managed_send_buffer::sptr get_tx_buff_with_flowctrl(
}
managed_send_buffer::sptr buff = xport->get_send_buff(timeout);
- if (buff) guts->last_seq_out++; //update seq, this will actually be a send
+ if (buff) {
+ guts->last_seq_out++; //update seq, this will actually be a send
+ }
return buff;
}