aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp')
-rw-r--r--host/lib/usrp/b100/b100_impl.cpp8
-rw-r--r--host/lib/usrp/b100/b100_impl.hpp1
-rw-r--r--host/lib/usrp/b200/b200_iface.cpp38
-rw-r--r--host/lib/usrp/b200/b200_impl.cpp47
-rw-r--r--host/lib/usrp/b200/b200_impl.hpp15
-rw-r--r--host/lib/usrp/b200/b200_io_impl.cpp44
-rw-r--r--host/lib/usrp/common/ad9361_ctrl.cpp2
-rw-r--r--host/lib/usrp/common/ad9361_ctrl.hpp23
-rw-r--r--host/lib/usrp/common/ad9361_transaction.h5
-rw-r--r--host/lib/usrp/common/adf435x_common.cpp3
-rw-r--r--host/lib/usrp/cores/rx_dsp_core_3000.cpp6
-rw-r--r--host/lib/usrp/dboard/db_tvrx2.cpp6
-rw-r--r--host/lib/usrp/gps_ctrl.cpp9
-rw-r--r--host/lib/usrp/multi_usrp.cpp71
-rw-r--r--host/lib/usrp/usrp1/usrp1_impl.cpp9
-rw-r--r--host/lib/usrp/usrp1/usrp1_impl.hpp1
-rw-r--r--host/lib/usrp/usrp2/CMakeLists.txt14
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.cpp7
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp7
-rw-r--r--host/lib/usrp/x300/x300_fw_common.h2
-rw-r--r--host/lib/usrp/x300/x300_impl.cpp66
-rw-r--r--host/lib/usrp/x300/x300_impl.hpp16
-rw-r--r--host/lib/usrp/x300/x300_io_impl.cpp59
-rw-r--r--host/lib/usrp/x300/x300_regs.hpp10
24 files changed, 369 insertions, 100 deletions
diff --git a/host/lib/usrp/b100/b100_impl.cpp b/host/lib/usrp/b100/b100_impl.cpp
index a47856b07..baf2b6ae3 100644
--- a/host/lib/usrp/b100/b100_impl.cpp
+++ b/host/lib/usrp/b100/b100_impl.cpp
@@ -20,6 +20,7 @@
#include "b100_regs.hpp"
#include <uhd/transport/usb_control.hpp>
#include <uhd/utils/msg.hpp>
+#include <uhd/utils/cast.hpp>
#include <uhd/exception.hpp>
#include <uhd/utils/static.hpp>
#include <uhd/utils/images.hpp>
@@ -56,11 +57,11 @@ static device_addrs_t b100_find(const device_addr_t &hint)
//since an address and resource is intended for a different, non-USB, device.
if (hint.has_key("addr") || hint.has_key("resource")) return b100_addrs;
- unsigned int vid, pid;
+ boost::uint16_t vid, pid;
if(hint.has_key("vid") && hint.has_key("pid") && hint.has_key("type") && hint["type"] == "b100") {
- sscanf(hint.get("vid").c_str(), "%x", &vid);
- sscanf(hint.get("pid").c_str(), "%x", &pid);
+ vid = uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("vid"));
+ pid = uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("pid"));
} else {
vid = B100_VENDOR_ID;
pid = B100_PRODUCT_ID;
@@ -515,6 +516,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_iface.cpp b/host/lib/usrp/b200/b200_iface.cpp
index 5d799bf01..efb9b3a35 100644
--- a/host/lib/usrp/b200/b200_iface.cpp
+++ b/host/lib/usrp/b200/b200_iface.cpp
@@ -19,6 +19,7 @@
#include <uhd/config.hpp>
#include <uhd/utils/msg.hpp>
+#include <uhd/utils/log.hpp>
#include <uhd/exception.hpp>
#include <boost/functional/hash.hpp>
#include <boost/thread/thread.hpp>
@@ -32,6 +33,12 @@
#include <iomanip>
#include <libusb.h>
+//! libusb_error_name is only in newer API
+#ifndef HAVE_LIBUSB_ERROR_NAME
+ #define libusb_error_name(code) \
+ str(boost::format("LIBUSB_ERROR_CODE %d") % code)
+#endif
+
using namespace uhd;
using namespace uhd::transport;
@@ -298,10 +305,10 @@ public:
}
}
- void ad9361_transact(const unsigned char in_buff[64], unsigned char out_buff[64]) {
- const int bytes_to_write = 64;
- const int bytes_to_read = 64;
- const size_t read_retries = 30;
+ void ad9361_transact(const unsigned char in_buff[AD9361_DISPATCH_PACKET_SIZE], unsigned char out_buff[AD9361_DISPATCH_PACKET_SIZE]) {
+ const int bytes_to_write = AD9361_DISPATCH_PACKET_SIZE;
+ const int bytes_to_read = AD9361_DISPATCH_PACKET_SIZE;
+ const size_t read_retries = 5;
int ret = fx3_control_write(B200_VREQ_AD9361_CTRL_WRITE, 0x00, 0x00, (unsigned char *)in_buff, bytes_to_write);
if (ret < 0)
@@ -311,9 +318,26 @@ public:
for (size_t i = 0; i < read_retries; i++)
{
- ret = fx3_control_read(B200_VREQ_AD9361_CTRL_READ, 0x00, 0x00, out_buff, bytes_to_read, 1000);
+ ret = fx3_control_read(B200_VREQ_AD9361_CTRL_READ, 0x00, 0x00, out_buff, bytes_to_read, 3000);
if (ret < 0)
- throw uhd::io_error((boost::format("Failed to read AD9361 (%d: %s)") % ret % libusb_error_name(ret)).str());
+ {
+ if (ret == LIBUSB_ERROR_TIMEOUT)
+ {
+ UHD_LOG << (boost::format("Failed to read AD9361 (%d: %s). Retrying (%d of %d)...")
+ % ret
+ % libusb_error_name(ret)
+ % (i+1)
+ % read_retries
+ ) << std::endl;
+ }
+ else
+ {
+ throw uhd::io_error((boost::format("Failed to read AD9361 (%d: %s)")
+ % ret
+ % libusb_error_name(ret)
+ ).str());
+ }
+ }
if (ret == bytes_to_read)
return;
@@ -682,7 +706,7 @@ public:
const size_t percent_before = size_t((bytes_sent*100)/file_size);
bytes_sent += transfer_count;
const size_t percent_after = size_t((bytes_sent*100)/file_size);
- if (percent_before/10 != percent_after/10)
+ if (percent_before != percent_after)
{
UHD_MSG(status) << "\b\b\b\b" << std::setw(3) << percent_after << "%" << std::flush;
}
diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp
index a7f9b11bd..98141dbaa 100644
--- a/host/lib/usrp/b200/b200_impl.cpp
+++ b/host/lib/usrp/b200/b200_impl.cpp
@@ -19,6 +19,7 @@
#include "b200_regs.hpp"
#include <uhd/transport/usb_control.hpp>
#include <uhd/utils/msg.hpp>
+#include <uhd/utils/cast.hpp>
#include <uhd/exception.hpp>
#include <uhd/utils/static.hpp>
#include <uhd/utils/images.hpp>
@@ -58,11 +59,11 @@ static device_addrs_t b200_find(const device_addr_t &hint)
//since an address and resource is intended for a different, non-USB, device.
if (hint.has_key("addr") || hint.has_key("resource")) return b200_addrs;
- unsigned int vid, pid;
+ boost::uint16_t vid, pid;
if(hint.has_key("vid") && hint.has_key("pid") && hint.has_key("type") && hint["type"] == "b200") {
- sscanf(hint.get("vid").c_str(), "%x", &vid);
- sscanf(hint.get("pid").c_str(), "%x", &pid);
+ vid = uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("vid"));
+ pid = uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("pid"));
} else {
vid = B200_VENDOR_ID;
pid = B200_PRODUCT_ID;
@@ -157,12 +158,12 @@ b200_impl::b200_impl(const device_addr_t &device_addr)
const fs_path mb_path = "/mboards/0";
//try to match the given device address with something on the USB bus
- uint16_t vid = B200_VENDOR_ID;
- uint16_t pid = B200_PRODUCT_ID;
+ boost::uint16_t vid = B200_VENDOR_ID;
+ boost::uint16_t pid = B200_PRODUCT_ID;
if (device_addr.has_key("vid"))
- sscanf(device_addr.get("vid").c_str(), "%x", &vid);
+ vid = uhd::cast::hexstr_cast<boost::uint16_t>(device_addr.get("vid"));
if (device_addr.has_key("pid"))
- sscanf(device_addr.get("pid").c_str(), "%x", &pid);
+ pid = uhd::cast::hexstr_cast<boost::uint16_t>(device_addr.get("pid"));
std::vector<usb_device_handle::sptr> device_list =
usb_device_handle::get_device_list(vid, pid);
@@ -250,6 +251,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
@@ -663,9 +665,40 @@ void b200_impl::codec_loopback_self_test(wb_iface::sptr iface)
/***********************************************************************
* Sample and tick rate comprehension below
**********************************************************************/
+void b200_impl::enforce_tick_rate_limits(size_t chan_count, double tick_rate, const char* direction /*= NULL*/)
+{
+ const size_t max_chans = 2;
+ if (chan_count > max_chans)
+ {
+ throw uhd::value_error(boost::str(
+ boost::format("cannot not setup %d %s channels (maximum is %d)")
+ % chan_count
+ % (direction ? direction : "data")
+ % max_chans
+ ));
+ }
+ else
+ {
+ const double max_tick_rate = ((chan_count <= 1) ? AD9361_1_CHAN_CLOCK_RATE_MAX : AD9361_2_CHAN_CLOCK_RATE_MAX);
+ if (tick_rate > max_tick_rate)
+ {
+ throw uhd::value_error(boost::str(
+ boost::format("current master clock rate (%.2f MHz) exceeds maximum possible master clock rate (%.2f MHz) when using %d %s channels")
+ % (tick_rate/1e6)
+ % (max_tick_rate/1e6)
+ % chan_count
+ % (direction ? direction : "data")
+ ));
+ }
+ }
+}
+
double b200_impl::set_tick_rate(const double rate)
{
UHD_MSG(status) << "Asking for clock rate " << rate/1e6 << " MHz\n";
+
+ check_tick_rate_with_current_streamers(rate); // Defined in b200_io_impl.cpp
+
_tick_rate = _codec_ctrl->set_clock_rate(rate);
UHD_MSG(status) << "Actually got clock rate " << _tick_rate/1e6 << " MHz\n";
diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp
index a370e54f9..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;
@@ -91,6 +93,7 @@ public:
uhd::rx_streamer::sptr get_rx_stream(const uhd::stream_args_t &args);
uhd::tx_streamer::sptr get_tx_stream(const uhd::stream_args_t &args);
bool recv_async_msg(uhd::async_metadata_t &, double);
+ void check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const char* direction = NULL);
private:
//controllers
@@ -177,13 +180,15 @@ private:
void update_enables(void);
void update_atrs(void);
- void update_tick_rate(const double);
- void update_rx_samp_rate(const size_t, const double);
- void update_tx_samp_rate(const size_t, const double);
-
double _tick_rate;
double get_tick_rate(void){return _tick_rate;}
double set_tick_rate(const double rate);
+ void update_tick_rate(const double);
+ void enforce_tick_rate_limits(size_t chan_count, double tick_rate, const char* direction = NULL);
+ void check_tick_rate_with_current_streamers(double rate);
+
+ void update_rx_samp_rate(const size_t, const double);
+ void update_tx_samp_rate(const size_t, const double);
};
#endif /* INCLUDED_B200_IMPL_HPP */
diff --git a/host/lib/usrp/b200/b200_io_impl.cpp b/host/lib/usrp/b200/b200_io_impl.cpp
index 4f072c4d4..9f6d593fe 100644
--- a/host/lib/usrp/b200/b200_io_impl.cpp
+++ b/host/lib/usrp/b200/b200_io_impl.cpp
@@ -23,6 +23,7 @@
#include "async_packet_handler.hpp"
#include <boost/bind.hpp>
#include <boost/make_shared.hpp>
+#include <set>
using namespace uhd;
using namespace uhd::usrp;
@@ -31,8 +32,47 @@ using namespace uhd::transport;
/***********************************************************************
* update streamer rates
**********************************************************************/
+void b200_impl::check_tick_rate_with_current_streamers(double rate)
+{
+ size_t max_tx_chan_count = 0, max_rx_chan_count = 0;
+ BOOST_FOREACH(radio_perifs_t &perif, _radio_perifs)
+ {
+ {
+ boost::shared_ptr<sph::recv_packet_streamer> rx_streamer =
+ boost::dynamic_pointer_cast<sph::recv_packet_streamer>(perif.rx_streamer.lock());
+ if (rx_streamer)
+ max_rx_chan_count = std::max(max_rx_chan_count, rx_streamer->get_num_channels());
+ }
+
+ {
+ boost::shared_ptr<sph::send_packet_streamer> tx_streamer =
+ boost::dynamic_pointer_cast<sph::send_packet_streamer>(perif.tx_streamer.lock());
+ if (tx_streamer)
+ max_tx_chan_count = std::max(max_tx_chan_count, tx_streamer->get_num_channels());
+ }
+ }
+
+ // Defined in b200_impl.cpp
+ enforce_tick_rate_limits(max_rx_chan_count, rate, "RX");
+ enforce_tick_rate_limits(max_tx_chan_count, rate, "TX");
+}
+
+void b200_impl::check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const char* direction /*= NULL*/)
+{
+ std::set<size_t> chans_set;
+ for (size_t stream_i = 0; stream_i < args.channels.size(); stream_i++)
+ {
+ const size_t chan = args.channels[stream_i];
+ chans_set.insert(chan);
+ }
+
+ enforce_tick_rate_limits(chans_set.size(), tick_rate, direction); // Defined in b200_impl.cpp
+}
+
void b200_impl::update_tick_rate(const double rate)
{
+ check_tick_rate_with_current_streamers(rate);
+
BOOST_FOREACH(radio_perifs_t &perif, _radio_perifs)
{
boost::shared_ptr<sph::recv_packet_streamer> my_streamer =
@@ -222,6 +262,8 @@ rx_streamer::sptr b200_impl::get_rx_stream(const uhd::stream_args_t &args_)
if (args.otw_format.empty()) args.otw_format = "sc16";
args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels;
+ check_streamer_args(args, this->get_tick_rate(), "RX");
+
boost::shared_ptr<sph::recv_packet_streamer> my_streamer;
for (size_t stream_i = 0; stream_i < args.channels.size(); stream_i++)
{
@@ -325,6 +367,8 @@ tx_streamer::sptr b200_impl::get_tx_stream(const uhd::stream_args_t &args_)
if (args.otw_format.empty()) args.otw_format = "sc16";
args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels;
+ check_streamer_args(args, this->get_tick_rate(), "TX");
+
boost::shared_ptr<sph::send_packet_streamer> my_streamer;
for (size_t stream_i = 0; stream_i < args.channels.size(); stream_i++)
{
diff --git a/host/lib/usrp/common/ad9361_ctrl.cpp b/host/lib/usrp/common/ad9361_ctrl.cpp
index 1afa2fbb7..10496f2a9 100644
--- a/host/lib/usrp/common/ad9361_ctrl.cpp
+++ b/host/lib/usrp/common/ad9361_ctrl.cpp
@@ -151,7 +151,7 @@ struct ad9361_ctrl_impl : public ad9361_ctrl
//handle errors
const size_t len = my_strnlen(out->error_msg, AD9361_TRANSACTION_MAX_ERROR_MSG);
const std::string error_msg(out->error_msg, len);
- if (not error_msg.empty()) throw uhd::runtime_error("ad9361 do transaction: " + error_msg);
+ if (not error_msg.empty()) throw uhd::runtime_error("[ad9361_ctrl::do_transaction] firmware reported: \"" + error_msg + "\"");
//return result done!
return *out;
diff --git a/host/lib/usrp/common/ad9361_ctrl.hpp b/host/lib/usrp/common/ad9361_ctrl.hpp
index fd8012764..098b5dae8 100644
--- a/host/lib/usrp/common/ad9361_ctrl.hpp
+++ b/host/lib/usrp/common/ad9361_ctrl.hpp
@@ -27,10 +27,17 @@
#include <vector>
#include <string>
+#include "ad9361_transaction.h"
+
+
+static const double AD9361_CLOCK_RATE_MAX = 61.44e6;
+static const double AD9361_1_CHAN_CLOCK_RATE_MAX = AD9361_CLOCK_RATE_MAX;
+static const double AD9361_2_CHAN_CLOCK_RATE_MAX = (AD9361_1_CHAN_CLOCK_RATE_MAX / 2);
+
struct ad9361_ctrl_iface_type
{
- virtual void ad9361_transact(const unsigned char in_buff[64], unsigned char out_buff[64]) = 0;
+ virtual void ad9361_transact(const unsigned char in_buff[AD9361_DISPATCH_PACKET_SIZE], unsigned char out_buff[AD9361_DISPATCH_PACKET_SIZE]) = 0;
};
typedef boost::shared_ptr<ad9361_ctrl_iface_type> ad9361_ctrl_iface_sptr;
@@ -42,18 +49,18 @@ struct ad9361_ctrl_over_zc : ad9361_ctrl_iface_type
_xport = xport;
}
- void ad9361_transact(const unsigned char in_buff[64], unsigned char out_buff[64])
+ void ad9361_transact(const unsigned char in_buff[AD9361_DISPATCH_PACKET_SIZE], unsigned char out_buff[AD9361_DISPATCH_PACKET_SIZE])
{
{
uhd::transport::managed_send_buffer::sptr buff = _xport->get_send_buff(10.0);
- if (not buff or buff->size() < 64) throw std::runtime_error("ad9361_ctrl_over_zc send timeout");
- std::memcpy(buff->cast<void *>(), in_buff, 64);
- buff->commit(64);
+ if (not buff or buff->size() < AD9361_DISPATCH_PACKET_SIZE) throw std::runtime_error("ad9361_ctrl_over_zc send timeout");
+ std::memcpy(buff->cast<void *>(), in_buff, AD9361_DISPATCH_PACKET_SIZE);
+ buff->commit(AD9361_DISPATCH_PACKET_SIZE);
}
{
uhd::transport::managed_recv_buffer::sptr buff = _xport->get_recv_buff(10.0);
- if (not buff or buff->size() < 64) throw std::runtime_error("ad9361_ctrl_over_zc recv timeout");
- std::memcpy(out_buff, buff->cast<const void *>(), 64);
+ if (not buff or buff->size() < AD9361_DISPATCH_PACKET_SIZE) throw std::runtime_error("ad9361_ctrl_over_zc recv timeout");
+ std::memcpy(out_buff, buff->cast<const void *>(), AD9361_DISPATCH_PACKET_SIZE);
}
}
@@ -100,7 +107,7 @@ public:
static uhd::meta_range_t get_clock_rate_range(void)
{
//return uhd::meta_range_t(220e3, 61.44e6);
- return uhd::meta_range_t(5e6, 61.44e6); //5 MHz DCM low end
+ return uhd::meta_range_t(5e6, AD9361_CLOCK_RATE_MAX); //5 MHz DCM low end
}
//! set the filter bandwidth for the frontend
diff --git a/host/lib/usrp/common/ad9361_transaction.h b/host/lib/usrp/common/ad9361_transaction.h
index 7cbad5908..693f32e41 100644
--- a/host/lib/usrp/common/ad9361_transaction.h
+++ b/host/lib/usrp/common/ad9361_transaction.h
@@ -25,8 +25,8 @@ extern "C" {
#endif
//various constants
-#define AD9361_TRANSACTION_VERSION 0x4
-#define AD9361_TRANSACTION_MAX_ERROR_MSG 40
+#define AD9361_TRANSACTION_VERSION 0x4
+#define AD9361_DISPATCH_PACKET_SIZE 64
//action types
#define AD9361_ACTION_ECHO 0
@@ -100,6 +100,7 @@ typedef struct
} ad9361_transaction_t;
+#define AD9361_TRANSACTION_MAX_ERROR_MSG (AD9361_DISPATCH_PACKET_SIZE - (sizeof(ad9361_transaction_t)-4)-1) // -4 for 'error_msg' alignment padding, -1 for terminating \0
#ifdef __cplusplus
}
diff --git a/host/lib/usrp/common/adf435x_common.cpp b/host/lib/usrp/common/adf435x_common.cpp
index f0df6a334..972a69388 100644
--- a/host/lib/usrp/common/adf435x_common.cpp
+++ b/host/lib/usrp/common/adf435x_common.cpp
@@ -16,8 +16,11 @@
//
#include "adf435x_common.hpp"
+
#include <uhd/types/tune_request.hpp>
#include <uhd/utils/log.hpp>
+#include <cmath>
+
using namespace uhd;
diff --git a/host/lib/usrp/cores/rx_dsp_core_3000.cpp b/host/lib/usrp/cores/rx_dsp_core_3000.cpp
index 86846667f..02c24b4bb 100644
--- a/host/lib/usrp/cores/rx_dsp_core_3000.cpp
+++ b/host/lib/usrp/cores/rx_dsp_core_3000.cpp
@@ -91,8 +91,10 @@ public:
uhd::meta_range_t get_host_rates(void){
meta_range_t range;
- for (int rate = 1024; rate > 512; rate -= 8){
- range.push_back(range_t(_tick_rate/rate));
+ if (!_is_b200) {
+ for (int rate = 1024; rate > 512; rate -= 8){
+ range.push_back(range_t(_tick_rate/rate));
+ }
}
for (int rate = 512; rate > 256; rate -= 4){
range.push_back(range_t(_tick_rate/rate));
diff --git a/host/lib/usrp/dboard/db_tvrx2.cpp b/host/lib/usrp/dboard/db_tvrx2.cpp
index c593c5437..c74c64471 100644
--- a/host/lib/usrp/dboard/db_tvrx2.cpp
+++ b/host/lib/usrp/dboard/db_tvrx2.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010,2012-2013 Ettus Research LLC
+// Copyright 2010,2012-2014 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
@@ -1005,8 +1005,8 @@ tvrx2::tvrx2(ctor_args_t args) : rx_dboard_base(args){
_freq_scalar = (4*16.0e6)/(this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX));
} else if (ref_clock == 100e6) {
-
- this->get_iface()->set_gpio_out(dboard_iface::UNIT_RX, REFCLOCK_DIV8);
+
+ this->get_iface()->set_gpio_out(dboard_iface::UNIT_RX, REFCLOCK_DIV6);
UHD_LOGV(often) << boost::format(
"TVRX2 (%s): Dividing Refclock by 6"
diff --git a/host/lib/usrp/gps_ctrl.cpp b/host/lib/usrp/gps_ctrl.cpp
index 6f5c75dec..d327a84f9 100644
--- a/host/lib/usrp/gps_ctrl.cpp
+++ b/host/lib/usrp/gps_ctrl.cpp
@@ -74,8 +74,15 @@ private:
// Get all GPSDO messages available
// Creating a map here because we only want the latest of each message type
- for (std::string msg = _recv(); msg.length() > 6; msg = _recv())
+ for (std::string msg = _recv(); msg.length(); msg = _recv())
{
+ if (msg.length() < 6)
+ continue;
+
+ // Strip any end of line characters
+ erase_all(msg, "\r");
+ erase_all(msg, "\n");
+
// Look for SERVO message
if (boost::regex_search(msg, status_regex, boost::regex_constants::match_continuous))
msgs["SERVO"] = msg;
diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp
index f08709669..71b1f8995 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);
@@ -739,7 +747,11 @@ public:
void set_rx_dc_offset(const bool enb, size_t chan){
if (chan != ALL_CHANS){
- _tree->access<bool>(rx_fe_root(chan) / "dc_offset" / "enable").set(enb);
+ if (_tree->exists(rx_fe_root(chan) / "dc_offset" / "enable")) {
+ _tree->access<bool>(rx_fe_root(chan) / "dc_offset" / "enable").set(enb);
+ } else {
+ UHD_MSG(warning) << "Setting DC offset compensation is not possible on this device." << std::endl;
+ }
return;
}
for (size_t c = 0; c < get_rx_num_channels(); c++){
@@ -749,7 +761,11 @@ public:
void set_rx_dc_offset(const std::complex<double> &offset, size_t chan){
if (chan != ALL_CHANS){
- _tree->access<std::complex<double> >(rx_fe_root(chan) / "dc_offset" / "value").set(offset);
+ if (_tree->exists(rx_fe_root(chan) / "dc_offset" / "value")) {
+ _tree->access<std::complex<double> >(rx_fe_root(chan) / "dc_offset" / "value").set(offset);
+ } else {
+ UHD_MSG(warning) << "Setting DC offset is not possible on this device." << std::endl;
+ }
return;
}
for (size_t c = 0; c < get_rx_num_channels(); c++){
@@ -759,7 +775,11 @@ public:
void set_rx_iq_balance(const std::complex<double> &offset, size_t chan){
if (chan != ALL_CHANS){
- _tree->access<std::complex<double> >(rx_fe_root(chan) / "iq_balance" / "value").set(offset);
+ if (_tree->exists(rx_fe_root(chan) / "iq_balance" / "value")) {
+ _tree->access<std::complex<double> >(rx_fe_root(chan) / "iq_balance" / "value").set(offset);
+ } else {
+ UHD_MSG(warning) << "Setting IQ balance is not possible on this device." << std::endl;
+ }
return;
}
for (size_t c = 0; c < get_rx_num_channels(); c++){
@@ -770,6 +790,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);
@@ -920,7 +945,11 @@ public:
void set_tx_dc_offset(const std::complex<double> &offset, size_t chan){
if (chan != ALL_CHANS){
- _tree->access<std::complex<double> >(tx_fe_root(chan) / "dc_offset" / "value").set(offset);
+ if (_tree->exists(tx_fe_root(chan) / "dc_offset" / "value")) {
+ _tree->access<std::complex<double> >(tx_fe_root(chan) / "dc_offset" / "value").set(offset);
+ } else {
+ UHD_MSG(warning) << "Setting DC offset is not possible on this device." << std::endl;
+ }
return;
}
for (size_t c = 0; c < get_tx_num_channels(); c++){
@@ -930,7 +959,11 @@ public:
void set_tx_iq_balance(const std::complex<double> &offset, size_t chan){
if (chan != ALL_CHANS){
- _tree->access<std::complex<double> >(tx_fe_root(chan) / "iq_balance" / "value").set(offset);
+ if (_tree->exists(tx_fe_root(chan) / "iq_balance" / "value")) {
+ _tree->access<std::complex<double> >(tx_fe_root(chan) / "iq_balance" / "value").set(offset);
+ } else {
+ UHD_MSG(warning) << "Setting IQ balance is not possible on this device." << std::endl;
+ }
return;
}
for (size_t c = 0; c < get_tx_num_channels(); c++){
@@ -1178,6 +1211,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.empty() ? "sc16" : 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..0ba2e1e4a 100644
--- a/host/lib/usrp/usrp1/usrp1_impl.cpp
+++ b/host/lib/usrp/usrp1/usrp1_impl.cpp
@@ -20,6 +20,7 @@
#include <uhd/utils/safe_call.hpp>
#include <uhd/transport/usb_control.hpp>
#include <uhd/utils/msg.hpp>
+#include <uhd/utils/cast.hpp>
#include <uhd/exception.hpp>
#include <uhd/utils/static.hpp>
#include <uhd/utils/images.hpp>
@@ -59,11 +60,11 @@ static device_addrs_t usrp1_find(const device_addr_t &hint)
//since an address and resource is intended for a different, non-USB, device.
if (hint.has_key("addr") || hint.has_key("resource")) return usrp1_addrs;
- unsigned int vid, pid;
+ boost::uint16_t vid, pid;
if(hint.has_key("vid") && hint.has_key("pid") && hint.has_key("type") && hint["type"] == "usrp1") {
- sscanf(hint.get("vid").c_str(), "%x", &vid);
- sscanf(hint.get("pid").c_str(), "%x", &pid);
+ vid = uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("vid"));
+ pid = uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("pid"));
} else {
vid = USRP1_VENDOR_ID;
pid = USRP1_PRODUCT_ID;
@@ -409,7 +410,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/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt
index da39d9df1..c6257c7fe 100644
--- a/host/lib/usrp/usrp2/CMakeLists.txt
+++ b/host/lib/usrp/usrp2/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2011-2012 Ettus Research LLC
+# Copyright 2011-2012,2014 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
@@ -25,6 +25,18 @@
LIBUHD_REGISTER_COMPONENT("USRP2" ENABLE_USRP2 ON "ENABLE_LIBUHD" OFF)
IF(ENABLE_USRP2)
+ ########################################################################
+ # Define UHD_PKG_DATA_PATH for usrp2_iface.cpp
+ ########################################################################
+ FILE(TO_NATIVE_PATH ${CMAKE_INSTALL_PREFIX} UHD_PKG_PATH)
+ STRING(REPLACE "\\" "\\\\" UHD_PKG_PATH ${UHD_PKG_PATH})
+
+ SET_SOURCE_FILES_PROPERTIES(
+ ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_iface.cpp
+ PROPERTIES COMPILE_DEFINITIONS
+ "UHD_LIB_DIR=\"lib${LIB_SUFFIX}\""
+ )
+
LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.cpp
diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp
index 7297a30d1..b2085807f 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.cpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2012 Ettus Research LLC
+// Copyright 2010-2012,2014 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -21,6 +21,7 @@
#include "usrp2_iface.hpp"
#include <uhd/exception.hpp>
#include <uhd/utils/msg.hpp>
+#include <uhd/utils/paths.hpp>
#include <uhd/utils/tasks.hpp>
#include <uhd/utils/images.hpp>
#include <uhd/utils/safe_call.hpp>
@@ -386,13 +387,13 @@ public:
//create the burner commands
if (this->get_rev() == USRP2_REV3 or this->get_rev() == USRP2_REV4){
- const std::string card_burner = (fs::path(fw_image_path).branch_path().branch_path() / "utils" / "usrp2_card_burner.py").string();
+ const std::string card_burner = (fs::path(uhd::get_pkg_path()) / UHD_LIB_DIR / "uhd" / "utils" / "usrp2_card_burner.py").string();
const std::string card_burner_cmd = str(boost::format("\"%s%s\" %s--fpga=\"%s\" %s--fw=\"%s\"") % sudo % card_burner % ml % fpga_image_path % ml % fw_image_path);
return str(boost::format("%s\n%s") % print_images_error() % card_burner_cmd);
}
else{
const std::string addr = _ctrl_transport->get_recv_addr();
- const std::string net_burner_path = (fs::path(fw_image_path).branch_path().branch_path() / "utils" / "usrp_n2xx_simple_net_burner").string();
+ const std::string net_burner_path = (fs::path(uhd::get_pkg_path()) / UHD_LIB_DIR / "uhd" / "utils" / "usrp_n2xx_simple_net_burner").string();
const std::string net_burner_cmd = str(boost::format("\"%s\" %s--addr=\"%s\"") % net_burner_path % ml % addr);
return str(boost::format("%s\n%s") % print_images_error() % net_burner_cmd);
}
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index 16d9b9a54..918f3e892 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
@@ -655,12 +656,14 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
.subscribe(boost::bind(&time64_core_200::set_time_next_pps, _mbc[mb].time64, _1));
//setup time source props
_tree->create<std::string>(mb_path / "time_source/value")
- .subscribe(boost::bind(&time64_core_200::set_time_source, _mbc[mb].time64, _1));
+ .subscribe(boost::bind(&time64_core_200::set_time_source, _mbc[mb].time64, _1))
+ .set("none");
_tree->create<std::vector<std::string> >(mb_path / "time_source/options")
.publish(boost::bind(&time64_core_200::get_time_sources, _mbc[mb].time64));
//setup reference source props
_tree->create<std::string>(mb_path / "clock_source/value")
- .subscribe(boost::bind(&usrp2_impl::update_clock_source, this, mb, _1));
+ .subscribe(boost::bind(&usrp2_impl::update_clock_source, this, mb, _1))
+ .set("internal");
std::vector<std::string> clock_sources = boost::assign::list_of("internal")("external")("mimo");
if (_mbc[mb].gps and _mbc[mb].gps->gps_detected()) clock_sources.push_back("gpsdo");
_tree->create<std::vector<std::string> >(mb_path / "clock_source/options").set(clock_sources);
diff --git a/host/lib/usrp/x300/x300_fw_common.h b/host/lib/usrp/x300/x300_fw_common.h
index 632391644..0bbaee319 100644
--- a/host/lib/usrp/x300/x300_fw_common.h
+++ b/host/lib/usrp/x300/x300_fw_common.h
@@ -31,7 +31,7 @@ extern "C" {
#define X300_FW_COMPAT_MAJOR 3
#define X300_FW_COMPAT_MINOR 0
-#define X300_FPGA_COMPAT_MAJOR 4
+#define X300_FPGA_COMPAT_MAJOR 6
//shared memory sections - in between the stack and the program space
#define X300_FW_SHMEM_BASE 0x6000
diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp
index e492b2238..e931b7983 100644
--- a/host/lib/usrp/x300/x300_impl.cpp
+++ b/host/lib/usrp/x300/x300_impl.cpp
@@ -135,6 +135,12 @@ static device_addrs_t x300_find_with_addr(const device_addr_t &hint)
return addrs;
}
+//We need a zpu xport registry to ensure synchronization between the static finder method
+//and the instances of the x300_impl class.
+typedef uhd::dict< std::string, boost::weak_ptr<wb_iface> > pcie_zpu_iface_registry_t;
+UHD_SINGLETON_FCN(pcie_zpu_iface_registry_t, get_pcie_zpu_iface_registry)
+static boost::mutex pcie_zpu_iface_registry_mutex;
+
static device_addrs_t x300_find_pcie(const device_addr_t &hint, bool explicit_query)
{
std::string rpc_port_name(NIUSRPRIO_DEFAULT_RPC_PORT);
@@ -167,17 +173,30 @@ static device_addrs_t x300_find_pcie(const device_addr_t &hint, bool explicit_qu
}
niriok_proxy kernel_proxy;
- kernel_proxy.open(dev_info.interface_path);
//Attempt to read the name from the EEPROM and perform filtering.
//This operation can throw due to compatibility mismatch.
try
{
- //This call could throw an exception if the user is switching to using UHD
+ //This block could throw an exception if the user is switching to using UHD
//after LabVIEW FPGA. In that case, skip reading the name and serial and pick
//a default FPGA flavor. During make, a new image will be loaded and everything
//will be OK
- wb_iface::sptr zpu_ctrl = x300_make_ctrl_iface_pcie(kernel_proxy);
+
+ wb_iface::sptr zpu_ctrl;
+
+ //Hold on to the registry mutex as long as zpu_ctrl is alive
+ //to prevent any use by different threads while enumerating
+ boost::mutex::scoped_lock(pcie_zpu_iface_registry_mutex);
+
+ if (get_pcie_zpu_iface_registry().has_key(resource_d)) {
+ zpu_ctrl = get_pcie_zpu_iface_registry()[resource_d].lock();
+ } else {
+ kernel_proxy.open(dev_info.interface_path);
+ zpu_ctrl = x300_make_ctrl_iface_pcie(kernel_proxy);
+ //We don't put this zpu_ctrl in the registry because we need
+ //a persistent niriok_proxy associated with the object
+ }
if (x300_impl::is_claimed(zpu_ctrl)) continue; //claimed by another process
//Attempt to autodetect the FPGA type
@@ -392,6 +411,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,12 +477,20 @@ 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
UHD_MSG(status) << "Setup basic communication..." << std::endl;
if (mb.xport_path == "nirio") {
- mb.zpu_ctrl = x300_make_ctrl_iface_pcie(mb.rio_fpga_interface->get_kernel_proxy());
+ boost::mutex::scoped_lock(pcie_zpu_iface_registry_mutex);
+ if (get_pcie_zpu_iface_registry().has_key(mb.addr)) {
+ throw uhd::assertion_error("Someone else has a ZPU transport to the device open. Internal error!");
+ } else {
+ mb.zpu_ctrl = x300_make_ctrl_iface_pcie(mb.rio_fpga_interface->get_kernel_proxy());
+ get_pcie_zpu_iface_registry()[mb.addr] = boost::weak_ptr<wb_iface>(mb.zpu_ctrl);
+ }
} else {
mb.zpu_ctrl = x300_make_ctrl_iface_enet(udp_simple::make_connected(mb.addr,
BOOST_STRINGIZE(X300_FW_COMMS_UDP_PORT)));
@@ -830,8 +859,14 @@ x300_impl::~x300_impl(void)
//kill the claimer task and unclaim the device
mb.claimer_task.reset();
- mb.zpu_ctrl->poke32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_CLAIM_TIME), 0);
- mb.zpu_ctrl->poke32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_CLAIM_SRC), 0);
+ { //Critical section
+ boost::mutex::scoped_lock(pcie_zpu_iface_registry_mutex);
+ mb.zpu_ctrl->poke32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_CLAIM_TIME), 0);
+ mb.zpu_ctrl->poke32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_CLAIM_SRC), 0);
+ //If the process is killed, the entire registry will disappear so we
+ //don't need to worry about unclean shutdowns here.
+ get_pcie_zpu_iface_registry().pop(mb.addr);
+ }
}
}
catch(...)
@@ -1133,11 +1168,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) {
@@ -1380,7 +1418,8 @@ void x300_impl::update_time_source(mboard_members_t &mb, const std::string &sour
//check for valid pps
if (!is_pps_present(mb.zpu_ctrl))
{
- throw uhd::runtime_error((boost::format("The %d PPS was not detected. Please check the PPS source and try again.") % source).str());
+ // TODO - Implement intelligent PPS detection
+ /* throw uhd::runtime_error((boost::format("The %d PPS was not detected. Please check the PPS source and try again.") % source).str()); */
}
}
@@ -1453,13 +1492,18 @@ void x300_impl::set_fp_gpio(gpio_core_200::sptr gpio, const std::string &attr, c
void x300_impl::claimer_loop(wb_iface::sptr iface)
{
- iface->poke32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_CLAIM_TIME), time(NULL));
- iface->poke32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_CLAIM_SRC), get_process_hash());
- boost::this_thread::sleep(boost::posix_time::milliseconds(1500)); //1.5 seconds
+ { //Critical section
+ boost::mutex::scoped_lock(claimer_mutex);
+ iface->poke32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_CLAIM_TIME), time(NULL));
+ iface->poke32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_CLAIM_SRC), get_process_hash());
+ }
+ boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); //1 second
}
bool x300_impl::is_claimed(wb_iface::sptr iface)
{
+ boost::mutex::scoped_lock(claimer_mutex);
+
//If timed out then device is definitely unclaimed
if (iface->peek32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_CLAIM_STATUS)) == 0)
return false;
diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp
index 259ea253d..90aed2fdb 100644
--- a/host/lib/usrp/x300/x300_impl.hpp
+++ b/host/lib/usrp/x300/x300_impl.hpp
@@ -53,7 +53,7 @@
static const std::string X300_FW_FILE_NAME = "usrp_x300_fw.bin";
static const double X300_DEFAULT_TICK_RATE = 200e6; //Hz
-static const double X300_BUS_CLOCK_RATE = 175e6; //Hz
+static const double X300_BUS_CLOCK_RATE = 166.666667e6; //Hz
static const size_t X300_TX_HW_BUFF_SIZE = 0x90000; //576KiB
static const size_t X300_TX_FC_RESPONSE_FREQ = 8; //per flow-control window
@@ -76,6 +76,19 @@ static const size_t X300_ETH_MSG_NUM_FRAMES = 32;
static const size_t X300_ETH_DATA_NUM_FRAMES = 32;
static const double X300_DEFAULT_SYSREF_RATE = 10e6;
+static const size_t X300_TX_MAX_HDR_LEN = // bytes
+ sizeof(boost::uint32_t) // Header
+ + 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_RX_MAX_HDR_LEN = // bytes
+ sizeof(boost::uint32_t) // Header
+ + 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
@@ -139,6 +152,7 @@ public:
bool recv_async_msg(uhd::async_metadata_t &, double);
// used by x300_find_with_addr to find X300 devices.
+ static boost::mutex claimer_mutex; //All claims and checks in this process are serialized
static bool is_claimed(uhd::wb_iface::sptr);
enum x300_mboard_t {
diff --git a/host/lib/usrp/x300/x300_io_impl.cpp b/host/lib/usrp/x300/x300_io_impl.cpp
index 85de34a54..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;
}
@@ -399,15 +408,9 @@ rx_streamer::sptr x300_impl::get_rx_stream(const uhd::stream_args_t &args_)
both_xports_t xport = this->make_transport(mb_index, dest, X300_RADIO_DEST_PREFIX_RX, device_addr, data_sid);
UHD_LOG << boost::format("data_sid = 0x%08x, actual recv_buff_size = %d\n") % data_sid % xport.recv_buff_size << std::endl;
- //calculate packet size
- static const size_t hdr_size = 0
- + vrt::num_vrl_words32*sizeof(boost::uint32_t)
- + vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
- + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer
- - sizeof(vrt::if_packet_info_t().cid) //no class id ever used
- - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used
- ;
- const size_t bpp = xport.recv->get_recv_frame_size() - hdr_size; // bytes per packet
+ // To calculate the max number of samples per packet, we assume the maximum header length
+ // to avoid fragmentation should the entire header be used.
+ const size_t bpp = xport.recv->get_recv_frame_size() - X300_RX_MAX_HDR_LEN; // bytes per packet
const size_t bpi = convert::get_bytes_per_item(args.otw_format); // bytes per item
const size_t spp = unsigned(args.args.cast<double>("spp", bpp/bpi)); // samples per packet
@@ -568,15 +571,9 @@ tx_streamer::sptr x300_impl::get_tx_stream(const uhd::stream_args_t &args_)
both_xports_t xport = this->make_transport(mb_index, dest, X300_RADIO_DEST_PREFIX_TX, device_addr, data_sid);
UHD_LOG << boost::format("data_sid = 0x%08x\n") % data_sid << std::endl;
- //calculate packet size
- static const size_t hdr_size = 0
- + vrt::num_vrl_words32*sizeof(boost::uint32_t)
- + vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
- //+ sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer
- - sizeof(vrt::if_packet_info_t().cid) //no class id ever used
- - sizeof(vrt::if_packet_info_t().tsi) //no int time ever used
- ;
- const size_t bpp = xport.send->get_send_frame_size() - hdr_size;
+ // To calculate the max number of samples per packet, we assume the maximum header length
+ // to avoid fragmentation should the entire header be used.
+ const size_t bpp = xport.send->get_send_frame_size() - X300_TX_MAX_HDR_LEN;
const size_t bpi = convert::get_bytes_per_item(args.otw_format);
const size_t spp = unsigned(args.args.cast<double>("spp", bpp/bpi));
diff --git a/host/lib/usrp/x300/x300_regs.hpp b/host/lib/usrp/x300/x300_regs.hpp
index fb1786deb..cf1e33695 100644
--- a/host/lib/usrp/x300/x300_regs.hpp
+++ b/host/lib/usrp/x300/x300_regs.hpp
@@ -124,9 +124,12 @@ static const uint32_t FPGA_PCIE_SIG_REG = PCIE_FPGA_REG(0x0000);
static const uint32_t FPGA_CNTR_LO_REG = PCIE_FPGA_REG(0x0004);
static const uint32_t FPGA_CNTR_HI_REG = PCIE_FPGA_REG(0x0008);
static const uint32_t FPGA_CNTR_FREQ_REG = PCIE_FPGA_REG(0x000C);
+static const uint32_t FPGA_STATUS_REG = PCIE_FPGA_REG(0x0020);
static const uint32_t FPGA_USR_SIG_REG_BASE = PCIE_FPGA_REG(0x0030);
static const uint32_t FPGA_USR_SIG_REG_SIZE = 16;
+static const uint32_t FPGA_STATUS_DMA_ACTIVE_MASK = 0x3F3F0000;
+
static const uint32_t PCIE_TX_DMA_REG_BASE = PCIE_FPGA_REG(0x0200);
static const uint32_t PCIE_RX_DMA_REG_BASE = PCIE_FPGA_REG(0x0400);
@@ -139,12 +142,15 @@ static const uint32_t DMA_PKT_COUNT_REG = 0xC;
#define PCIE_TX_DMA_REG(REG, CHAN) (PCIE_TX_DMA_REG_BASE + (CHAN*DMA_REG_GRP_SIZE) + REG)
#define PCIE_RX_DMA_REG(REG, CHAN) (PCIE_RX_DMA_REG_BASE + (CHAN*DMA_REG_GRP_SIZE) + REG)
-static const uint32_t DMA_CTRL_RESET = 1;
+static const uint32_t DMA_CTRL_DISABLED = 0x00000000;
+static const uint32_t DMA_CTRL_ENABLED = 0x00000002;
+static const uint32_t DMA_CTRL_CLEAR_STB = 0x00000001;
static const uint32_t DMA_CTRL_SW_BUF_U64 = (3 << 4);
static const uint32_t DMA_CTRL_SW_BUF_U32 = (2 << 4);
static const uint32_t DMA_CTRL_SW_BUF_U16 = (1 << 4);
static const uint32_t DMA_CTRL_SW_BUF_U8 = (0 << 4);
-static const uint32_t DMA_STATUS_ERROR = 1;
+static const uint32_t DMA_STATUS_ERROR = 0x00000001;
+static const uint32_t DMA_STATUS_BUSY = 0x00000002;
static const uint32_t PCIE_ROUTER_REG_BASE = PCIE_FPGA_REG(0x0500);
#define PCIE_ROUTER_REG(X) (PCIE_ROUTER_REG_BASE + X)