aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp')
-rw-r--r--host/lib/usrp/b200/CMakeLists.txt2
-rw-r--r--host/lib/usrp/b200/b200_iface.hpp3
-rw-r--r--host/lib/usrp/b200/b200_impl.cpp176
-rw-r--r--host/lib/usrp/b200/b200_impl.hpp62
-rw-r--r--host/lib/usrp/b200/b200_io_impl.cpp156
-rw-r--r--host/lib/usrp/b200/b200_regs.hpp2
-rw-r--r--host/lib/usrp/common/ad9361_ctrl.cpp44
-rw-r--r--host/lib/usrp/common/ad9361_ctrl.hpp33
-rw-r--r--host/lib/usrp/common/ad9361_driver/ad9361_device.cpp372
-rw-r--r--host/lib/usrp/common/ad9361_driver/ad9361_device.h30
-rw-r--r--host/lib/usrp/common/ad9361_driver/ad9361_gain_tables.h162
-rw-r--r--host/lib/usrp/common/ad9361_driver/ad9361_synth_lut.h28
-rw-r--r--host/lib/usrp/cores/gpio_core_200.hpp26
-rw-r--r--host/lib/usrp/cores/rx_dsp_core_3000.cpp2
-rw-r--r--host/lib/usrp/cores/time_core_3000.cpp6
-rw-r--r--host/lib/usrp/dboard/db_cbx.cpp2
-rw-r--r--host/lib/usrp/dboard/db_ubx.cpp52
-rw-r--r--host/lib/usrp/e300/e300_eeprom_manager.cpp4
-rw-r--r--host/lib/usrp/e300/e300_impl.cpp36
-rw-r--r--host/lib/usrp/e300/e300_impl.hpp8
-rw-r--r--host/lib/usrp/e300/e300_io_impl.cpp48
-rw-r--r--host/lib/usrp/e300/e300_network.cpp18
-rw-r--r--host/lib/usrp/e300/e300_remote_codec_ctrl.cpp76
-rw-r--r--host/lib/usrp/e300/e300_remote_codec_ctrl.hpp10
-rw-r--r--host/lib/usrp/e300/e300_sensor_manager.hpp2
-rw-r--r--host/lib/usrp/e300/e300_spi.cpp6
-rw-r--r--host/lib/usrp/e300/e300_ublox_control_impl.cpp2
-rw-r--r--host/lib/usrp/multi_usrp.cpp204
-rw-r--r--host/lib/usrp/usrp2/io_impl.cpp3
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.cpp2
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp5
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp1
-rw-r--r--host/lib/usrp/x300/x300_impl.cpp85
-rw-r--r--host/lib/usrp/x300/x300_impl.hpp6
-rw-r--r--host/lib/usrp/x300/x300_io_impl.cpp52
-rw-r--r--host/lib/usrp/x300/x300_regs.hpp140
36 files changed, 1429 insertions, 437 deletions
diff --git a/host/lib/usrp/b200/CMakeLists.txt b/host/lib/usrp/b200/CMakeLists.txt
index a08c4bd03..ce89b5d80 100644
--- a/host/lib/usrp/b200/CMakeLists.txt
+++ b/host/lib/usrp/b200/CMakeLists.txt
@@ -20,7 +20,7 @@
########################################################################
########################################################################
-# Conditionally configure the B100 support
+# Conditionally configure the B200 support
########################################################################
LIBUHD_REGISTER_COMPONENT("B200" ENABLE_B200 ON "ENABLE_LIBUHD;ENABLE_USB" OFF)
diff --git a/host/lib/usrp/b200/b200_iface.hpp b/host/lib/usrp/b200/b200_iface.hpp
index 83adfdd64..1821865d3 100644
--- a/host/lib/usrp/b200/b200_iface.hpp
+++ b/host/lib/usrp/b200/b200_iface.hpp
@@ -26,7 +26,10 @@
#include "ad9361_ctrl.hpp"
const static boost::uint16_t B200_VENDOR_ID = 0x2500;
+const static boost::uint16_t B200_VENDOR_NI_ID = 0x3923;
const static boost::uint16_t B200_PRODUCT_ID = 0x0020;
+const static boost::uint16_t B200_PRODUCT_NI_ID = 0x7813;
+const static boost::uint16_t B210_PRODUCT_NI_ID = 0x7814;
const static boost::uint16_t FX3_VID = 0x04b4;
const static boost::uint16_t FX3_DEFAULT_PID = 0x00f3;
const static boost::uint16_t FX3_REENUM_PID = 0x00f0;
diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp
index 355d12d12..647c64695 100644
--- a/host/lib/usrp/b200/b200_impl.cpp
+++ b/host/lib/usrp/b200/b200_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2012-2014 Ettus Research LLC
+// Copyright 2012-2015 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
@@ -86,16 +86,20 @@ static device_addrs_t b200_find(const device_addr_t &hint)
//Return an empty list of addresses when an address or resource is specified,
//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;
+ BOOST_FOREACH(device_addr_t hint_i, separate_device_addr(hint)) {
+ if (hint_i.has_key("addr") || hint_i.has_key("resource")) return b200_addrs;
+ }
- boost::uint16_t vid, pid;
+ size_t found = 0;
+ std::vector<usb_device_handle::vid_pid_pair_t> vid_pid_pair_list;//vid pid pair search list for devices.
if(hint.has_key("vid") && hint.has_key("pid") && hint.has_key("type") && hint["type"] == "b200") {
- vid = uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("vid"));
- pid = uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("pid"));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("vid")),
+ uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("pid"))));
} else {
- vid = B200_VENDOR_ID;
- pid = B200_PRODUCT_ID;
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID, B200_PRODUCT_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID, B200_PRODUCT_NI_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID, B210_PRODUCT_NI_ID));
}
// Important note:
@@ -105,8 +109,9 @@ static device_addrs_t b200_find(const device_addr_t &hint)
// This requirement is a courtesy of libusb1.0 on windows.
//find the usrps and load firmware
- size_t found = 0;
- BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid, pid)) {
+ std::vector<usb_device_handle::sptr> uhd_usb_device_vector = usb_device_handle::get_device_list(vid_pid_pair_list);
+
+ BOOST_FOREACH(usb_device_handle::sptr handle, uhd_usb_device_vector) {
//extract the firmware path for the b200
std::string b200_fw_image;
try{
@@ -137,7 +142,7 @@ static device_addrs_t b200_find(const device_addr_t &hint)
//search for the device until found or timeout
while (boost::get_system_time() < timeout_time and b200_addrs.empty() and found != 0)
{
- BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid, pid))
+ BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid_pid_pair_list))
{
usb_control::sptr control;
try{control = usb_control::make(handle, 0);}
@@ -154,12 +159,16 @@ static device_addrs_t b200_find(const device_addr_t &hint)
{
switch (boost::lexical_cast<boost::uint16_t>(mb_eeprom["product"]))
{
+ //0x0001 and 0x7737 are Ettus B200 product Ids.
case 0x0001:
case 0x7737:
+ case B200_PRODUCT_NI_ID:
new_addr["product"] = "B200";
break;
- case 0x7738:
+ //0x0002 and 0x7738 are Ettus B210 product Ids.
case 0x0002:
+ case 0x7738:
+ case B210_PRODUCT_NI_ID:
new_addr["product"] = "B210";
break;
default: UHD_MSG(error) << "B200 unknown product code: " << mb_eeprom["product"] << std::endl;
@@ -194,7 +203,8 @@ UHD_STATIC_BLOCK(register_b200_device)
/***********************************************************************
* Structors
**********************************************************************/
-b200_impl::b200_impl(const device_addr_t &device_addr)
+b200_impl::b200_impl(const device_addr_t &device_addr) :
+ _tick_rate(0.0) // Forces a clock initialization at startup
{
_tree = property_tree::make();
_type = device::USRP;
@@ -203,13 +213,50 @@ b200_impl::b200_impl(const device_addr_t &device_addr)
//try to match the given device address with something on the USB bus
boost::uint16_t vid = B200_VENDOR_ID;
boost::uint16_t pid = B200_PRODUCT_ID;
+ bool specified_vid = false;
+ bool specified_pid = false;
+
if (device_addr.has_key("vid"))
+ {
vid = uhd::cast::hexstr_cast<boost::uint16_t>(device_addr.get("vid"));
+ specified_vid = true;
+ }
+
if (device_addr.has_key("pid"))
+ {
pid = uhd::cast::hexstr_cast<boost::uint16_t>(device_addr.get("pid"));
+ specified_pid = true;
+ }
+
+ std::vector<usb_device_handle::vid_pid_pair_t> vid_pid_pair_list;//search list for devices.
+
+ // Search only for specified VID and PID if both specified
+ if (specified_vid && specified_pid)
+ {
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,pid));
+ }
+ // Search for all supported PIDs limited to specified VID if only VID specified
+ else if (specified_vid)
+ {
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,B200_PRODUCT_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,B200_PRODUCT_NI_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,B210_PRODUCT_NI_ID));
+ }
+ // Search for all supported VIDs limited to specified PID if only PID specified
+ else if (specified_pid)
+ {
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID,pid));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID,pid));
+ }
+ // Search for all supported devices if neither VID nor PID specified
+ else
+ {
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID,B200_PRODUCT_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID,B200_PRODUCT_NI_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID,B210_PRODUCT_NI_ID));
+ }
- std::vector<usb_device_handle::sptr> device_list =
- usb_device_handle::get_device_list(vid, pid);
+ std::vector<usb_device_handle::sptr> device_list = usb_device_handle::get_device_list(vid_pid_pair_list);
//locate the matching handle in the device list
usb_device_handle::sptr handle;
@@ -243,13 +290,17 @@ b200_impl::b200_impl(const device_addr_t &device_addr)
{
switch (boost::lexical_cast<boost::uint16_t>(mb_eeprom["product"]))
{
+ //0x0001 and 0x7737 are Ettus B200 product Ids.
case 0x0001:
case 0x7737:
+ case B200_PRODUCT_NI_ID:
product_name = "B200";
default_file_name = B200_FPGA_FILE_NAME;
break;
- case 0x7738:
+ //0x0002 and 0x7738 are Ettus B210 product Ids.
case 0x0002:
+ case 0x7738:
+ case B210_PRODUCT_NI_ID:
product_name = "B210";
default_file_name = B210_FPGA_FILE_NAME;
break;
@@ -415,6 +466,7 @@ b200_impl::b200_impl(const device_addr_t &device_addr)
.publish(boost::bind(&b200_impl::get_tick_rate, this))
.subscribe(boost::bind(&b200_impl::update_tick_rate, this, _1));
_tree->create<time_spec_t>(mb_path / "time" / "cmd");
+ _tree->create<bool>(mb_path / "auto_tick_rate").set(false);
////////////////////////////////////////////////////////////////////
// and do the misc mboard sensors
@@ -478,6 +530,19 @@ b200_impl::b200_impl(const device_addr_t &device_addr)
_tree->create<std::vector<std::string> >(mb_path / "clock_source" / "options").set(clock_sources);
////////////////////////////////////////////////////////////////////
+ // front panel gpio
+ ////////////////////////////////////////////////////////////////////
+ _radio_perifs[0].fp_gpio = gpio_core_200::make(_radio_perifs[0].ctrl, TOREG(SR_FP_GPIO), RB32_FP_GPIO);
+ BOOST_FOREACH(const gpio_attr_map_t::value_type attr, gpio_attr_map)
+ {
+ _tree->create<boost::uint32_t>(mb_path / "gpio" / "FP0" / attr.second)
+ .set(0)
+ .subscribe(boost::bind(&b200_impl::set_fp_gpio, this, _radio_perifs[0].fp_gpio, attr.first, _1));
+ }
+ _tree->create<boost::uint32_t>(mb_path / "gpio" / "FP0" / "READBACK")
+ .publish(boost::bind(&b200_impl::get_fp_gpio, this, _radio_perifs[0].fp_gpio));
+
+ ////////////////////////////////////////////////////////////////////
// dboard eeproms but not really
////////////////////////////////////////////////////////////////////
dboard_eeprom_t db_eeprom;
@@ -515,6 +580,11 @@ b200_impl::b200_impl(const device_addr_t &device_addr)
_tree->access<double>(mb_path / "rx_dsps" / str(boost::format("%u") % i)/ "rate/value").set(B200_DEFAULT_RATE);
_tree->access<double>(mb_path / "tx_dsps" / str(boost::format("%u") % i) / "rate/value").set(B200_DEFAULT_RATE);
}
+ // We can automatically choose a master clock rate, but not if the user specifies one
+ _tree->access<bool>(mb_path / "auto_tick_rate").set(not device_addr.has_key("master_clock_rate"));
+ if (not device_addr.has_key("master_clock_rate")) {
+ UHD_MSG(status) << "Setting master clock rate selection to 'automatic'." << std::endl;
+ }
//GPS installed: use external ref, time, and init time spec
if (_gps and _gps->gps_detected())
@@ -535,7 +605,7 @@ b200_impl::b200_impl(const device_addr_t &device_addr)
b200_impl::~b200_impl(void)
{
- UHD_SAFE_CALL
+ UHD_SAFE_CALL
(
_async_task.reset();
)
@@ -578,7 +648,7 @@ void b200_impl::setup_radio(const size_t dspno)
_tree->create<meta_range_t>(rx_dsp_path / "rate" / "range")
.publish(boost::bind(&rx_dsp_core_3000::get_host_rates, perif.ddc));
_tree->create<double>(rx_dsp_path / "rate" / "value")
- .coerce(boost::bind(&rx_dsp_core_3000::set_host_rate, perif.ddc, _1))
+ .coerce(boost::bind(&b200_impl::coerce_rx_samp_rate, this, perif.ddc, dspno, _1))
.subscribe(boost::bind(&b200_impl::update_rx_samp_rate, this, dspno, _1))
.set(0.0); // Can only set this after tick rate is initialized.
_tree->create<double>(rx_dsp_path / "freq" / "value")
@@ -602,7 +672,7 @@ void b200_impl::setup_radio(const size_t dspno)
_tree->create<meta_range_t>(tx_dsp_path / "rate" / "range")
.publish(boost::bind(&tx_dsp_core_3000::get_host_rates, perif.duc));
_tree->create<double>(tx_dsp_path / "rate" / "value")
- .coerce(boost::bind(&tx_dsp_core_3000::set_host_rate, perif.duc, _1))
+ .coerce(boost::bind(&b200_impl::coerce_tx_samp_rate, this, perif.duc, dspno, _1))
.subscribe(boost::bind(&b200_impl::update_tx_samp_rate, this, dspno, _1))
.set(0.0); // Can only set this after tick rate is initialized.
_tree->create<double>(tx_dsp_path / "freq" / "value")
@@ -646,7 +716,7 @@ void b200_impl::setup_radio(const size_t dspno)
_tree->create<bool>(rf_fe_path / "use_lo_offset").set(false);
_tree->create<double>(rf_fe_path / "bandwidth" / "value")
.coerce(boost::bind(&ad9361_ctrl::set_bw_filter, _codec_ctrl, key, _1))
- .set(40e6);
+ .set(56e6);
_tree->create<meta_range_t>(rf_fe_path / "bandwidth" / "range")
.publish(boost::bind(&ad9361_ctrl::get_bw_filter_range, key));
_tree->create<double>(rf_fe_path / "freq" / "value")
@@ -655,8 +725,20 @@ void b200_impl::setup_radio(const size_t dspno)
.set(B200_DEFAULT_FREQ);
_tree->create<meta_range_t>(rf_fe_path / "freq" / "range")
.publish(boost::bind(&ad9361_ctrl::get_rf_freq_range));
+ _tree->create<sensor_value_t>(rf_fe_path / "sensors" / "temp")
+ .publish(boost::bind(&ad9361_ctrl::get_temperature, _codec_ctrl));
//setup RX related stuff
+ if(direction)
+ {
+ _tree->create<bool>(rf_fe_path / "dc_offset" / "enable" )
+ .subscribe(boost::bind(&ad9361_ctrl::set_dc_offset_auto, _codec_ctrl, key, _1)).set(true);
+
+ _tree->create<bool>(rf_fe_path / "iq_balance" / "enable" )
+ .subscribe(boost::bind(&ad9361_ctrl::set_iq_balance_auto, _codec_ctrl, key, _1)).set(true);
+ }
+
+ //setup antenna stuff
if (key[0] == 'R')
{
static const std::vector<std::string> ants = boost::assign::list_of("TX/RX")("RX2");
@@ -666,6 +748,16 @@ void b200_impl::setup_radio(const size_t dspno)
.set("RX2");
_tree->create<sensor_value_t>(rf_fe_path / "sensors" / "rssi")
.publish(boost::bind(&ad9361_ctrl::get_rssi, _codec_ctrl, key));
+
+ //AGC setup
+ const std::list<std::string> mode_strings = boost::assign::list_of("slow")("fast");
+ _tree->create<bool>(rf_fe_path / "gain" / "agc" / "enable")
+ .subscribe(boost::bind((&ad9361_ctrl::set_agc), _codec_ctrl, key, _1))
+ .set(false);
+ _tree->create<std::string>(rf_fe_path / "gain" / "agc" / "mode" / "value")
+ .subscribe(boost::bind((&ad9361_ctrl::set_agc_mode), _codec_ctrl, key, _1)).set(mode_strings.front());
+ _tree->create<std::list<std::string> >(rf_fe_path / "gain" / "agc" / "mode" / "options")
+ .set(mode_strings);
}
if (key[0] == 'T')
{
@@ -722,7 +814,7 @@ 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*/)
+void b200_impl::enforce_tick_rate_limits(size_t chan_count, double tick_rate, const std::string &direction /*= ""*/)
{
const size_t max_chans = 2;
if (chan_count > max_chans)
@@ -730,7 +822,7 @@ void b200_impl::enforce_tick_rate_limits(size_t chan_count, double tick_rate, co
throw uhd::value_error(boost::str(
boost::format("cannot not setup %d %s channels (maximum is %d)")
% chan_count
- % (direction ? direction : "data")
+ % (direction.empty() ? "data" : direction)
% max_chans
));
}
@@ -744,20 +836,26 @@ void b200_impl::enforce_tick_rate_limits(size_t chan_count, double tick_rate, co
% (tick_rate/1e6)
% (max_tick_rate/1e6)
% chan_count
- % (direction ? direction : "data")
+ % (direction.empty() ? "data" : direction)
));
}
}
}
-double b200_impl::set_tick_rate(const double rate)
+double b200_impl::set_tick_rate(const double new_tick_rate)
{
- UHD_MSG(status) << (boost::format("Asking for clock rate %.6f MHz\n") % (rate/1e6));
-
- check_tick_rate_with_current_streamers(rate); // Defined in b200_io_impl.cpp
+ UHD_MSG(status) << (boost::format("Asking for clock rate %.6f MHz... ") % (new_tick_rate/1e6)) << std::flush;
+ check_tick_rate_with_current_streamers(new_tick_rate); // Defined in b200_io_impl.cpp
+
+ // Make sure the clock rate is actually changed before doing
+ // the full Monty of setting regs and loopback tests etc.
+ if (std::abs(new_tick_rate - _tick_rate) < 1.0) {
+ UHD_MSG(status) << "OK" << std::endl;
+ return _tick_rate;
+ }
- _tick_rate = _codec_ctrl->set_clock_rate(rate);
- UHD_MSG(status) << (boost::format("Actually got clock rate %.6f MHz\n") % (_tick_rate/1e6));
+ _tick_rate = _codec_ctrl->set_clock_rate(new_tick_rate);
+ UHD_MSG(status) << std::endl << (boost::format("Actually got clock rate %.6f MHz.") % (_tick_rate/1e6)) << std::endl;
//reset after clock rate change
this->reset_codec_dcm();
@@ -818,6 +916,26 @@ void b200_impl::set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &mb_eeprom)
}
+boost::uint32_t b200_impl::get_fp_gpio(gpio_core_200::sptr gpio)
+{
+ return boost::uint32_t(gpio->read_gpio(dboard_iface::UNIT_RX));
+}
+
+void b200_impl::set_fp_gpio(gpio_core_200::sptr gpio, const gpio_attr_t attr, const boost::uint32_t value)
+{
+ switch (attr)
+ {
+ case GPIO_CTRL: return gpio->set_pin_ctrl(dboard_iface::UNIT_RX, value);
+ case GPIO_DDR: return gpio->set_gpio_ddr(dboard_iface::UNIT_RX, value);
+ case GPIO_OUT: return gpio->set_gpio_out(dboard_iface::UNIT_RX, value);
+ case GPIO_ATR_0X: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, value);
+ case GPIO_ATR_RX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, value);
+ case GPIO_ATR_TX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, value);
+ case GPIO_ATR_XX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, value);
+ default: UHD_THROW_INVALID_CODE_PATH();
+ }
+}
+
/***********************************************************************
* Reference time and clock
**********************************************************************/
@@ -1004,6 +1122,6 @@ sensor_value_t b200_impl::get_ref_locked(void)
sensor_value_t b200_impl::get_fe_pll_locked(const bool is_tx)
{
const boost::uint32_t st = _local_ctrl->peek32(RB32_CORE_PLL);
- const bool locked = is_tx ? st & 0x1 : st & 0x2;
+ const bool locked = is_tx ? bool(st & 0x1) : bool(st & 0x2);
return sensor_value_t("LO", locked, "locked", "unlocked");
}
diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp
index 396819f9a..cff767b4b 100644
--- a/host/lib/usrp/b200/b200_impl.hpp
+++ b/host/lib/usrp/b200/b200_impl.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2012-2013 Ettus Research LLC
+// Copyright 2012-2015 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
@@ -98,7 +98,13 @@ 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);
+
+ //! Check that the combination of stream args and tick rate are valid.
+ //
+ // Basically figures out the arguments for enforce_tick_rate_limits()
+ // and calls said method. If arguments are invalid, throws a
+ // uhd::value_error.
+ void check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const std::string &direction = "");
private:
//controllers
@@ -150,6 +156,7 @@ private:
{
radio_ctrl_core_3000::sptr ctrl;
gpio_core_200_32wo::sptr atr;
+ gpio_core_200::sptr fp_gpio;
time_core_3000::sptr time64;
rx_vita_core_3000::sptr framer;
rx_dsp_core_3000::sptr ddc;
@@ -188,14 +195,63 @@ private:
void update_enables(void);
void update_atrs(void);
+ boost::uint32_t get_fp_gpio(gpio_core_200::sptr);
+ void set_fp_gpio(gpio_core_200::sptr, const gpio_attr_t, const boost::uint32_t);
+
double _tick_rate;
double get_tick_rate(void){return _tick_rate;}
double set_tick_rate(const double rate);
+
+ /*! \brief Choose a tick rate (master clock rate) that works well for the given sampling rate.
+ *
+ * This function will try and choose a master clock rate automatically.
+ * See the function definition for details on the algorithm.
+ *
+ * The chosen tick rate is the largest multiple of two that is smaler
+ * than the max tick rate.
+ * The base rate is either given explicitly, or is the lcm() of the tx
+ * and rx sampling rates. In that case, it reads the rates directly
+ * from the property tree. It also tries to guess the number of channels
+ * (for the max possible tick rate) by checking the available streamers.
+ * This value, too, can explicitly be given.
+ *
+ * \param rate If this is given, it will be used as a minimum rate, or
+ * argument to lcm().
+ * \param tree_dsp_path The sampling rate from this property tree path
+ * will be ignored.
+ * \param num_chans If given, specifies the number of channels.
+ */
+ void set_auto_tick_rate(
+ const double rate=0,
+ const uhd::fs_path &tree_dsp_path="",
+ size_t num_chans=0
+ );
+
void update_tick_rate(const double);
- void enforce_tick_rate_limits(size_t chan_count, double tick_rate, const char* direction = NULL);
+
+ /*! Check if \p tick_rate works with \p chan_count channels.
+ *
+ * Throws a uhd::value_error if not.
+ */
+ void enforce_tick_rate_limits(size_t chan_count, double tick_rate, const std::string &direction = "");
void check_tick_rate_with_current_streamers(double rate);
+ /*! Return the max number of channels on active rx_streamer or tx_streamer objects associated with this device.
+ *
+ * \param direction Set to "TX" to only check tx_streamers, "RX" to only check
+ * rx_streamers. Any other value will check if \e any active
+ * streamers are available.
+ * \return Return the number of tx streamers (direction=="TX"), the number of rx
+ * streamers (direction=="RX") or the total number of streamers.
+ */
+ size_t max_chan_count(const std::string &direction="");
+
+ //! Coercer, attached to the "rate/value" property on the rx dsps.
+ double coerce_rx_samp_rate(rx_dsp_core_3000::sptr, size_t, const double);
void update_rx_samp_rate(const size_t, const double);
+
+ //! Coercer, attached to the "rate/value" property on the tx dsps.
+ double coerce_tx_samp_rate(tx_dsp_core_3000::sptr, size_t, const double);
void update_tx_samp_rate(const size_t, const double);
};
diff --git a/host/lib/usrp/b200/b200_io_impl.cpp b/host/lib/usrp/b200/b200_io_impl.cpp
index 262c95f0d..60b925517 100644
--- a/host/lib/usrp/b200/b200_io_impl.cpp
+++ b/host/lib/usrp/b200/b200_io_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2012-2013 Ettus Research LLC
+// Copyright 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,8 +21,10 @@
#include "../../transport/super_recv_packet_handler.hpp"
#include "../../transport/super_send_packet_handler.hpp"
#include "async_packet_handler.hpp"
+#include <uhd/utils/math.hpp>
#include <boost/bind.hpp>
#include <boost/make_shared.hpp>
+#include <boost/math/common_factor.hpp>
#include <set>
using namespace uhd;
@@ -34,30 +36,32 @@ using namespace uhd::transport;
**********************************************************************/
void b200_impl::check_tick_rate_with_current_streamers(double rate)
{
- size_t max_tx_chan_count = 0, max_rx_chan_count = 0;
+ // Defined in b200_impl.cpp
+ enforce_tick_rate_limits(max_chan_count("RX"), rate, "RX");
+ enforce_tick_rate_limits(max_chan_count("TX"), rate, "TX");
+}
+
+// direction can either be "TX", "RX", or empty (default)
+size_t b200_impl::max_chan_count(const std::string &direction /* = "" */)
+{
+ size_t max_count = 0;
BOOST_FOREACH(radio_perifs_t &perif, _radio_perifs)
{
- {
+ if ((direction == "RX" or direction.empty()) and not perif.rx_streamer.expired()) {
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());
+ max_count = std::max(max_count, rx_streamer->get_num_channels());
}
-
- {
+ if ((direction == "TX" or direction.empty()) and not perif.tx_streamer.expired()) {
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());
+ max_count = std::max(max_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");
+ return max_count;
}
-void b200_impl::check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const char* direction /*= NULL*/)
+void b200_impl::check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const std::string &direction /*= ""*/)
{
std::set<size_t> chans_set;
for (size_t stream_i = 0; stream_i < args.channels.size(); stream_i++)
@@ -69,26 +73,120 @@ void b200_impl::check_streamer_args(const uhd::stream_args_t &args, double tick_
enforce_tick_rate_limits(chans_set.size(), tick_rate, direction); // Defined in b200_impl.cpp
}
-void b200_impl::update_tick_rate(const double rate)
+void b200_impl::set_auto_tick_rate(
+ const double rate,
+ const fs_path &tree_dsp_path,
+ size_t num_chans
+) {
+ if (num_chans == 0) { // Divine them
+ num_chans = std::max(size_t(1), max_chan_count());
+ }
+
+ // See also the doxygen documentation for these steps in b200_impl.hpp
+ // Step 1: Obtain LCM and max rate from all relevant dsps
+ boost::uint32_t lcm_rate = (rate == 0) ? 1 : static_cast<boost::uint32_t>(floor(rate + 0.5));
+ for (int i = 0; i < 2; i++) { // Loop through rx and tx
+ std::string dir = (i == 0) ? "tx" : "rx";
+ // We have no way of knowing which DSPs are used, so we check them all.
+ BOOST_FOREACH(const std::string &dsp_no, _tree->list(str(boost::format("/mboards/0/%s_dsps") % dir))) {
+ fs_path dsp_path = str(boost::format("/mboards/0/%s_dsps/%s") % dir % dsp_no);
+ if (dsp_path == tree_dsp_path) {
+ continue;
+ }
+ double this_dsp_rate = _tree->access<double>(dsp_path / "rate/value").get();
+ // If this_dsp_rate == B200_DEFAULT_RATE, we assume the user did not actually set
+ // the sampling rate. If the user *did* set the rate to
+ // B200_DEFAULT_RATE on all DSPs, then this will still work (see below).
+ // If the user set one DSP to B200_DEFAULT_RATE and the other to
+ // a different rate, this also works if the rates are integer multiples
+ // of one another. Only for certain configurations of B200_DEFAULT_RATE
+ // and another rate that is not an integer multiple, this will be problematic.
+ // Since this case is less common than the case where a rate is left unset,
+ // we don't handle that but rather explain that corner case in the documentation.
+ if (this_dsp_rate == B200_DEFAULT_RATE) {
+ continue;
+ }
+ lcm_rate = boost::math::lcm<boost::uint32_t>(
+ lcm_rate,
+ static_cast<boost::uint32_t>(floor(this_dsp_rate + 0.5))
+ );
+ }
+ }
+ if (lcm_rate == 1) {
+ lcm_rate = static_cast<boost::uint32_t>(B200_DEFAULT_RATE);
+ }
+
+ // Step 2: Determine whether if we can use lcm_rate (preferred),
+ // or have to give up because too large:
+ const double max_tick_rate =
+ ((num_chans <= 1) ? ad9361_device_t::AD9361_RECOMMENDED_MAX_CLOCK_RATE : ad9361_device_t::AD9361_MAX_CLOCK_RATE/2);
+ double base_rate = static_cast<double>(lcm_rate);
+ if (base_rate > max_tick_rate) {
+ UHD_MSG(warning)
+ << "Cannot automatically determine an appropriate tick rate for these sampling rates." << std::endl
+ << "Consider using different sampling rates, or manually specify a suitable master clock rate." << std::endl;
+ return; // Let the others handle this
+ }
+
+ // Step 3: Choose the new rate
+ // Rules for choosing the tick rate:
+ // Choose a rate that is a power of 2 larger than the sampling rate,
+ // but at least 4. Cannot exceed the max tick rate, of course, but must
+ // be larger than the minimum tick rate.
+ // An equation that does all that is:
+ //
+ // f_auto = r * 2^floor(log2(f_max/r))
+ //
+ // where r is the base rate and f_max is the maximum tick rate. The case
+ // where floor() yields 1 must be caught.
+ const double min_tick_rate = _codec_ctrl->get_clock_rate_range().start();
+ // We use shifts here instead of 2^x because exp2() is not available in all compilers,
+ // also this guarantees no rounding issues. The type cast to int32_t serves as floor():
+ boost::int32_t multiplier = (1 << boost::int32_t(uhd::math::log2(max_tick_rate / base_rate)));
+ if (multiplier == 2 and base_rate >= min_tick_rate) {
+ // Don't bother (see above)
+ multiplier = 1;
+ }
+ double new_rate = base_rate * multiplier;
+ UHD_ASSERT_THROW(new_rate >= min_tick_rate);
+ UHD_ASSERT_THROW(new_rate <= max_tick_rate);
+
+ if (_tree->access<double>("/mboards/0/tick_rate").get() != new_rate) {
+ _tree->access<double>("/mboards/0/tick_rate").set(new_rate);
+ }
+}
+
+void b200_impl::update_tick_rate(const double new_tick_rate)
{
- check_tick_rate_with_current_streamers(rate);
+ check_tick_rate_with_current_streamers(new_tick_rate);
BOOST_FOREACH(radio_perifs_t &perif, _radio_perifs)
{
boost::shared_ptr<sph::recv_packet_streamer> my_streamer =
boost::dynamic_pointer_cast<sph::recv_packet_streamer>(perif.rx_streamer.lock());
- if (my_streamer) my_streamer->set_tick_rate(rate);
- perif.framer->set_tick_rate(_tick_rate);
+ if (my_streamer) my_streamer->set_tick_rate(new_tick_rate);
+ perif.framer->set_tick_rate(new_tick_rate);
}
BOOST_FOREACH(radio_perifs_t &perif, _radio_perifs)
{
boost::shared_ptr<sph::send_packet_streamer> my_streamer =
boost::dynamic_pointer_cast<sph::send_packet_streamer>(perif.tx_streamer.lock());
- if (my_streamer) my_streamer->set_tick_rate(rate);
- perif.deframer->set_tick_rate(_tick_rate);
+ if (my_streamer) my_streamer->set_tick_rate(new_tick_rate);
+ perif.deframer->set_tick_rate(new_tick_rate);
}
}
+
+double b200_impl::coerce_rx_samp_rate(rx_dsp_core_3000::sptr ddc, size_t dspno, const double rx_rate)
+{
+ // Have to set tick rate first, or the ddc will change the requested rate based on default tick rate
+ if (_tree->access<bool>("/mboards/0/auto_tick_rate").get()) {
+ const std::string dsp_path = (boost::format("/mboards/0/rx_dsps/%s") % dspno).str();
+ set_auto_tick_rate(rx_rate, dsp_path);
+ }
+ return ddc->set_host_rate(rx_rate);
+}
+
void b200_impl::update_rx_samp_rate(const size_t dspno, const double rate)
{
boost::shared_ptr<sph::recv_packet_streamer> my_streamer =
@@ -99,6 +197,16 @@ void b200_impl::update_rx_samp_rate(const size_t dspno, const double rate)
my_streamer->set_scale_factor(adj);
}
+double b200_impl::coerce_tx_samp_rate(tx_dsp_core_3000::sptr duc, size_t dspno, const double tx_rate)
+{
+ // Have to set tick rate first, or the duc will change the requested rate based on default tick rate
+ if (_tree->access<bool>("/mboards/0/auto_tick_rate").get()) {
+ const std::string dsp_path = (boost::format("/mboards/0/tx_dsps/%s") % dspno).str();
+ set_auto_tick_rate(tx_rate, dsp_path);
+ }
+ return duc->set_host_rate(tx_rate);
+}
+
void b200_impl::update_tx_samp_rate(const size_t dspno, const double rate)
{
boost::shared_ptr<sph::send_packet_streamer> my_streamer =
@@ -264,6 +372,9 @@ 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;
+ if (_tree->access<bool>("/mboards/0/auto_tick_rate").get()) {
+ set_auto_tick_rate(0, "", args.channels.size());
+ }
check_streamer_args(args, this->get_tick_rate(), "RX");
boost::shared_ptr<sph::recv_packet_streamer> my_streamer;
@@ -371,7 +482,10 @@ 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");
+ if (_tree->access<bool>("/mboards/0/auto_tick_rate").get()) {
+ set_auto_tick_rate(0, "", args.channels.size());
+ }
+ check_streamer_args(args, this->get_tick_rate(), "RX");
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/b200/b200_regs.hpp b/host/lib/usrp/b200/b200_regs.hpp
index 900651f94..8f2dd03f3 100644
--- a/host/lib/usrp/b200/b200_regs.hpp
+++ b/host/lib/usrp/b200/b200_regs.hpp
@@ -46,11 +46,13 @@ localparam SR_TX_DSP = 184;
localparam SR_TIME = 128;
localparam SR_RX_FMT = 136;
localparam SR_TX_FMT = 138;
+localparam SR_FP_GPIO = 200;
localparam RB32_TEST = 0;
localparam RB64_TIME_NOW = 8;
localparam RB64_TIME_PPS = 16;
localparam RB64_CODEC_READBACK = 24;
+localparam RB32_FP_GPIO = 32;
//pll constants
static const int AD9361_SLAVENO = (1 << 0);
diff --git a/host/lib/usrp/common/ad9361_ctrl.cpp b/host/lib/usrp/common/ad9361_ctrl.cpp
index 85510530d..a0a5fa663 100644
--- a/host/lib/usrp/common/ad9361_ctrl.cpp
+++ b/host/lib/usrp/common/ad9361_ctrl.cpp
@@ -16,7 +16,6 @@
//
#include "ad9361_ctrl.hpp"
-#include <uhd/exception.hpp>
#include <uhd/types/ranges.hpp>
#include <uhd/utils/msg.hpp>
#include <uhd/types/serial.hpp>
@@ -108,6 +107,27 @@ public:
return _device.set_gain(direction, chain, value);
}
+ void set_agc(const std::string &which, bool enable)
+ {
+ boost::lock_guard<boost::mutex> lock(_mutex);
+
+ ad9361_device_t::chain_t chain =_get_chain_from_antenna(which);
+ _device.set_agc(chain, enable);
+ }
+
+ void set_agc_mode(const std::string &which, const std::string &mode)
+ {
+ boost::lock_guard<boost::mutex> lock(_mutex);
+ ad9361_device_t::chain_t chain =_get_chain_from_antenna(which);
+ if(mode == "slow") {
+ _device.set_agc_mode(chain, ad9361_device_t::GAIN_MODE_SLOW_AGC);
+ } else if (mode == "fast"){
+ _device.set_agc_mode(chain, ad9361_device_t::GAIN_MODE_FAST_AGC);
+ } else {
+ throw uhd::runtime_error("ad9361_ctrl got an invalid AGC option.");
+ }
+ }
+
//! set a new clock rate, return the exact value
double set_clock_rate(const double rate)
{
@@ -172,6 +192,28 @@ public:
return sensor_value_t("RSSI", _device.get_rssi(chain), "dB");
}
+ //! read the internal temp sensor. Average over 3 results
+ sensor_value_t get_temperature()
+ {
+ return sensor_value_t("temp", _device.get_average_temperature(), "C");
+ }
+
+ void set_dc_offset_auto(const std::string &which, const bool on)
+ {
+ boost::lock_guard<boost::mutex> lock(_mutex);
+
+ ad9361_device_t::direction_t direction = _get_direction_from_antenna(which);
+ _device.set_dc_offset_auto(direction,on);
+ }
+
+ void set_iq_balance_auto(const std::string &which, const bool on)
+ {
+ boost::lock_guard<boost::mutex> lock(_mutex);
+
+ ad9361_device_t::direction_t direction = _get_direction_from_antenna(which);
+ _device.set_iq_balance_auto(direction,on);
+ }
+
private:
static ad9361_device_t::direction_t _get_direction_from_antenna(const std::string& antenna)
{
diff --git a/host/lib/usrp/common/ad9361_ctrl.hpp b/host/lib/usrp/common/ad9361_ctrl.hpp
index c5718302f..0dd1b08d9 100644
--- a/host/lib/usrp/common/ad9361_ctrl.hpp
+++ b/host/lib/usrp/common/ad9361_ctrl.hpp
@@ -22,9 +22,11 @@
#include <uhd/types/ranges.hpp>
#include <uhd/types/serial.hpp>
#include <uhd/types/sensors.hpp>
+#include <uhd/exception.hpp>
#include <boost/shared_ptr.hpp>
#include <ad9361_device.h>
#include <string>
+#include <complex>
namespace uhd { namespace usrp {
@@ -86,6 +88,12 @@ public:
//! set the gain for a particular gain element
virtual double set_gain(const std::string &which, const double value) = 0;
+ //! Enable or disable the AGC module
+ virtual void set_agc(const std::string &which, bool enable) = 0;
+
+ //! configure the AGC module to slow or fast mode
+ virtual void set_agc_mode(const std::string &which, const std::string &mode) = 0;
+
//! set a new clock rate, return the exact value
virtual double set_clock_rate(const double rate) = 0;
@@ -95,11 +103,34 @@ public:
//! tune the given frontend, return the exact value
virtual double tune(const std::string &which, const double value) = 0;
- //! turn on/off data port loopback
+ //! set the DC offset for I and Q manually
+ void set_dc_offset(const std::string &, const std::complex<double>)
+ {
+ //This feature should not be used according to Analog Devices
+ throw uhd::runtime_error("ad9361_ctrl::set_dc_offset this feature is not supported on this device.");
+ }
+
+ //! enable or disable the BB/RF DC tracking feature
+ virtual void set_dc_offset_auto(const std::string &which, const bool on) = 0;
+
+ //! set the IQ correction value manually
+ void set_iq_balance(const std::string &, const std::complex<double>)
+ {
+ //This feature should not be used according to Analog Devices
+ throw uhd::runtime_error("ad9361_ctrl::set_iq_balance this feature is not supported on this device.");
+ }
+
+ //! enable or disable the quadrature calibration
+ virtual void set_iq_balance_auto(const std::string &which, const bool on) = 0;
+
+ //! turn on/off Catalina's data port loopback
virtual void data_port_loopback(const bool on) = 0;
//! read internal RSSI sensor
virtual sensor_value_t get_rssi(const std::string &which) = 0;
+
+ //! read the internal temp sensor
+ virtual sensor_value_t get_temperature() = 0;
};
}}
diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp
index d3e53c80f..92ad0ee3f 100644
--- a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp
+++ b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp
@@ -11,6 +11,7 @@
#include <cmath>
#include <uhd/exception.hpp>
#include <uhd/utils/log.hpp>
+#include <uhd/utils/msg.hpp>
#include <boost/cstdint.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/thread.hpp>
@@ -79,6 +80,7 @@ int get_num_taps(int max_num_taps) {
const double ad9361_device_t::AD9361_MAX_GAIN = 89.75;
const double ad9361_device_t::AD9361_MAX_CLOCK_RATE = 61.44e6;
const double ad9361_device_t::AD9361_RECOMMENDED_MAX_CLOCK_RATE = 56e6;
+const double ad9361_device_t::AD9361_CAL_VALID_WINDOW = 100e6;
/* Program either the RX or TX FIR filter.
*
@@ -650,11 +652,12 @@ void ad9361_device_t::_setup_adc()
}
/* Calibrate the baseband DC offset.
- *
- * Note that this function is called from within the TX quadrature
- * calibration function! */
+ * Disables tracking
+ */
void ad9361_device_t::_calibrate_baseband_dc_offset()
{
+ _io_iface->poke8(0x18b, 0x83); //Reset RF DC tracking flag
+
_io_iface->poke8(0x193, 0x3f); // Calibration settings
_io_iface->poke8(0x190, 0x0f); // Set tracking coefficient
//write_ad9361_reg(device, 0x190, /*0x0f*//*0xDF*/0x80*1 | 0x40*1 | (16+8/*+4*/)); // Set tracking coefficient: don't *4 counter, do decim /4, increased gain shift
@@ -674,9 +677,8 @@ void ad9361_device_t::_calibrate_baseband_dc_offset()
}
/* Calibrate the RF DC offset.
- *
- * Note that this function is called from within the TX quadrature
- * calibration function. */
+ * Disables tracking
+ */
void ad9361_device_t::_calibrate_rf_dc_offset()
{
/* Some settings are frequency-dependent. */
@@ -691,7 +693,7 @@ void ad9361_device_t::_calibrate_rf_dc_offset()
}
_io_iface->poke8(0x185, 0x20); // RF DC Offset wait count
- _io_iface->poke8(0x18b, 0x83);
+ _io_iface->poke8(0x18b, 0x83); // Disable tracking
_io_iface->poke8(0x189, 0x30);
/* Run the calibration! */
@@ -707,6 +709,16 @@ void ad9361_device_t::_calibrate_rf_dc_offset()
}
}
+void ad9361_device_t::_configure_bb_rf_dc_tracking(const bool on)
+{
+ if(on)
+ {
+ _io_iface->poke8(0x18b, 0xad); // Enable BB and RF DC tracking
+ } else {
+ _io_iface->poke8(0x18b, 0x83); // Disable BB and RF DC tracking
+ }
+}
+
/* Start the RX quadrature calibration.
*
* Note that we are using AD9361's 'tracking' feature for RX quadrature
@@ -719,16 +731,20 @@ void ad9361_device_t::_calibrate_rx_quadrature()
_io_iface->poke8(0x16e, 0x25); // RX Gain index to use for cal
_io_iface->poke8(0x16a, 0x75); // Set Kexp phase
_io_iface->poke8(0x16b, 0x15); // Set Kexp amplitude
- _io_iface->poke8(0x169, 0xcf); // Continuous tracking mode
- _io_iface->poke8(0x18b, 0xad);
+
+ if(_use_iq_balance_correction)
+ {
+ _io_iface->poke8(0x169, 0xcf); // Continuous tracking mode. Gets disabled in _tx_quadrature_cal_routine!
+ }
}
-/* TX quadtrature calibration routine.
+/* TX quadrature calibration routine.
*
* The TX quadrature needs to be done twice, once for each TX chain, with
* only one register change in between. Thus, this function enacts the
* calibrations, and it is called from calibrate_tx_quadrature. */
void ad9361_device_t::_tx_quadrature_cal_routine() {
+
/* This is a weird process, but here is how it works:
* 1) Read the calibrated NCO frequency bits out of 0A3.
* 2) Write the two bits to the RX NCO freq part of 0A0.
@@ -773,12 +789,6 @@ void ad9361_device_t::_tx_quadrature_cal_routine() {
_io_iface->poke8(0x0a4, 0xf0); // Cal setting conut
_io_iface->poke8(0x0ae, 0x00); // Cal LPF gain index (split mode)
- /* First, calibrate the baseband DC offset. */
- _calibrate_baseband_dc_offset();
-
- /* Second, calibrate the RF DC offset. */
- _calibrate_rf_dc_offset();
-
/* Now, calibrate the TX quadrature! */
size_t count = 0;
_io_iface->poke8(0x016, 0x10);
@@ -793,9 +803,7 @@ void ad9361_device_t::_tx_quadrature_cal_routine() {
}
/* Run the TX quadrature calibration.
- *
- * Note that from within this function we are also triggering the baseband
- * and RF DC calibrations. */
+ */
void ad9361_device_t::_calibrate_tx_quadrature()
{
/* Make sure we are, in fact, in the ALERT state. If not, something is
@@ -879,7 +887,7 @@ void ad9361_device_t::_program_mixer_gm_subtable()
void ad9361_device_t::_program_gain_table() {
/* Figure out which gain table we should be using for our current
* frequency band. */
- boost::uint8_t (*gain_table)[5] = NULL;
+ boost::uint8_t (*gain_table)[3] = NULL;
boost::uint8_t new_gain_table;
if (_rx_freq < 1300e6) {
gain_table = gain_table_sub_1300mhz;
@@ -910,9 +918,9 @@ void ad9361_device_t::_program_gain_table() {
boost::uint8_t index = 0;
for (; index < 77; index++) {
_io_iface->poke8(0x130, index);
- _io_iface->poke8(0x131, gain_table[index][1]);
- _io_iface->poke8(0x132, gain_table[index][2]);
- _io_iface->poke8(0x133, gain_table[index][3]);
+ _io_iface->poke8(0x131, gain_table[index][0]);
+ _io_iface->poke8(0x132, gain_table[index][1]);
+ _io_iface->poke8(0x133, gain_table[index][2]);
_io_iface->poke8(0x137, 0x1E);
_io_iface->poke8(0x134, 0x00);
_io_iface->poke8(0x134, 0x00);
@@ -938,28 +946,58 @@ void ad9361_device_t::_program_gain_table() {
/* Setup gain control registers.
*
- * This really only needs to be done once, at initialization. */
-void ad9361_device_t::_setup_gain_control()
+ * This really only needs to be done once, at initialization.
+ * If AGC is used the mode select bits (Reg 0x0FA) must be written manually */
+void ad9361_device_t::_setup_gain_control(bool agc)
{
- _io_iface->poke8(0x0FA, 0xE0); // Gain Control Mode Select
- _io_iface->poke8(0x0FB, 0x08); // Table, Digital Gain, Man Gain Ctrl
- _io_iface->poke8(0x0FC, 0x23); // Incr Step Size, ADC Overrange Size
- _io_iface->poke8(0x0FD, 0x4C); // Max Full/LMT Gain Table Index
- _io_iface->poke8(0x0FE, 0x44); // Decr Step Size, Peak Overload Time
- _io_iface->poke8(0x100, 0x6F); // Max Digital Gain
- _io_iface->poke8(0x104, 0x2F); // ADC Small Overload Threshold
- _io_iface->poke8(0x105, 0x3A); // ADC Large Overload Threshold
- _io_iface->poke8(0x107, 0x31); // Large LMT Overload Threshold
- _io_iface->poke8(0x108, 0x39); // Small LMT Overload Threshold
- _io_iface->poke8(0x109, 0x23); // Rx1 Full/LMT Gain Index
- _io_iface->poke8(0x10A, 0x58); // Rx1 LPF Gain Index
- _io_iface->poke8(0x10B, 0x00); // Rx1 Digital Gain Index
- _io_iface->poke8(0x10C, 0x23); // Rx2 Full/LMT Gain Index
- _io_iface->poke8(0x10D, 0x18); // Rx2 LPF Gain Index
- _io_iface->poke8(0x10E, 0x00); // Rx2 Digital Gain Index
- _io_iface->poke8(0x114, 0x30); // Low Power Threshold
- _io_iface->poke8(0x11A, 0x27); // Initial LMT Gain Limit
- _io_iface->poke8(0x081, 0x00); // Tx Symbol Gain Control
+ /* The AGC mode configuration should be good for all cases.
+ * However, non AGC configuration still used for backward compatibility. */
+ if (agc) {
+ /*mode select bits must be written before hand!*/
+ _io_iface->poke8(0x0FB, 0x08); // Table, Digital Gain, Man Gain Ctrl
+ _io_iface->poke8(0x0FC, 0x23); // Incr Step Size, ADC Overrange Size
+ _io_iface->poke8(0x0FD, 0x4C); // Max Full/LMT Gain Table Index
+ _io_iface->poke8(0x0FE, 0x44); // Decr Step Size, Peak Overload Time
+ _io_iface->poke8(0x100, 0x6F); // Max Digital Gain
+ _io_iface->poke8(0x101, 0x0A); // Max Digital Gain
+ _io_iface->poke8(0x103, 0x08); // Max Digital Gain
+ _io_iface->poke8(0x104, 0x2F); // ADC Small Overload Threshold
+ _io_iface->poke8(0x105, 0x3A); // ADC Large Overload Threshold
+ _io_iface->poke8(0x106, 0x22); // Max Digital Gain
+ _io_iface->poke8(0x107, 0x2B); // Large LMT Overload Threshold
+ _io_iface->poke8(0x108, 0x31);
+ _io_iface->poke8(0x111, 0x0A);
+ _io_iface->poke8(0x11A, 0x1C);
+ _io_iface->poke8(0x120, 0x0C);
+ _io_iface->poke8(0x121, 0x44);
+ _io_iface->poke8(0x122, 0x44);
+ _io_iface->poke8(0x123, 0x11);
+ _io_iface->poke8(0x124, 0xF5);
+ _io_iface->poke8(0x125, 0x3B);
+ _io_iface->poke8(0x128, 0x03);
+ _io_iface->poke8(0x129, 0x56);
+ _io_iface->poke8(0x12A, 0x22);
+ } else {
+ _io_iface->poke8(0x0FA, 0xE0); // Gain Control Mode Select
+ _io_iface->poke8(0x0FB, 0x08); // Table, Digital Gain, Man Gain Ctrl
+ _io_iface->poke8(0x0FC, 0x23); // Incr Step Size, ADC Overrange Size
+ _io_iface->poke8(0x0FD, 0x4C); // Max Full/LMT Gain Table Index
+ _io_iface->poke8(0x0FE, 0x44); // Decr Step Size, Peak Overload Time
+ _io_iface->poke8(0x100, 0x6F); // Max Digital Gain
+ _io_iface->poke8(0x104, 0x2F); // ADC Small Overload Threshold
+ _io_iface->poke8(0x105, 0x3A); // ADC Large Overload Threshold
+ _io_iface->poke8(0x107, 0x31); // Large LMT Overload Threshold
+ _io_iface->poke8(0x108, 0x39); // Small LMT Overload Threshold
+ _io_iface->poke8(0x109, 0x23); // Rx1 Full/LMT Gain Index
+ _io_iface->poke8(0x10A, 0x58); // Rx1 LPF Gain Index
+ _io_iface->poke8(0x10B, 0x00); // Rx1 Digital Gain Index
+ _io_iface->poke8(0x10C, 0x23); // Rx2 Full/LMT Gain Index
+ _io_iface->poke8(0x10D, 0x18); // Rx2 LPF Gain Index
+ _io_iface->poke8(0x10E, 0x00); // Rx2 Digital Gain Index
+ _io_iface->poke8(0x114, 0x30); // Low Power Threshold
+ _io_iface->poke8(0x11A, 0x27); // Initial LMT Gain Limit
+ _io_iface->poke8(0x081, 0x00); // Tx Symbol Gain Control
+ }
}
/* Setup the RX or TX synthesizers.
@@ -1049,7 +1087,7 @@ double ad9361_device_t::_tune_bbvco(const double rate)
const double vcomin = 672e6;
double vcorate;
int vcodiv;
-
+
/* Iterate over VCO dividers until appropriate divider is found. */
int i = 1;
for (; i <= 6; i++) {
@@ -1256,6 +1294,7 @@ double ad9361_device_t::_setup_rates(const double rate)
int divfactor = 0;
_tfir_factor = 0;
_rfir_factor = 0;
+
if (rate < 0.33e6) {
// RX1 + RX2 enabled, 3, 2, 2, 4
_regs.rxfilt = B8(11101111);
@@ -1306,7 +1345,7 @@ double ad9361_device_t::_setup_rates(const double rate)
divfactor = 16;
_tfir_factor = 2;
_rfir_factor = 2;
- } else if ((rate >= 41e6) && (rate <= 56e6)) {
+ } else if ((rate >= 41e6) && (rate <= 58e6)) {
// RX1 + RX2 enabled, 3, 1, 2, 2
_regs.rxfilt = B8(11100110);
@@ -1316,15 +1355,15 @@ double ad9361_device_t::_setup_rates(const double rate)
divfactor = 12;
_tfir_factor = 2;
_rfir_factor = 2;
- } else if ((rate > 56e6) && (rate <= 61.44e6)) {
- // RX1 + RX2 enabled, 3, 1, 1, 2
- _regs.rxfilt = B8(11100010);
+ } else if ((rate > 58e6) && (rate <= 61.44e6)) {
+ // RX1 + RX2 enabled, 2, 1, 2, 2
+ _regs.rxfilt = B8(11010110);
- // TX1 + TX2 enabled, 3, 1, 1, 1
- _regs.txfilt = B8(11100001);
+ // TX1 + TX2 enabled, 2, 1, 1, 2
+ _regs.txfilt = B8(11010010);
- divfactor = 6;
- _tfir_factor = 1;
+ divfactor = 8;
+ _tfir_factor = 2;
_rfir_factor = 2;
} else {
// should never get in here
@@ -1340,7 +1379,7 @@ double ad9361_device_t::_setup_rates(const double rate)
/* The DAC clock must be <= 336e6, and is either the ADC clock or 1/2 the
* ADC clock.*/
if (adcclk > 336e6) {
- /* Make the DAC clock = ADC/2, and bypass the TXFIR. */
+ /* Make the DAC clock = ADC/2 */
_regs.bbpll = _regs.bbpll | 0x08;
dacclk = adcclk / 2.0;
} else {
@@ -1411,6 +1450,13 @@ void ad9361_device_t::initialize()
_rx2_gain = 0;
_tx1_gain = 0;
_tx2_gain = 0;
+ _use_dc_offset_correction = true;
+ _use_iq_balance_correction = true;
+ _rx1_agc_mode = GAIN_MODE_SLOW_AGC;
+ _rx2_agc_mode = GAIN_MODE_SLOW_AGC;
+ _rx1_agc_enable = false;
+ _rx2_agc_enable = false;
+ _last_calibration_freq = -AD9361_CAL_VALID_WINDOW;
/* Reset the device. */
_io_iface->poke8(0x000, 0x01);
@@ -1500,7 +1546,7 @@ void ad9361_device_t::initialize()
/* Setup AuxADC */
_io_iface->poke8(0x00B, 0x00); // Temp Sensor Setup (Offset)
_io_iface->poke8(0x00C, 0x00); // Temp Sensor Setup (Temp Window)
- _io_iface->poke8(0x00D, 0x03); // Temp Sensor Setup (Periodic Measure)
+ _io_iface->poke8(0x00D, 0x00); // Temp Sensor Setup (Manual Measure)
_io_iface->poke8(0x00F, 0x04); // Temp Sensor Setup (Decimation)
_io_iface->poke8(0x01C, 0x10); // AuxADC Setup (Clock Div)
_io_iface->poke8(0x01D, 0x01); // AuxADC Setup (Decimation/Enable)
@@ -1554,7 +1600,7 @@ void ad9361_device_t::initialize()
_program_mixer_gm_subtable();
_program_gain_table();
- _setup_gain_control();
+ _setup_gain_control(false);
_calibrate_baseband_rx_analog_filter();
_calibrate_baseband_tx_analog_filter();
@@ -1563,8 +1609,11 @@ void ad9361_device_t::initialize()
_setup_adc();
+ _calibrate_baseband_dc_offset();
+ _calibrate_rf_dc_offset();
_calibrate_tx_quadrature();
_calibrate_rx_quadrature();
+ _configure_bb_rf_dc_tracking(_use_dc_offset_correction);
// cals done, set PPORT config
switch (_client_params->get_digital_interface_mode()) {
@@ -1677,7 +1726,7 @@ double ad9361_device_t::set_clock_rate(const double req_rate)
_program_mixer_gm_subtable();
_program_gain_table();
- _setup_gain_control();
+ _setup_gain_control(false);
_reprogram_gains();
_calibrate_baseband_rx_analog_filter();
@@ -1687,8 +1736,11 @@ double ad9361_device_t::set_clock_rate(const double req_rate)
_setup_adc();
+ _calibrate_baseband_dc_offset();
+ _calibrate_rf_dc_offset();
_calibrate_tx_quadrature();
_calibrate_rx_quadrature();
+ _configure_bb_rf_dc_tracking(_use_dc_offset_correction);
// cals done, set PPORT config
switch (_client_params->get_digital_interface_mode()) {
@@ -1840,9 +1892,16 @@ double ad9361_device_t::tune(direction_t direction, const double value)
/* Update the gain settings. */
_reprogram_gains();
- /* Run the calibration algorithms. */
- _calibrate_tx_quadrature();
- _calibrate_rx_quadrature();
+ /* Only run the following calibrations if we are more than 100MHz away
+ * from the previous calibration point. */
+ if (std::abs(_last_calibration_freq - tune_freq) > AD9361_CAL_VALID_WINDOW) {
+ /* Run the calibration algorithms. */
+ _calibrate_rf_dc_offset();
+ _calibrate_tx_quadrature();
+ _calibrate_rx_quadrature();
+ _configure_bb_rf_dc_tracking(_use_dc_offset_correction);
+ _last_calibration_freq = tune_freq;
+ }
/* If we were in the FDD state, return it now. */
if (not_in_alert) {
@@ -1946,4 +2005,197 @@ double ad9361_device_t::get_rssi(chain_t chain)
return rssi;
}
+/*
+ * Returns the reading of the internal temperature sensor.
+ * One point calibration of the sensor was done according to datasheet
+ * leading to the given default constant correction factor.
+ */
+double ad9361_device_t::_get_temperature(const double cal_offset, const double timeout)
+{
+ //set 0x01D[0] to 1 to disable AuxADC GPIO reading
+ boost::uint8_t tmp = 0;
+ tmp = _io_iface->peek8(0x01D);
+ _io_iface->poke8(0x01D, (tmp | 0x01));
+ _io_iface->poke8(0x00B, 0); //set offset to 0
+
+ _io_iface->poke8(0x00C, 0x01); //start reading, clears bit 0x00C[1]
+ boost::posix_time::ptime start_time = boost::posix_time::microsec_clock::local_time();
+ boost::posix_time::time_duration elapsed;
+ //wait for valid data (toggle of bit 1 in 0x00C)
+ while(((_io_iface->peek8(0x00C) >> 1) & 0x01) == 0) {
+ boost::this_thread::sleep(boost::posix_time::microseconds(100));
+ elapsed = boost::posix_time::microsec_clock::local_time() - start_time;
+ if(elapsed.total_milliseconds() > (timeout*1000))
+ {
+ throw uhd::runtime_error("[ad9361_device_t] timeout while reading temperature");
+ }
+ }
+ _io_iface->poke8(0x00C, 0x00); //clear read flag
+
+ boost::uint8_t temp = _io_iface->peek8(0x00E); //read temperature.
+ double tmp_temp = temp/1.140f; //according to ADI driver
+ tmp_temp = tmp_temp + cal_offset; //Constant offset acquired by one point calibration.
+
+ return tmp_temp;
+}
+
+double ad9361_device_t::get_average_temperature(const double cal_offset, const size_t num_samples)
+{
+ double d_temp = 0;
+ for(size_t i = 0; i < num_samples; i++) {
+ double tmp_temp = _get_temperature(cal_offset);
+ d_temp += (tmp_temp/num_samples);
+ }
+ return d_temp;
+}
+
+void ad9361_device_t::set_dc_offset_auto(direction_t direction, const bool on)
+{
+ if(direction == RX)
+ {
+ _use_dc_offset_correction = on;
+ _configure_bb_rf_dc_tracking(_use_dc_offset_correction);
+ if(on)
+ {
+ _io_iface->poke8(0x182, (_io_iface->peek8(0x182) & (~((1 << 7) | (1 << 6) | (1 << 3) | (1 << 2))))); //Clear force bits
+ //Do a single shot DC offset cal before enabling tracking (Not possible if not in ALERT state. Is it necessary?)
+ } else {
+ //clear current config values
+ _io_iface->poke8(0x182, (_io_iface->peek8(0x182) | ((1 << 7) | (1 << 6) | (1 << 3) | (1 << 2)))); //Set input A and input B&C force enable bits
+ _io_iface->poke8(0x174, 0x00);
+ _io_iface->poke8(0x175, 0x00);
+ _io_iface->poke8(0x176, 0x00);
+ _io_iface->poke8(0x177, 0x00);
+ _io_iface->poke8(0x178, 0x00);
+ _io_iface->poke8(0x17D, 0x00);
+ _io_iface->poke8(0x17E, 0x00);
+ _io_iface->poke8(0x17F, 0x00);
+ _io_iface->poke8(0x180, 0x00);
+ _io_iface->poke8(0x181, 0x00);
+ }
+ } else {
+ // DC offset is removed during TX quad cal
+ throw uhd::runtime_error("[ad9361_device_t] [set_iq_balance_auto] INVALID_CODE_PATH");
+ }
+}
+
+void ad9361_device_t::set_iq_balance_auto(direction_t direction, const bool on)
+{
+ if(direction == RX)
+ {
+ _use_iq_balance_correction = on;
+ if(on)
+ {
+ //disable force registers and enable tracking
+ _io_iface->poke8(0x182, (_io_iface->peek8(0x182) & (~ ( (1<<1) | (1<<0) | (1<<5) | (1<<4) ))));
+ _calibrate_rx_quadrature();
+ } else {
+ //disable IQ tracking
+ _io_iface->poke8(0x169, 0xc0);
+ //clear current config values
+ _io_iface->poke8(0x182, (_io_iface->peek8(0x182) | ((1 << 1) | (1 << 0) | (1 << 5) | (1 << 4)))); //Set Rx2 input B&C force enable bit
+ _io_iface->poke8(0x17B, 0x00);
+ _io_iface->poke8(0x17C, 0x00);
+ _io_iface->poke8(0x179, 0x00);
+ _io_iface->poke8(0x17A, 0x00);
+ _io_iface->poke8(0x170, 0x00);
+ _io_iface->poke8(0x171, 0x00);
+ _io_iface->poke8(0x172, 0x00);
+ _io_iface->poke8(0x173, 0x00);
+ }
+ } else {
+ throw uhd::runtime_error("[ad9361_device_t] [set_iq_balance_auto] INVALID_CODE_PATH");
+ }
+}
+
+/* Sets the RX gain mode to be used.
+ * If a transition from an AGC to an non AGC mode occurs (or vice versa)
+ * the gain configuration will be reloaded. */
+void ad9361_device_t::_setup_agc(chain_t chain, gain_mode_t gain_mode)
+{
+ boost::uint8_t gain_mode_reg = 0;
+ boost::uint8_t gain_mode_prev = 0;
+ boost::uint8_t gain_mode_bits_pos = 0;
+
+ gain_mode_reg = _io_iface->peek8(0x0FA);
+ gain_mode_prev = (gain_mode_reg & 0x0F);
+
+ if (chain == CHAIN_1) {
+ gain_mode_bits_pos = 0;
+ } else if (chain == CHAIN_2) {
+ gain_mode_bits_pos = 2;
+ } else
+ {
+ throw uhd::runtime_error("[ad9361_device_t] Wrong value for chain");
+ }
+
+ gain_mode_reg = (gain_mode_reg & (~(0x03<<gain_mode_bits_pos))); //clear mode bits
+ switch (gain_mode) {
+ case GAIN_MODE_MANUAL:
+ //leave bits cleared
+ break;
+ case GAIN_MODE_SLOW_AGC:
+ gain_mode_reg = (gain_mode_reg | (0x02<<gain_mode_bits_pos));
+ break;
+ case GAIN_MODE_FAST_AGC:
+ gain_mode_reg = (gain_mode_reg | (0x01<<gain_mode_bits_pos));
+ break;
+ default:
+ throw uhd::runtime_error("[ad9361_device_t] Gain mode does not exist");
+ }
+ _io_iface->poke8(0x0FA, gain_mode_reg);
+ boost::uint8_t gain_mode_status = _io_iface->peek8(0x0FA);
+ gain_mode_status = (gain_mode_status & 0x0F);
+ /*Check if gain mode configuration needs to be reprogrammed*/
+ if (((gain_mode_prev == 0) && (gain_mode_status != 0)) || ((gain_mode_prev != 0) && (gain_mode_status == 0))) {
+ if (gain_mode_status == 0) {
+ /*load manual mode config*/
+ _setup_gain_control(false);
+ } else {
+ /*load agc mode config*/
+ _setup_gain_control(true);
+ }
+ }
+}
+
+void ad9361_device_t::set_agc(chain_t chain, bool enable)
+{
+ if(chain == CHAIN_1) {
+ _rx1_agc_enable = enable;
+ if(enable) {
+ _setup_agc(chain, _rx1_agc_mode);
+ } else {
+ _setup_agc(chain, GAIN_MODE_MANUAL);
+ }
+ } else if (chain == CHAIN_2){
+ _rx2_agc_enable = enable;
+ if(enable) {
+ _setup_agc(chain, _rx2_agc_mode);
+ } else {
+ _setup_agc(chain, GAIN_MODE_MANUAL);
+ }
+ } else
+ {
+ throw uhd::runtime_error("[ad9361_device_t] Wrong value for chain");
+ }
+}
+
+void ad9361_device_t::set_agc_mode(chain_t chain, gain_mode_t gain_mode)
+{
+ if(chain == CHAIN_1) {
+ _rx1_agc_mode = gain_mode;
+ if(_rx1_agc_enable) {
+ _setup_agc(chain, _rx1_agc_mode);
+ }
+ } else if(chain == CHAIN_2){
+ _rx2_agc_mode = gain_mode;
+ if(_rx2_agc_enable) {
+ _setup_agc(chain, _rx2_agc_mode);
+ }
+ } else
+ {
+ throw uhd::runtime_error("[ad9361_device_t] Wrong value for chain");
+ }
+}
+
}}
diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_device.h b/host/lib/usrp/common/ad9361_driver/ad9361_device.h
index ca83f3037..7c53ff0c4 100644
--- a/host/lib/usrp/common/ad9361_driver/ad9361_device.h
+++ b/host/lib/usrp/common/ad9361_driver/ad9361_device.h
@@ -16,6 +16,7 @@ class ad9361_device_t : public boost::noncopyable
public:
enum direction_t { RX, TX };
enum chain_t { CHAIN_1, CHAIN_2 };
+ enum gain_mode_t {GAIN_MODE_MANUAL, GAIN_MODE_SLOW_AGC, GAIN_MODE_FAST_AGC};
ad9361_device_t(ad9361_params::sptr client, ad9361_io::sptr io_iface) :
_client_params(client), _io_iface(io_iface) {}
@@ -66,10 +67,29 @@ public:
/* Read back the internal RSSI measurement data. */
double get_rssi(chain_t chain);
+ /*! Read the internal temperature sensor
+ *\param calibrate return raw sensor readings or apply calibration factor.
+ *\param num_samples number of measurements to average over
+ */
+ double get_average_temperature(const double cal_offset = -30.0, const size_t num_samples = 3);
+
+ /* Turn on/off AD9361's RX DC offset correction */
+ void set_dc_offset_auto(direction_t direction, const bool on);
+
+ /* Turn on/off AD9361's RX IQ imbalance correction */
+ void set_iq_balance_auto(direction_t direction, const bool on);
+
+ /* Configure AD9361's AGC module to use either fast or slow AGC mode. */
+ void set_agc_mode(chain_t chain, gain_mode_t gain_mode);
+
+ /* Enable AD9361's AGC gain mode. */
+ void set_agc(chain_t chain, bool enable);
+
//Constants
static const double AD9361_MAX_GAIN;
static const double AD9361_MAX_CLOCK_RATE;
static const double AD9361_RECOMMENDED_MAX_CLOCK_RATE;
+ static const double AD9361_CAL_VALID_WINDOW;
private: //Methods
void _program_fir_filter(direction_t direction, int num_taps, boost::uint16_t *coeffs);
@@ -89,12 +109,15 @@ private: //Methods
void _calibrate_tx_quadrature();
void _program_mixer_gm_subtable();
void _program_gain_table();
- void _setup_gain_control();
+ void _setup_gain_control(bool use_agc);
void _setup_synth(direction_t direction, double vcorate);
double _tune_bbvco(const double rate);
void _reprogram_gains();
double _tune_helper(direction_t direction, const double value);
double _setup_rates(const double rate);
+ double _get_temperature(const double cal_offset, const double timeout = 0.1);
+ void _configure_bb_rf_dc_tracking(const bool on);
+ void _setup_agc(chain_t chain, gain_mode_t gain_mode);
private: //Members
typedef struct {
@@ -112,6 +135,7 @@ private: //Members
ad9361_io::sptr _io_iface;
//Intermediate state
double _rx_freq, _tx_freq, _req_rx_freq, _req_tx_freq;
+ double _last_calibration_freq;
double _baseband_bw, _bbpll_freq, _adcclock_freq;
double _req_clock_rate, _req_coreclk;
boost::uint16_t _rx_bbf_tunediv;
@@ -119,10 +143,14 @@ private: //Members
double _rx1_gain, _rx2_gain, _tx1_gain, _tx2_gain;
boost::int32_t _tfir_factor;
boost::int32_t _rfir_factor;
+ gain_mode_t _rx1_agc_mode, _rx2_agc_mode;
+ bool _rx1_agc_enable, _rx2_agc_enable;
//Register soft-copies
chip_regs_t _regs;
//Synchronization
boost::recursive_mutex _mutex;
+ bool _use_dc_offset_correction;
+ bool _use_iq_balance_correction;
};
}} //namespace
diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_gain_tables.h b/host/lib/usrp/common/ad9361_driver/ad9361_gain_tables.h
index 786029d6e..553655fa5 100644
--- a/host/lib/usrp/common/ad9361_driver/ad9361_gain_tables.h
+++ b/host/lib/usrp/common/ad9361_driver/ad9361_gain_tables.h
@@ -7,91 +7,91 @@
#include <boost/cstdint.hpp>
-boost::uint8_t gain_table_sub_1300mhz[77][5] = { {0,0x00,0x00,0x20,1},
- {1,0x00,0x00,0x00,0}, {2,0x00,0x00,0x00,0}, {3,0x00,0x01,0x00,0},
- {4,0x00,0x02,0x00,0}, {5,0x00,0x03,0x00,0}, {6,0x00,0x04,0x00,0},
- {7,0x00,0x05,0x00,0}, {8,0x01,0x03,0x20,1}, {9,0x01,0x04,0x00,0},
- {10,0x01,0x05,0x00,0}, {11,0x01,0x06,0x00,0}, {12,0x01,0x07,0x00,0},
- {13,0x01,0x08,0x00,0}, {14,0x01,0x09,0x00,0}, {15,0x01,0x0A,0x00,0},
- {16,0x01,0x0B,0x00,0}, {17,0x01,0x0C,0x00,0}, {18,0x01,0x0D,0x00,0},
- {19,0x01,0x0E,0x00,0}, {20,0x02,0x09,0x20,1}, {21,0x02,0x0A,0x00,0},
- {22,0x02,0x0B,0x00,0}, {23,0x02,0x0C,0x00,0}, {24,0x02,0x0D,0x00,0},
- {25,0x02,0x0E,0x00,0}, {26,0x02,0x0F,0x00,0}, {27,0x02,0x10,0x00,0},
- {28,0x02,0x2B,0x20,1}, {29,0x02,0x2C,0x00,0}, {30,0x04,0x27,0x20,1},
- {31,0x04,0x28,0x00,0}, {32,0x04,0x29,0x00,0}, {33,0x04,0x2A,0x00,0},
- {34,0x04,0x2B,0x00,1}, {35,0x24,0x21,0x20,0}, {36,0x24,0x22,0x00,1},
- {37,0x44,0x20,0x20,0}, {38,0x44,0x21,0x00,0}, {39,0x44,0x22,0x00,0},
- {40,0x44,0x23,0x00,0}, {41,0x44,0x24,0x00,0}, {42,0x44,0x25,0x00,0},
- {43,0x44,0x26,0x00,0}, {44,0x44,0x27,0x00,0}, {45,0x44,0x28,0x00,0},
- {46,0x44,0x29,0x00,0}, {47,0x44,0x2A,0x00,0}, {48,0x44,0x2B,0x00,0},
- {49,0x44,0x2C,0x00,0}, {50,0x44,0x2D,0x00,0}, {51,0x44,0x2E,0x00,0},
- {52,0x44,0x2F,0x00,0}, {53,0x44,0x30,0x00,0}, {54,0x44,0x31,0x00,0},
- {55,0x64,0x2E,0x20,1}, {56,0x64,0x2F,0x00,0}, {57,0x64,0x30,0x00,0},
- {58,0x64,0x31,0x00,0}, {59,0x64,0x32,0x00,0}, {60,0x64,0x33,0x00,0},
- {61,0x64,0x34,0x00,0}, {62,0x64,0x35,0x00,0}, {63,0x64,0x36,0x00,0},
- {64,0x64,0x37,0x00,0}, {65,0x64,0x38,0x00,0}, {66,0x65,0x38,0x20,1},
- {67,0x66,0x38,0x20,1}, {68,0x67,0x38,0x20,1}, {69,0x68,0x38,0x20,1},
- {70,0x69,0x38,0x20,1}, {71,0x6A,0x38,0x20,1}, {72,0x6B,0x38,0x20,1},
- {73,0x6C,0x38,0x20,1}, {74,0x6D,0x38,0x20,1}, {75,0x6E,0x38,0x20,1},
- {76,0x6F,0x38,0x20,1}};
+boost::uint8_t gain_table_sub_1300mhz[77][3] = {
+{ 0x00, 0x00, 0x20 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 },
+{ 0x00, 0x01, 0x00 }, { 0x00, 0x02, 0x00 }, { 0x00, 0x03, 0x00 },
+{ 0x00, 0x04, 0x00 }, { 0x00, 0x05, 0x00 }, { 0x01, 0x03, 0x20 },
+{ 0x01, 0x04, 0x00 }, { 0x01, 0x05, 0x00 }, { 0x01, 0x06, 0x00 },
+{ 0x01, 0x07, 0x00 }, { 0x01, 0x08, 0x00 }, { 0x01, 0x09, 0x00 },
+{ 0x01, 0x0A, 0x00 }, { 0x01, 0x0B, 0x00 }, { 0x01, 0x0C, 0x00 },
+{ 0x01, 0x0D, 0x00 }, { 0x01, 0x0E, 0x00 }, { 0x02, 0x09, 0x20 },
+{ 0x02, 0x0A, 0x00 }, { 0x02, 0x0B, 0x00 }, { 0x02, 0x0C, 0x00 },
+{ 0x02, 0x0D, 0x00 }, { 0x02, 0x0E, 0x00 }, { 0x02, 0x0F, 0x00 },
+{ 0x02, 0x10, 0x00 }, { 0x02, 0x2B, 0x20 }, { 0x02, 0x2C, 0x00 },
+{ 0x04, 0x28, 0x20 }, { 0x04, 0x29, 0x00 }, { 0x04, 0x2A, 0x00 },
+{ 0x04, 0x2B, 0x00 }, { 0x24, 0x20, 0x20 }, { 0x24, 0x21, 0x00 },
+{ 0x44, 0x20, 0x20 }, { 0x44, 0x21, 0x00 }, { 0x44, 0x22, 0x00 },
+{ 0x44, 0x23, 0x00 }, { 0x44, 0x24, 0x00 }, { 0x44, 0x25, 0x00 },
+{ 0x44, 0x26, 0x00 }, { 0x44, 0x27, 0x00 }, { 0x44, 0x28, 0x00 },
+{ 0x44, 0x29, 0x00 }, { 0x44, 0x2A, 0x00 }, { 0x44, 0x2B, 0x00 },
+{ 0x44, 0x2C, 0x00 }, { 0x44, 0x2D, 0x00 }, { 0x44, 0x2E, 0x00 },
+{ 0x44, 0x2F, 0x00 }, { 0x44, 0x30, 0x00 }, { 0x44, 0x31, 0x00 },
+{ 0x44, 0x32, 0x00 }, { 0x64, 0x2E, 0x20 }, { 0x64, 0x2F, 0x00 },
+{ 0x64, 0x30, 0x00 }, { 0x64, 0x31, 0x00 }, { 0x64, 0x32, 0x00 },
+{ 0x64, 0x33, 0x00 }, { 0x64, 0x34, 0x00 }, { 0x64, 0x35, 0x00 },
+{ 0x64, 0x36, 0x00 }, { 0x64, 0x37, 0x00 }, { 0x64, 0x38, 0x00 },
+{ 0x65, 0x38, 0x20 }, { 0x66, 0x38, 0x20 }, { 0x67, 0x38, 0x20 },
+{ 0x68, 0x38, 0x20 }, { 0x69, 0x38, 0x20 }, { 0x6A, 0x38, 0x20 },
+{ 0x6B, 0x38, 0x20 }, { 0x6C, 0x38, 0x20 }, { 0x6D, 0x38, 0x20 },
+{ 0x6E, 0x38, 0x20 }, { 0x6F, 0x38, 0x20 } };
-boost::uint8_t gain_table_1300mhz_to_4000mhz[77][5] = { {0,0x00,0x00,0x20,1},
- {1,0x00,0x00,0x00,0}, {2,0x00,0x00,0x00,0}, {3,0x00,0x01,0x00,0},
- {4,0x00,0x02,0x00,0}, {5,0x00,0x03,0x00,0}, {6,0x00,0x04,0x00,0},
- {7,0x00,0x05,0x00,0}, {8,0x01,0x03,0x20,1}, {9,0x01,0x04,0x00,0},
- {10,0x01,0x05,0x00,0}, {11,0x01,0x06,0x00,0}, {12,0x01,0x07,0x00,0},
- {13,0x01,0x08,0x00,0}, {14,0x01,0x09,0x00,0}, {15,0x01,0x0A,0x00,0},
- {16,0x01,0x0B,0x00,0}, {17,0x01,0x0C,0x00,0}, {18,0x01,0x0D,0x00,0},
- {19,0x01,0x0E,0x00,0}, {20,0x02,0x09,0x20,1}, {21,0x02,0x0A,0x00,0},
- {22,0x02,0x0B,0x00,0}, {23,0x02,0x0C,0x00,0}, {24,0x02,0x0D,0x00,0},
- {25,0x02,0x0E,0x00,0}, {26,0x02,0x0F,0x00,0}, {27,0x02,0x10,0x00,0},
- {28,0x02,0x2B,0x20,1}, {29,0x02,0x2C,0x00,0}, {30,0x04,0x28,0x20,1},
- {31,0x04,0x29,0x00,0}, {32,0x04,0x2A,0x00,0}, {33,0x04,0x2B,0x00,0},
- {34,0x24,0x20,0x20,0}, {35,0x24,0x21,0x00,1}, {36,0x44,0x20,0x20,0},
- {37,0x44,0x21,0x00,1}, {38,0x44,0x22,0x00,0}, {39,0x44,0x23,0x00,0},
- {40,0x44,0x24,0x00,0}, {41,0x44,0x25,0x00,0}, {42,0x44,0x26,0x00,0},
- {43,0x44,0x27,0x00,0}, {44,0x44,0x28,0x00,0}, {45,0x44,0x29,0x00,0},
- {46,0x44,0x2A,0x00,0}, {47,0x44,0x2B,0x00,0}, {48,0x44,0x2C,0x00,0},
- {49,0x44,0x2D,0x00,0}, {50,0x44,0x2E,0x00,0}, {51,0x44,0x2F,0x00,0},
- {52,0x44,0x30,0x00,0}, {53,0x44,0x31,0x00,0}, {54,0x44,0x32,0x00,0},
- {55,0x64,0x2E,0x20,1}, {56,0x64,0x2F,0x00,0}, {57,0x64,0x30,0x00,0},
- {58,0x64,0x31,0x00,0}, {59,0x64,0x32,0x00,0}, {60,0x64,0x33,0x00,0},
- {61,0x64,0x34,0x00,0}, {62,0x64,0x35,0x00,0}, {63,0x64,0x36,0x00,0},
- {64,0x64,0x37,0x00,0}, {65,0x64,0x38,0x00,0}, {66,0x65,0x38,0x20,1},
- {67,0x66,0x38,0x20,1}, {68,0x67,0x38,0x20,1}, {69,0x68,0x38,0x20,1},
- {70,0x69,0x38,0x20,1}, {71,0x6A,0x38,0x20,1}, {72,0x6B,0x38,0x20,1},
- {73,0x6C,0x38,0x20,1}, {74,0x6D,0x38,0x20,1}, {75,0x6E,0x38,0x20,1},
- {76,0x6F,0x38,0x20,1}};
+boost::uint8_t gain_table_1300mhz_to_4000mhz[77][3] = {
+{ 0x00, 0x00, 0x20 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 },
+{ 0x00, 0x01, 0x00 }, { 0x00, 0x02, 0x00 }, { 0x00, 0x03, 0x00 },
+{ 0x00, 0x04, 0x00 }, { 0x00, 0x05, 0x00 }, { 0x01, 0x03, 0x20 },
+{ 0x01, 0x04, 0x00 }, { 0x01, 0x05, 0x00 }, { 0x01, 0x06, 0x00 },
+{ 0x01, 0x07, 0x00 }, { 0x01, 0x08, 0x00 }, { 0x01, 0x09, 0x00 },
+{ 0x01, 0x0A, 0x00 }, { 0x01, 0x0B, 0x00 }, { 0x01, 0x0C, 0x00 },
+{ 0x01, 0x0D, 0x00 }, { 0x01, 0x0E, 0x00 }, { 0x02, 0x09, 0x20 },
+{ 0x02, 0x0A, 0x00 }, { 0x02, 0x0B, 0x00 }, { 0x02, 0x0C, 0x00 },
+{ 0x02, 0x0D, 0x00 }, { 0x02, 0x0E, 0x00 }, { 0x02, 0x0F, 0x00 },
+{ 0x02, 0x10, 0x00 }, { 0x02, 0x2B, 0x20 }, { 0x02, 0x2C, 0x00 },
+{ 0x04, 0x27, 0x20 }, { 0x04, 0x28, 0x00 }, { 0x04, 0x29, 0x00 },
+{ 0x04, 0x2A, 0x00 }, { 0x04, 0x2B, 0x00 }, { 0x24, 0x21, 0x20 },
+{ 0x24, 0x22, 0x00 }, { 0x44, 0x20, 0x20 }, { 0x44, 0x21, 0x00 },
+{ 0x44, 0x22, 0x00 }, { 0x44, 0x23, 0x00 }, { 0x44, 0x24, 0x00 },
+{ 0x44, 0x25, 0x00 }, { 0x44, 0x26, 0x00 }, { 0x44, 0x27, 0x00 },
+{ 0x44, 0x28, 0x00 }, { 0x44, 0x29, 0x00 }, { 0x44, 0x2A, 0x00 },
+{ 0x44, 0x2B, 0x00 }, { 0x44, 0x2C, 0x00 }, { 0x44, 0x2D, 0x00 },
+{ 0x44, 0x2E, 0x00 }, { 0x44, 0x2F, 0x00 }, { 0x44, 0x30, 0x00 },
+{ 0x44, 0x31, 0x00 }, { 0x64, 0x2E, 0x20 }, { 0x64, 0x2F, 0x00 },
+{ 0x64, 0x30, 0x00 }, { 0x64, 0x31, 0x00 }, { 0x64, 0x32, 0x00 },
+{ 0x64, 0x33, 0x00 }, { 0x64, 0x34, 0x00 }, { 0x64, 0x35, 0x00 },
+{ 0x64, 0x36, 0x00 }, { 0x64, 0x37, 0x00 }, { 0x64, 0x38, 0x00 },
+{ 0x65, 0x38, 0x20 }, { 0x66, 0x38, 0x20 }, { 0x67, 0x38, 0x20 },
+{ 0x68, 0x38, 0x20 }, { 0x69, 0x38, 0x20 }, { 0x6A, 0x38, 0x20 },
+{ 0x6B, 0x38, 0x20 }, { 0x6C, 0x38, 0x20 }, { 0x6D, 0x38, 0x20 },
+{ 0x6E, 0x38, 0x20 }, { 0x6F, 0x38, 0x20 } };
-boost::uint8_t gain_table_4000mhz_to_6000mhz[77][5] = { {0,0x00,0x00,0x20,1},
- {1,0x00,0x00,0x00,0}, {2,0x00,0x00,0x00,0}, {3,0x00,0x00,0x00,0},
- {4,0x00,0x00,0x00,0}, {5,0x00,0x01,0x00,0}, {6,0x00,0x02,0x00,0},
- {7,0x00,0x03,0x00,0}, {8,0x01,0x01,0x20,1}, {9,0x01,0x02,0x00,0},
- {10,0x01,0x03,0x00,0}, {11,0x01,0x04,0x20,1}, {12,0x01,0x05,0x00,0},
- {13,0x01,0x06,0x00,0}, {14,0x01,0x07,0x00,0}, {15,0x01,0x08,0x00,0},
- {16,0x01,0x09,0x00,0}, {17,0x01,0x0A,0x00,0}, {18,0x01,0x0B,0x00,0},
- {19,0x01,0x0C,0x00,0}, {20,0x02,0x08,0x20,1}, {21,0x02,0x09,0x00,0},
- {22,0x02,0x0A,0x00,0}, {23,0x02,0x0B,0x20,1}, {24,0x02,0x0C,0x00,0},
- {25,0x02,0x0D,0x00,0}, {26,0x02,0x0E,0x00,0}, {27,0x02,0x0F,0x00,0},
- {28,0x02,0x2A,0x20,1}, {29,0x02,0x2B,0x00,0}, {30,0x04,0x27,0x20,1},
- {31,0x04,0x28,0x00,0}, {32,0x04,0x29,0x00,0}, {33,0x04,0x2A,0x00,0},
- {34,0x04,0x2B,0x00,0}, {35,0x04,0x2C,0x00,0}, {36,0x04,0x2D,0x00,0},
- {37,0x24,0x20,0x20,1}, {38,0x24,0x21,0x00,0}, {39,0x24,0x22,0x00,0},
- {40,0x44,0x20,0x20,1}, {41,0x44,0x21,0x00,0}, {42,0x44,0x22,0x00,0},
- {43,0x44,0x23,0x00,0}, {44,0x44,0x24,0x00,0}, {45,0x44,0x25,0x00,0},
- {46,0x44,0x26,0x00,0}, {47,0x44,0x27,0x00,0}, {48,0x44,0x28,0x00,0},
- {49,0x44,0x29,0x00,0}, {50,0x44,0x2A,0x00,0}, {51,0x44,0x2B,0x00,0},
- {52,0x44,0x2C,0x00,0}, {53,0x44,0x2D,0x00,0}, {54,0x44,0x2E,0x00,0},
- {55,0x64,0x2E,0x20,1}, {56,0x64,0x2F,0x00,0}, {57,0x64,0x30,0x00,0},
- {58,0x64,0x31,0x00,0}, {59,0x64,0x32,0x00,0}, {60,0x64,0x33,0x00,0},
- {61,0x64,0x34,0x00,0}, {62,0x64,0x35,0x00,0}, {63,0x64,0x36,0x00,0},
- {64,0x64,0x37,0x00,0}, {65,0x64,0x38,0x00,0}, {66,0x65,0x38,0x20,1},
- {67,0x66,0x38,0x20,1}, {68,0x67,0x38,0x20,1}, {69,0x68,0x38,0x20,1},
- {70,0x69,0x38,0x20,1}, {71,0x6A,0x38,0x20,1}, {72,0x6B,0x38,0x20,1},
- {73,0x6C,0x38,0x20,1}, {74,0x6D,0x38,0x20,1}, {75,0x6E,0x38,0x20,1},
- {76,0x6F,0x38,0x20,1}};
+boost::uint8_t gain_table_4000mhz_to_6000mhz[77][3] = {
+{ 0x00, 0x00, 0x20 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 },
+{ 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x01, 0x00 },
+{ 0x00, 0x02, 0x00 }, { 0x00, 0x03, 0x00 }, { 0x01, 0x01, 0x20 },
+{ 0x01, 0x02, 0x00 }, { 0x01, 0x03, 0x00 }, { 0x01, 0x04, 0x20 },
+{ 0x01, 0x05, 0x00 }, { 0x01, 0x06, 0x00 }, { 0x01, 0x07, 0x00 },
+{ 0x01, 0x08, 0x00 }, { 0x01, 0x09, 0x00 }, { 0x01, 0x0A, 0x00 },
+{ 0x01, 0x0B, 0x00 }, { 0x01, 0x0C, 0x00 }, { 0x02, 0x08, 0x20 },
+{ 0x02, 0x09, 0x00 }, { 0x02, 0x0A, 0x00 }, { 0x02, 0x0B, 0x20 },
+{ 0x02, 0x0C, 0x00 }, { 0x02, 0x0D, 0x00 }, { 0x02, 0x0E, 0x00 },
+{ 0x02, 0x0F, 0x00 }, { 0x02, 0x2A, 0x20 }, { 0x02, 0x2B, 0x00 },
+{ 0x04, 0x27, 0x20 }, { 0x04, 0x28, 0x00 }, { 0x04, 0x29, 0x00 },
+{ 0x04, 0x2A, 0x00 }, { 0x04, 0x2B, 0x00 }, { 0x04, 0x2C, 0x00 },
+{ 0x04, 0x2D, 0x00 }, { 0x24, 0x20, 0x20 }, { 0x24, 0x21, 0x00 },
+{ 0x24, 0x22, 0x00 }, { 0x44, 0x20, 0x20 }, { 0x44, 0x21, 0x00 },
+{ 0x44, 0x22, 0x00 }, { 0x44, 0x23, 0x00 }, { 0x44, 0x24, 0x00 },
+{ 0x44, 0x25, 0x00 }, { 0x44, 0x26, 0x00 }, { 0x44, 0x27, 0x00 },
+{ 0x44, 0x28, 0x00 }, { 0x44, 0x29, 0x00 }, { 0x44, 0x2A, 0x00 },
+{ 0x44, 0x2B, 0x00 }, { 0x44, 0x2C, 0x00 }, { 0x44, 0x2D, 0x00 },
+{ 0x44, 0x2E, 0x00 }, { 0x64, 0x2E, 0x20 }, { 0x64, 0x2F, 0x00 },
+{ 0x64, 0x30, 0x00 }, { 0x64, 0x31, 0x00 }, { 0x64, 0x32, 0x00 },
+{ 0x64, 0x33, 0x00 }, { 0x64, 0x34, 0x00 }, { 0x64, 0x35, 0x00 },
+{ 0x64, 0x36, 0x00 }, { 0x64, 0x37, 0x00 }, { 0x64, 0x38, 0x00 },
+{ 0x65, 0x38, 0x20 }, { 0x66, 0x38, 0x20 }, { 0x67, 0x38, 0x20 },
+{ 0x68, 0x38, 0x20 }, { 0x69, 0x38, 0x20 }, { 0x6A, 0x38, 0x20 },
+{ 0x6B, 0x38, 0x20 }, { 0x6C, 0x38, 0x20 }, { 0x6D, 0x38, 0x20 },
+{ 0x6E, 0x38, 0x20 }, { 0x6F, 0x38, 0x20 } };
#endif /* INCLUDED_AD9361_GAIN_TABLES_HPP */
diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_synth_lut.h b/host/lib/usrp/common/ad9361_driver/ad9361_synth_lut.h
index cb320e1f4..0475a5eb1 100644
--- a/host/lib/usrp/common/ad9361_driver/ad9361_synth_lut.h
+++ b/host/lib/usrp/common/ad9361_driver/ad9361_synth_lut.h
@@ -6,20 +6,20 @@
#define INCLUDED_AD9361_SYNTH_LUT_HPP
-double vco_index[53] = {12605000000, 12245000000, 11906000000, 11588000000,
- 11288000000, 11007000000, 10742000000, 10492000000,
- 10258000000, 10036000000, 9827800000, 9631100000,
- 9445300000, 9269800000, 9103600000, 8946300000,
- 8797000000, 8655300000, 8520600000, 8392300000,
- 8269900000, 8153100000, 8041400000, 7934400000,
- 7831800000, 7733200000, 7638400000, 7547100000,
- 7459000000, 7374000000, 7291900000, 7212400000,
- 7135500000, 7061000000, 6988700000, 6918600000,
- 6850600000, 6784600000, 6720500000, 6658200000,
- 6597800000, 6539200000, 6482300000, 6427000000,
- 6373400000, 6321400000, 6270900000, 6222000000,
- 6174500000, 6128400000, 6083600000, 6040100000,
- 5997700000};
+double vco_index[53] = {12605000000.0, 12245000000.0, 11906000000.0, 11588000000.0,
+ 11288000000.0, 11007000000.0, 10742000000.0, 10492000000.0,
+ 10258000000.0, 10036000000.0, 9827800000.0, 9631100000.0,
+ 9445300000.0, 9269800000.0, 9103600000.0, 8946300000.0,
+ 8797000000.0, 8655300000.0, 8520600000.0, 8392300000.0,
+ 8269900000.0, 8153100000.0, 8041400000.0, 7934400000.0,
+ 7831800000.0, 7733200000.0, 7638400000.0, 7547100000.0,
+ 7459000000.0, 7374000000.0, 7291900000.0, 7212400000.0,
+ 7135500000.0, 7061000000.0, 6988700000.0, 6918600000.0,
+ 6850600000.0, 6784600000.0, 6720500000.0, 6658200000.0,
+ 6597800000.0, 6539200000.0, 6482300000.0, 6427000000.0,
+ 6373400000.0, 6321400000.0, 6270900000.0, 6222000000.0,
+ 6174500000.0, 6128400000.0, 6083600000.0, 6040100000.0,
+ 5997700000.0};
int synth_cal_lut[53][12] = { {10, 0, 4, 0, 15, 8, 8, 13, 4, 13, 15, 9},
{10, 0, 4, 0, 15, 8, 9, 13, 4, 13, 15, 9},
diff --git a/host/lib/usrp/cores/gpio_core_200.hpp b/host/lib/usrp/cores/gpio_core_200.hpp
index 164437f40..e22834fd9 100644
--- a/host/lib/usrp/cores/gpio_core_200.hpp
+++ b/host/lib/usrp/cores/gpio_core_200.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011,2014 Ettus Research LLC
+// Copyright 2011,2014,2015 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
@@ -20,10 +20,34 @@
#include <uhd/config.hpp>
#include <uhd/usrp/dboard_iface.hpp>
+#include <boost/assign.hpp>
#include <boost/cstdint.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
#include <uhd/types/wb_iface.hpp>
+#include <map>
+
+typedef enum {
+ GPIO_CTRL,
+ GPIO_DDR,
+ GPIO_OUT,
+ GPIO_ATR_0X,
+ GPIO_ATR_RX,
+ GPIO_ATR_TX,
+ GPIO_ATR_XX
+} gpio_attr_t;
+
+typedef std::map<gpio_attr_t,std::string> gpio_attr_map_t;
+static const gpio_attr_map_t gpio_attr_map =
+ boost::assign::map_list_of
+ (GPIO_CTRL, "CTRL")
+ (GPIO_DDR, "DDR")
+ (GPIO_OUT, "OUT")
+ (GPIO_ATR_0X, "ATR_0X")
+ (GPIO_ATR_RX, "ATR_RX")
+ (GPIO_ATR_TX, "ATR_TX")
+ (GPIO_ATR_XX, "ATR_XX")
+;
class gpio_core_200 : boost::noncopyable{
public:
diff --git a/host/lib/usrp/cores/rx_dsp_core_3000.cpp b/host/lib/usrp/cores/rx_dsp_core_3000.cpp
index 13d69920a..8a131ffb4 100644
--- a/host/lib/usrp/cores/rx_dsp_core_3000.cpp
+++ b/host/lib/usrp/cores/rx_dsp_core_3000.cpp
@@ -72,7 +72,7 @@ public:
{
UHD_SAFE_CALL
(
- //NOP
+ ;//NOP
)
}
diff --git a/host/lib/usrp/cores/time_core_3000.cpp b/host/lib/usrp/cores/time_core_3000.cpp
index aa5d5593d..ffae5dc0d 100644
--- a/host/lib/usrp/cores/time_core_3000.cpp
+++ b/host/lib/usrp/cores/time_core_3000.cpp
@@ -50,7 +50,7 @@ struct time_core_3000_impl : time_core_3000
{
UHD_SAFE_CALL
(
- //NOP
+ ;//NOP
)
}
@@ -71,8 +71,8 @@ struct time_core_3000_impl : time_core_3000
UHD_MSG(status) << ((test_fail)? " fail" : "pass") << std::endl;
//useful warning for debugging actual rate
- const size_t ticks_elapsed = _tick_rate*approx_secs;
- const size_t appox_rate = ticks_elapsed/(sleep_millis/1e3);
+ const size_t ticks_elapsed = size_t(_tick_rate*approx_secs);
+ const size_t appox_rate = size_t(ticks_elapsed/(sleep_millis/1e3));
if (test_fail) UHD_MSG(warning)
<< "Expecting clock rate: " << (_tick_rate/1e6) << " MHz\n"
<< "Appoximate clock rate: " << (appox_rate/1e6) << " MHz\n"
diff --git a/host/lib/usrp/dboard/db_cbx.cpp b/host/lib/usrp/dboard/db_cbx.cpp
index db7f84932..ad255460e 100644
--- a/host/lib/usrp/dboard/db_cbx.cpp
+++ b/host/lib/usrp/dboard/db_cbx.cpp
@@ -142,7 +142,7 @@ double sbx_xcvr::cbx::set_lo_freq(dboard_iface::unit_t unit, double target_freq)
}
//keep pfd freq low enough to achieve 50kHz BS clock
- BS = std::ceil(pfd_freq / 50e3);
+ BS = int(std::ceil(pfd_freq / 50e3));
if(BS <= 1023) break;
}
diff --git a/host/lib/usrp/dboard/db_ubx.cpp b/host/lib/usrp/dboard/db_ubx.cpp
index dd30cf534..5184d2ecb 100644
--- a/host/lib/usrp/dboard/db_ubx.cpp
+++ b/host/lib/usrp/dboard/db_ubx.cpp
@@ -32,6 +32,7 @@
#include <boost/math/special_functions/round.hpp>
#include <boost/thread.hpp>
#include <boost/algorithm/string.hpp>
+#include <boost/thread/mutex.hpp>
#include <map>
using namespace uhd;
@@ -83,7 +84,7 @@ protected:
// Get only regs with changes
try {
changed_regs = get_changed_addrs();
- } catch (uhd::runtime_error& e) {
+ } catch (uhd::runtime_error&) {
// No saved state - write all regs
for (int addr = 5; addr >= 0; addr--)
changed_regs.insert(boost::uint32_t(addr));
@@ -691,7 +692,7 @@ static const ubx_gpio_field_info_t ubx_v1_gpio_info[] = {
};
/***********************************************************************
- * Macros and helper functions for routing and writing SPI registers
+ * Macros for routing and writing SPI registers
**********************************************************************/
#define ROUTE_SPI(iface, dest) \
iface->set_gpio_out(dboard_iface::UNIT_TX, dest, 0x7);
@@ -699,19 +700,6 @@ static const ubx_gpio_field_info_t ubx_v1_gpio_info[] = {
#define WRITE_SPI(iface, val) \
iface->write_spi(dboard_iface::UNIT_TX, spi_config_t::EDGE_RISE, val, 32);
-UHD_INLINE void write_spi_reg(dboard_iface::sptr iface, spi_dest_t dest, boost::uint32_t value)
-{
- ROUTE_SPI(iface, dest);
- WRITE_SPI(iface, value);
-}
-
-UHD_INLINE void write_spi_regs(dboard_iface::sptr iface, spi_dest_t dest, std::vector<boost::uint32_t> values)
-{
- ROUTE_SPI(iface, dest);
- for (size_t i = 0; i < values.size(); i++)
- WRITE_SPI(iface, values[i]);
-}
-
/***********************************************************************
* UBX Class Definition
**********************************************************************/
@@ -813,17 +801,17 @@ public:
// Initialize LOs
if (_rev == 0)
{
- _txlo1.reset(new max2870(boost::bind(&write_spi_regs, _iface, TXLO1, _1)));
- _txlo2.reset(new max2870(boost::bind(&write_spi_regs, _iface, TXLO2, _1)));
- _rxlo1.reset(new max2870(boost::bind(&write_spi_regs, _iface, RXLO1, _1)));
- _rxlo2.reset(new max2870(boost::bind(&write_spi_regs, _iface, RXLO2, _1)));
+ _txlo1.reset(new max2870(boost::bind(&ubx_xcvr::write_spi_regs, this, TXLO1, _1)));
+ _txlo2.reset(new max2870(boost::bind(&ubx_xcvr::write_spi_regs, this, TXLO2, _1)));
+ _rxlo1.reset(new max2870(boost::bind(&ubx_xcvr::write_spi_regs, this, RXLO1, _1)));
+ _rxlo2.reset(new max2870(boost::bind(&ubx_xcvr::write_spi_regs, this, RXLO2, _1)));
}
else if (_rev == 1)
{
- _txlo1.reset(new max2871(boost::bind(&write_spi_regs, _iface, TXLO1, _1)));
- _txlo2.reset(new max2871(boost::bind(&write_spi_regs, _iface, TXLO2, _1)));
- _rxlo1.reset(new max2871(boost::bind(&write_spi_regs, _iface, RXLO1, _1)));
- _rxlo2.reset(new max2871(boost::bind(&write_spi_regs, _iface, RXLO2, _1)));
+ _txlo1.reset(new max2871(boost::bind(&ubx_xcvr::write_spi_regs, this, TXLO1, _1)));
+ _txlo2.reset(new max2871(boost::bind(&ubx_xcvr::write_spi_regs, this, TXLO2, _1)));
+ _rxlo1.reset(new max2871(boost::bind(&ubx_xcvr::write_spi_regs, this, RXLO1, _1)));
+ _rxlo2.reset(new max2871(boost::bind(&ubx_xcvr::write_spi_regs, this, RXLO2, _1)));
}
else
{
@@ -948,6 +936,21 @@ private:
/***********************************************************************
* Helper Functions
**********************************************************************/
+ void write_spi_reg(spi_dest_t dest, boost::uint32_t value)
+ {
+ boost::mutex::scoped_lock lock(_spi_lock);
+ ROUTE_SPI(_iface, dest);
+ WRITE_SPI(_iface, value);
+ }
+
+ void write_spi_regs(spi_dest_t dest, std::vector<boost::uint32_t> values)
+ {
+ boost::mutex::scoped_lock lock(_spi_lock);
+ ROUTE_SPI(_iface, dest);
+ BOOST_FOREACH(boost::uint32_t value, values)
+ WRITE_SPI(_iface, value);
+ }
+
void set_cpld_field(ubx_cpld_field_id_t id, boost::uint32_t value)
{
_cpld_reg.set_field(id, value);
@@ -955,7 +958,7 @@ private:
void write_cpld_reg()
{
- write_spi_reg(_iface, CPLD, _cpld_reg.value);
+ write_spi_reg(CPLD, _cpld_reg.value);
}
void set_gpio_field(ubx_gpio_field_id_t id, boost::uint32_t value)
@@ -1389,6 +1392,7 @@ private:
* Variables
**********************************************************************/
dboard_iface::sptr _iface;
+ boost::mutex _spi_lock;
ubx_cpld_reg_t _cpld_reg;
boost::shared_ptr<max287x_synthesizer_iface> _txlo1;
boost::shared_ptr<max287x_synthesizer_iface> _txlo2;
diff --git a/host/lib/usrp/e300/e300_eeprom_manager.cpp b/host/lib/usrp/e300/e300_eeprom_manager.cpp
index dad6741f5..778e3150c 100644
--- a/host/lib/usrp/e300/e300_eeprom_manager.cpp
+++ b/host/lib/usrp/e300/e300_eeprom_manager.cpp
@@ -21,7 +21,7 @@
namespace uhd { namespace usrp { namespace e300 {
-static const std::string _bytes_to_string(const uint8_t* bytes, size_t max_len)
+static const std::string _bytes_to_string(const boost::uint8_t* bytes, size_t max_len)
{
std::string out;
for (size_t i = 0; i < max_len; i++) {
@@ -31,7 +31,7 @@ static const std::string _bytes_to_string(const uint8_t* bytes, size_t max_len)
return out;
}
-static void _string_to_bytes(const std::string &string, size_t max_len, uint8_t* buffer)
+static void _string_to_bytes(const std::string &string, size_t max_len, boost::uint8_t* buffer)
{
byte_vector_t bytes;
const size_t len = std::min(string.size(), max_len);
diff --git a/host/lib/usrp/e300/e300_impl.cpp b/host/lib/usrp/e300/e300_impl.cpp
index ac6294d5a..8be3e47c9 100644
--- a/host/lib/usrp/e300/e300_impl.cpp
+++ b/host/lib/usrp/e300/e300_impl.cpp
@@ -469,15 +469,14 @@ e300_impl::e300_impl(const uhd::device_addr_t &device_addr)
// internal gpios
////////////////////////////////////////////////////////////////////
gpio_core_200::sptr fp_gpio = gpio_core_200::make(_radio_perifs[0].ctrl, TOREG(SR_FP_GPIO), RB32_FP_GPIO);
- const std::vector<std::string> gpio_attrs = boost::assign::list_of("CTRL")("DDR")("OUT")("ATR_0X")("ATR_RX")("ATR_TX")("ATR_XX");
- BOOST_FOREACH(const std::string &attr, gpio_attrs)
+ BOOST_FOREACH(const gpio_attr_map_t::value_type attr, gpio_attr_map)
{
- _tree->create<boost::uint32_t>(mb_path / "gpio" / "INT0" / attr)
- .subscribe(boost::bind(&e300_impl::_set_internal_gpio, this, fp_gpio, attr, _1))
+ _tree->create<boost::uint32_t>(mb_path / "gpio" / "INT0" / attr.second)
+ .subscribe(boost::bind(&e300_impl::_set_internal_gpio, this, fp_gpio, attr.first, _1))
.set(0);
}
_tree->create<boost::uint8_t>(mb_path / "gpio" / "INT0" / "READBACK")
- .publish(boost::bind(&e300_impl::_get_internal_gpio, this, fp_gpio, "READBACK"));
+ .publish(boost::bind(&e300_impl::_get_internal_gpio, this, fp_gpio));
////////////////////////////////////////////////////////////////////
@@ -576,32 +575,35 @@ e300_impl::e300_impl(const uhd::device_addr_t &device_addr)
_tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(tx_spec);
}
-boost::uint8_t e300_impl::_get_internal_gpio(
- gpio_core_200::sptr gpio,
- const std::string &)
+boost::uint8_t e300_impl::_get_internal_gpio(gpio_core_200::sptr gpio)
{
return boost::uint32_t(gpio->read_gpio(dboard_iface::UNIT_RX));
}
void e300_impl::_set_internal_gpio(
gpio_core_200::sptr gpio,
- const std::string &attr,
+ const gpio_attr_t attr,
const boost::uint32_t value)
{
- if (attr == "CTRL")
+ switch (attr)
+ {
+ case GPIO_CTRL:
return gpio->set_pin_ctrl(dboard_iface::UNIT_RX, value);
- else if (attr == "DDR")
+ case GPIO_DDR:
return gpio->set_gpio_ddr(dboard_iface::UNIT_RX, value);
- else if (attr == "OUT")
+ case GPIO_OUT:
return gpio->set_gpio_out(dboard_iface::UNIT_RX, value);
- else if (attr == "ATR_0X")
+ case GPIO_ATR_0X:
return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, value);
- else if (attr == "ATR_RX")
+ case GPIO_ATR_RX:
return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, value);
- else if (attr == "ATR_TX")
+ case GPIO_ATR_TX:
return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, value);
- else if (attr == "ATR_XX")
+ case GPIO_ATR_XX:
return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, value);
+ default:
+ UHD_THROW_INVALID_CODE_PATH();
+ }
}
uhd::sensor_value_t e300_impl::_get_fe_pll_lock(const bool is_tx)
@@ -1028,6 +1030,8 @@ void e300_impl::_setup_radio(const size_t dspno)
_tree->create<int>(rf_fe_path / "sensors"); //empty TODO
_tree->create<sensor_value_t>(rf_fe_path / "sensors" / "lo_locked")
.publish(boost::bind(&e300_impl::_get_fe_pll_lock, this, direction == "tx"));
+ _tree->create<sensor_value_t>(rf_fe_path / "sensors" / "temp")
+ .publish(boost::bind(&ad9361_ctrl::get_temperature, _codec_ctrl));
BOOST_FOREACH(const std::string &name, ad9361_ctrl::get_gain_names(key))
{
_tree->create<meta_range_t>(rf_fe_path / "gains" / name / "range")
diff --git a/host/lib/usrp/e300/e300_impl.hpp b/host/lib/usrp/e300/e300_impl.hpp
index a4170ee42..21aef215d 100644
--- a/host/lib/usrp/e300/e300_impl.hpp
+++ b/host/lib/usrp/e300/e300_impl.hpp
@@ -70,6 +70,8 @@ static std::string E300_SERVER_I2C_PORT = "21761";
static std::string E300_SERVER_SENSOR_PORT = "21762";
static const double E300_RX_SW_BUFF_FULLNESS = 0.9; //Buffer should be half full
+static const size_t E300_RX_FC_REQUEST_FREQ = 32; // per flow ctrl window
+static const size_t E300_TX_FC_RESPONSE_FREQ = 8; // per flow ctrl window
// crossbar settings
static const boost::uint8_t E300_RADIO_DEST_PREFIX_TX = 0;
@@ -262,13 +264,11 @@ private: // methods
uhd::sensor_value_t _get_fe_pll_lock(const bool is_tx);
// internal gpios
- boost::uint8_t _get_internal_gpio(
- gpio_core_200::sptr,
- const std::string &);
+ boost::uint8_t _get_internal_gpio(gpio_core_200::sptr);
void _set_internal_gpio(
gpio_core_200::sptr gpio,
- const std::string &attr,
+ const gpio_attr_t attr,
const boost::uint32_t value);
private: // members
diff --git a/host/lib/usrp/e300/e300_io_impl.cpp b/host/lib/usrp/e300/e300_io_impl.cpp
index dcb6f2afe..fa4915ed1 100644
--- a/host/lib/usrp/e300/e300_io_impl.cpp
+++ b/host/lib/usrp/e300/e300_io_impl.cpp
@@ -25,6 +25,7 @@
#include <uhd/transport/bounded_buffer.hpp>
#include <boost/bind.hpp>
#include <uhd/utils/tasks.hpp>
+#include <uhd/utils/log.hpp>
#include <boost/foreach.hpp>
#include <boost/make_shared.hpp>
@@ -226,6 +227,18 @@ void e300_impl::_handle_overflow(
}
}
+static size_t get_rx_flow_control_window(size_t frame_size, size_t sw_buff_size, double fullness_factor)
+{
+ if (fullness_factor < 0.01 || fullness_factor > 1) {
+ throw uhd::value_error("recv_buff_fullness must be between 0.01 and 1 inclusive (1% to 100%)");
+ }
+
+ size_t window_in_pkts = (static_cast<size_t>(sw_buff_size * fullness_factor) / frame_size);
+ if (window_in_pkts == 0) {
+ throw uhd::value_error("recv_buff_size must be larger than the recv_frame_size.");
+ }
+ return window_in_pkts;
+}
static void handle_rx_flowctrl(
const boost::uint32_t sid,
@@ -457,25 +470,38 @@ rx_streamer::sptr e300_impl::get_rx_stream(const uhd::stream_args_t &args_)
id.num_outputs = 1;
my_streamer->set_converter(id);
+ perif.framer->clear();
perif.framer->set_nsamps_per_packet(spp); //seems to be a good place to set this
perif.framer->set_sid((data_sid << 16) | (data_sid >> 16));
perif.framer->setup(args);
perif.ddc->setup(args);
+
+ // flow control setup
+ const size_t frame_size = data_xports.recv->get_recv_frame_size();
+ const size_t num_frames = data_xports.recv->get_num_recv_frames();
+ const size_t fc_window = get_rx_flow_control_window(
+ frame_size,num_frames * frame_size,
+ E300_RX_SW_BUFF_FULLNESS);
+ const size_t fc_handle_window = std::max<size_t>(1, fc_window / E300_RX_FC_REQUEST_FREQ);
+
+ UHD_LOG << "RX Flow Control Window = " << fc_window
+ << ", RX Flow Control Handler Window = "
+ << fc_handle_window << std::endl;
+
+ perif.framer->configure_flow_control(fc_window);
+ boost::shared_ptr<e300_rx_fc_cache_t> fc_cache(new e300_rx_fc_cache_t());
+
my_streamer->set_xport_chan_get_buff(stream_i, boost::bind(
&zero_copy_if::get_recv_buff, data_xports.recv, _1
), true /*flush*/);
my_streamer->set_overflow_handler(stream_i,
- boost::bind(&rx_vita_core_3000::handle_overflow, perif.framer)
+ boost::bind(&e300_impl::_handle_overflow, this, boost::ref(perif),
+ boost::weak_ptr<uhd::rx_streamer>(my_streamer))
);
- //setup flow control
- const size_t fc_window = data_xports.recv->get_num_recv_frames();
- perif.framer->configure_flow_control(fc_window);
- boost::shared_ptr<e300_rx_fc_cache_t> fc_cache(new e300_rx_fc_cache_t());
my_streamer->set_xport_handle_flowctrl(stream_i,
boost::bind(&handle_rx_flowctrl, data_sid, data_xports.send, fc_cache, _1),
- static_cast<size_t>(static_cast<double>(fc_window) * E300_RX_SW_BUFF_FULLNESS),
- true/*init*/);
+ fc_handle_window, true/*init*/);
my_streamer->set_issue_stream_cmd(stream_i,
boost::bind(&rx_vita_core_3000::issue_stream_command, perif.framer, _1)
@@ -564,7 +590,13 @@ tx_streamer::sptr e300_impl::get_tx_stream(const uhd::stream_args_t &args_)
//flow control setup
const size_t fc_window = data_xports.send->get_num_send_frames();
- perif.deframer->configure_flow_control(0/*cycs off*/, fc_window/8/*pkts*/);
+ const size_t fc_handle_window = std::max<size_t>(1, fc_window/E300_TX_FC_RESPONSE_FREQ);
+
+ UHD_LOG << "TX Flow Control Window = " << fc_window
+ << ", TX Flow Control Handler Window = "
+ << fc_handle_window << std::endl;
+
+ perif.deframer->configure_flow_control(0/*cycs off*/, fc_handle_window/*pkts*/);
boost::shared_ptr<e300_tx_fc_cache_t> fc_cache(new e300_tx_fc_cache_t());
fc_cache->stream_channel = stream_i;
fc_cache->device_channel = args.channels[stream_i];
diff --git a/host/lib/usrp/e300/e300_network.cpp b/host/lib/usrp/e300/e300_network.cpp
index bb904773b..cb06a5740 100644
--- a/host/lib/usrp/e300/e300_network.cpp
+++ b/host/lib/usrp/e300/e300_network.cpp
@@ -227,6 +227,24 @@ static void e300_codec_ctrl_tunnel(
case codec_xact_t::ACTION_GET_RSSI:
out->rssi = _codec_ctrl->get_rssi(which_str).to_real();
break;
+ case codec_xact_t::ACTION_GET_TEMPERATURE:
+ out->temp = _codec_ctrl->get_temperature().to_real();
+ break;
+ case codec_xact_t::ACTION_SET_DC_OFFSET_AUTO:
+ _codec_ctrl->set_dc_offset_auto(which_str, in->use_dc_correction == 1);
+ break;
+ case codec_xact_t::ACTION_SET_IQ_BALANCE_AUTO:
+ _codec_ctrl->set_iq_balance_auto(which_str, in->use_iq_correction == 1);
+ case codec_xact_t::ACTION_SET_AGC:
+ _codec_ctrl->set_agc(which_str, in->use_agc == 1);
+ break;
+ case codec_xact_t::ACTION_SET_AGC_MODE:
+ if(in->agc_mode == 0) {
+ _codec_ctrl->set_agc_mode(which_str, "slow");
+ } else if (in->agc_mode == 1) {
+ _codec_ctrl->set_agc_mode(which_str, "fast");
+ }
+ break;
default:
UHD_MSG(status) << "Got unknown request?!" << std::endl;
//Zero out actions to fail this request on client
diff --git a/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp b/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp
index ed8131e2f..871885a7b 100644
--- a/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp
+++ b/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp
@@ -116,10 +116,84 @@ public:
_args.bits = uhd::htonx<boost::uint32_t>(0);
_transact();
-
return sensor_value_t("RSSI", _retval.rssi, "dB");
}
+ sensor_value_t get_temperature()
+ {
+ _clear();
+ _args.action = uhd::htonx<boost::uint32_t>(transaction_t::ACTION_GET_TEMPERATURE);
+ _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_NONE); /*Unused*/
+ _args.bits = uhd::htonx<boost::uint32_t>(0);
+
+ _transact();
+ return sensor_value_t("temp", _retval.temp, "C");
+ }
+
+ void set_dc_offset_auto(const std::string &which, const bool on)
+ {
+ _clear();
+ _args.action = uhd::htonx<boost::uint32_t>(transaction_t::ACTION_SET_DC_OFFSET_AUTO);
+ if (which == "TX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX1);
+ else if (which == "TX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX2);
+ else if (which == "RX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX1);
+ else if (which == "RX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX2);
+ else throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect chain string.");
+ _args.use_dc_correction = on ? 1 : 0;
+
+ _transact();
+ }
+
+ void set_iq_balance_auto(const std::string &which, const bool on)
+ {
+ _clear();
+ _args.action = uhd::htonx<boost::uint32_t>(transaction_t::ACTION_SET_IQ_BALANCE_AUTO);
+ if (which == "TX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX1);
+ else if (which == "TX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX2);
+ else if (which == "RX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX1);
+ else if (which == "RX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX2);
+ else throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect chain string.");
+ _args.use_iq_correction = on ? 1 : 0;
+
+ _transact();
+ }
+
+ void set_agc(const std::string &which, bool enable)
+ {
+ _clear();
+ _args.action = uhd::htonx<boost::uint32_t>(transaction_t::ACTION_SET_AGC);
+ if (which == "TX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX1);
+ else if (which == "TX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX2);
+ else if (which == "RX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX1);
+ else if (which == "RX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX2);
+ else throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect chain string.");
+ _args.use_agc = enable ? 1 : 0;
+
+ _transact();
+ }
+
+ void set_agc_mode(const std::string &which, const std::string &mode)
+ {
+ _clear();
+ _args.action = uhd::htonx<boost::uint32_t>(transaction_t::ACTION_SET_AGC_MODE);
+
+ if (which == "TX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX1);
+ else if (which == "TX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX2);
+ else if (which == "RX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX1);
+ else if (which == "RX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX2);
+ else throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect chain string.");
+
+ if(mode == "slow") {
+ _args.agc_mode = 0;
+ } else if (mode == "fast") {
+ _args.agc_mode = 1;
+ } else {
+ throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect agc mode.");
+ }
+
+ _transact();
+ }
+
private:
void _transact() {
{
diff --git a/host/lib/usrp/e300/e300_remote_codec_ctrl.hpp b/host/lib/usrp/e300/e300_remote_codec_ctrl.hpp
index cbc4b52d2..459d0ec55 100644
--- a/host/lib/usrp/e300/e300_remote_codec_ctrl.hpp
+++ b/host/lib/usrp/e300/e300_remote_codec_ctrl.hpp
@@ -34,6 +34,11 @@ public:
double gain;
double freq;
double rssi;
+ double temp;
+ boost::uint32_t use_dc_correction;
+ boost::uint32_t use_iq_correction;
+ boost::uint32_t use_agc;
+ boost::uint32_t agc_mode;
boost::uint64_t bits;
};
@@ -44,6 +49,11 @@ public:
static const boost::uint32_t ACTION_TUNE = 13;
static const boost::uint32_t ACTION_SET_LOOPBACK = 14;
static const boost::uint32_t ACTION_GET_RSSI = 15;
+ static const boost::uint32_t ACTION_GET_TEMPERATURE = 16;
+ static const boost::uint32_t ACTION_SET_DC_OFFSET_AUTO = 17;
+ static const boost::uint32_t ACTION_SET_IQ_BALANCE_AUTO = 18;
+ static const boost::uint32_t ACTION_SET_AGC = 19;
+ static const boost::uint32_t ACTION_SET_AGC_MODE = 20;
//Values for "which"
static const boost::uint32_t CHAIN_NONE = 0;
diff --git a/host/lib/usrp/e300/e300_sensor_manager.hpp b/host/lib/usrp/e300/e300_sensor_manager.hpp
index 9c060b19a..09f889251 100644
--- a/host/lib/usrp/e300/e300_sensor_manager.hpp
+++ b/host/lib/usrp/e300/e300_sensor_manager.hpp
@@ -62,7 +62,7 @@ public:
// Note: This is a hack
static boost::uint32_t pack_float_in_uint32_t(const float &v)
{
- const boost::uint32_t *cast = reinterpret_cast<const uint32_t*>(&v);
+ const boost::uint32_t *cast = reinterpret_cast<const boost::uint32_t*>(&v);
return *cast;
}
diff --git a/host/lib/usrp/e300/e300_spi.cpp b/host/lib/usrp/e300/e300_spi.cpp
index 9a2daf4a7..2722d7f53 100644
--- a/host/lib/usrp/e300/e300_spi.cpp
+++ b/host/lib/usrp/e300/e300_spi.cpp
@@ -82,13 +82,13 @@ public:
int ret(0);
struct spi_ioc_transfer tr;
- uint8_t *tx_data = reinterpret_cast<uint8_t *>(&data);
+ boost::uint8_t *tx_data = reinterpret_cast<boost::uint8_t *>(&data);
UHD_ASSERT_THROW(num_bits == 24);
- uint8_t tx[] = {tx_data[2], tx_data[1], tx_data[0]};
+ boost::uint8_t tx[] = {tx_data[2], tx_data[1], tx_data[0]};
- uint8_t rx[3];
+ boost::uint8_t rx[3];
tr.tx_buf = (unsigned long) &tx[0];
tr.rx_buf = (unsigned long) &rx[0];
tr.len = num_bits >> 3;
diff --git a/host/lib/usrp/e300/e300_ublox_control_impl.cpp b/host/lib/usrp/e300/e300_ublox_control_impl.cpp
index a0ec10271..0f56fdb67 100644
--- a/host/lib/usrp/e300/e300_ublox_control_impl.cpp
+++ b/host/lib/usrp/e300/e300_ublox_control_impl.cpp
@@ -498,7 +498,7 @@ control::sptr control::make(const std::string &node, const size_t baud_rate)
#else
using namespace uhd::usrp::gps::ublox::ubx;
-control::sptr control::make(const std::string &node, const size_t baud_rate)
+control::sptr control::make(const std::string& /* node */, const size_t /* baud_rate */)
{
throw uhd::assertion_error("control::sptr::make: !E300_NATIVE");
}
diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp
index 175633c4c..1866255c9 100644
--- a/host/lib/usrp/multi_usrp.cpp
+++ b/host/lib/usrp/multi_usrp.cpp
@@ -30,6 +30,8 @@
#include <boost/thread.hpp>
#include <boost/foreach.hpp>
#include <boost/format.hpp>
+#include <boost/algorithm/string.hpp>
+#include <algorithm>
#include <cmath>
using namespace uhd;
@@ -431,6 +433,9 @@ public:
******************************************************************/
void set_master_clock_rate(double rate, size_t mboard){
if (mboard != ALL_MBOARDS){
+ if (_tree->exists(mb_root(mboard) / "auto_tick_rate")) {
+ _tree->access<bool>(mb_root(mboard) / "auto_tick_rate").set(false);
+ }
_tree->access<double>(mb_root(mboard) / "tick_rate").set(rate);
return;
}
@@ -821,25 +826,86 @@ public:
}
void set_rx_gain(double gain, const std::string &name, size_t chan){
+ /* Check if any AGC mode is enable and if so warn the user */
+ if (chan != ALL_CHANS) {
+ if (_tree->exists(rx_rf_fe_root(chan) / "gain" / "agc")) {
+ bool agc = _tree->access<bool>(rx_rf_fe_root(chan) / "gain" / "agc" / "enable").get();
+ if(agc) {
+ UHD_MSG(warning) << "AGC enabled for this channel. Setting will be ignored." << std::endl;
+ }
+ }
+ } else {
+ for (size_t c = 0; c < get_rx_num_channels(); c++){
+ if (_tree->exists(rx_rf_fe_root(c) / "gain" / "agc")) {
+ bool agc = _tree->access<bool>(rx_rf_fe_root(chan) / "gain" / "agc" / "enable").get();
+ if(agc) {
+ UHD_MSG(warning) << "AGC enabled for this channel. Setting will be ignored." << std::endl;
+ }
+ }
+ }
+ }
+ /* Apply gain setting.
+ * If device is in AGC mode it will ignore the setting. */
try {
return rx_gain_group(chan)->set_value(gain, name);
- } catch (uhd::key_error &e) {
+ } catch (uhd::key_error &) {
THROW_GAIN_NAME_ERROR(name,chan,rx);
}
}
+ void set_normalized_rx_gain(double gain, size_t chan = 0)
+ {
+ if (gain > 1.0 || gain < 0.0) {
+ throw uhd::runtime_error("Normalized gain out of range, must be in [0, 1].");
+ }
+ gain_range_t gain_range = get_rx_gain_range(ALL_GAINS, chan);
+ double abs_gain = (gain * (gain_range.stop() - gain_range.start())) + gain_range.start();
+ set_rx_gain(abs_gain, ALL_GAINS, chan);
+ }
+
+ void set_rx_agc(bool enable, size_t chan = 0)
+ {
+ if (chan != ALL_CHANS){
+ if (_tree->exists(rx_rf_fe_root(chan) / "gain" / "agc" / "enable")) {
+ _tree->access<bool>(rx_rf_fe_root(chan) / "gain" / "agc" / "enable").set(enable);
+ } else {
+ UHD_MSG(warning) << "AGC is not available on this device." << std::endl;
+ }
+ return;
+ }
+ for (size_t c = 0; c < get_rx_num_channels(); c++){
+ this->set_rx_agc(enable, c);
+ }
+
+ }
+
double get_rx_gain(const std::string &name, size_t chan){
try {
return rx_gain_group(chan)->get_value(name);
- } catch (uhd::key_error &e) {
+ } catch (uhd::key_error &) {
THROW_GAIN_NAME_ERROR(name,chan,rx);
}
}
+ double get_normalized_rx_gain(size_t chan)
+ {
+ gain_range_t gain_range = get_rx_gain_range(ALL_GAINS, chan);
+ double gain_range_width = gain_range.stop() - gain_range.start();
+ // In case we have a device without a range of gains:
+ if (gain_range_width == 0.0) {
+ return 0;
+ }
+ double norm_gain = (get_rx_gain(ALL_GAINS, chan) - gain_range.start()) / gain_range_width;
+ // Avoid rounding errors:
+ if (norm_gain > 1.0) return 1.0;
+ if (norm_gain < 0.0) return 0.0;
+ return norm_gain;
+ }
+
gain_range_t get_rx_gain_range(const std::string &name, size_t chan){
try {
return rx_gain_group(chan)->get_range(name);
- } catch (uhd::key_error &e) {
+ } catch (uhd::key_error &) {
THROW_GAIN_NAME_ERROR(name,chan,rx);
}
}
@@ -888,6 +954,9 @@ public:
if (chan != ALL_CHANS){
if (_tree->exists(rx_fe_root(chan) / "dc_offset" / "enable")) {
_tree->access<bool>(rx_fe_root(chan) / "dc_offset" / "enable").set(enb);
+ } else if (_tree->exists(rx_rf_fe_root(chan) / "dc_offset" / "enable")) {
+ /*For B2xx devices the dc-offset correction is implemented in the rf front-end*/
+ _tree->access<bool>(rx_rf_fe_root(chan) / "dc_offset" / "enable").set(enb);
} else {
UHD_MSG(warning) << "Setting DC offset compensation is not possible on this device." << std::endl;
}
@@ -912,6 +981,20 @@ public:
}
}
+ void set_rx_iq_balance(const bool enb, size_t chan){
+ if (chan != ALL_CHANS){
+ if (_tree->exists(rx_rf_fe_root(chan) / "iq_balance" / "enable")) {
+ _tree->access<bool>(rx_rf_fe_root(chan) / "iq_balance" / "enable").set(enb);
+ } else {
+ UHD_MSG(warning) << "Setting IQ imbalance compensation is not possible on this device." << std::endl;
+ }
+ return;
+ }
+ for (size_t c = 0; c < get_rx_num_channels(); c++){
+ this->set_rx_iq_balance(enb, c);
+ }
+ }
+
void set_rx_iq_balance(const std::complex<double> &offset, size_t chan){
if (chan != ALL_CHANS){
if (_tree->exists(rx_fe_root(chan) / "iq_balance" / "value")) {
@@ -926,6 +1009,87 @@ public:
}
}
+ std::vector<std::string> get_filter_names(const std::string &search_mask)
+ {
+ std::vector<std::string> ret;
+
+ for (size_t chan = 0; chan < get_rx_num_channels(); chan++){
+
+ if (_tree->exists(rx_rf_fe_root(chan) / "filters")) {
+ std::vector<std::string> names = _tree->list(rx_rf_fe_root(chan) / "filters");
+ for(size_t i = 0; i < names.size(); i++)
+ {
+ std::string name = rx_rf_fe_root(chan) / "filters" / names[i];
+ if((search_mask.empty()) or boost::contains(name, search_mask)) {
+ ret.push_back(name);
+ }
+ }
+ }
+ if (_tree->exists(rx_dsp_root(chan) / "filters")) {
+ std::vector<std::string> names = _tree->list(rx_dsp_root(chan) / "filters");
+ for(size_t i = 0; i < names.size(); i++)
+ {
+ std::string name = rx_dsp_root(chan) / "filters" / names[i];
+ if((search_mask.empty()) or (boost::contains(name, search_mask))) {
+ ret.push_back(name);
+ }
+ }
+ }
+
+ }
+
+ for (size_t chan = 0; chan < get_tx_num_channels(); chan++){
+
+ if (_tree->exists(tx_rf_fe_root(chan) / "filters")) {
+ std::vector<std::string> names = _tree->list(tx_rf_fe_root(chan) / "filters");
+ for(size_t i = 0; i < names.size(); i++)
+ {
+ std::string name = tx_rf_fe_root(chan) / "filters" / names[i];
+ if((search_mask.empty()) or (boost::contains(name, search_mask))) {
+ ret.push_back(name);
+ }
+ }
+ }
+ if (_tree->exists(rx_dsp_root(chan) / "filters")) {
+ std::vector<std::string> names = _tree->list(tx_dsp_root(chan) / "filters");
+ for(size_t i = 0; i < names.size(); i++)
+ {
+ std::string name = tx_dsp_root(chan) / "filters" / names[i];
+ if((search_mask.empty()) or (boost::contains(name, search_mask))) {
+ ret.push_back(name);
+ }
+ }
+ }
+
+ }
+
+ return ret;
+ }
+
+ filter_info_base::sptr get_filter(const std::string &path)
+ {
+ std::vector<std::string> possible_names = get_filter_names("");
+ std::vector<std::string>::iterator it;
+ it = find(possible_names.begin(), possible_names.end(), path);
+ if (it == possible_names.end()) {
+ throw uhd::runtime_error("Attempting to get non-existing filter: "+path);
+ }
+
+ return _tree->access<filter_info_base::sptr>(path / "value").get();
+ }
+
+ void set_filter(const std::string &path, filter_info_base::sptr filter)
+ {
+ std::vector<std::string> possible_names = get_filter_names("");
+ std::vector<std::string>::iterator it;
+ it = find(possible_names.begin(), possible_names.end(), path);
+ if (it == possible_names.end()) {
+ throw uhd::runtime_error("Attempting to set non-existing filter: "+path);
+ }
+
+ _tree->access<filter_info_base::sptr>(path / "value").set(filter);
+ }
+
/*******************************************************************
* TX methods
******************************************************************/
@@ -1024,23 +1188,49 @@ public:
void set_tx_gain(double gain, const std::string &name, size_t chan){
try {
return tx_gain_group(chan)->set_value(gain, name);
- } catch (uhd::key_error &e) {
+ } catch (uhd::key_error &) {
THROW_GAIN_NAME_ERROR(name,chan,tx);
}
}
+ void set_normalized_tx_gain(double gain, size_t chan = 0)
+ {
+ if (gain > 1.0 || gain < 0.0) {
+ throw uhd::runtime_error("Normalized gain out of range, must be in [0, 1].");
+ }
+ gain_range_t gain_range = get_tx_gain_range(ALL_GAINS, chan);
+ double abs_gain = (gain * (gain_range.stop() - gain_range.start())) + gain_range.start();
+ set_tx_gain(abs_gain, ALL_GAINS, chan);
+ }
+
+
double get_tx_gain(const std::string &name, size_t chan){
try {
return tx_gain_group(chan)->get_value(name);
- } catch (uhd::key_error &e) {
+ } catch (uhd::key_error &) {
THROW_GAIN_NAME_ERROR(name,chan,tx);
}
}
+ double get_normalized_tx_gain(size_t chan)
+ {
+ gain_range_t gain_range = get_tx_gain_range(ALL_GAINS, chan);
+ double gain_range_width = gain_range.stop() - gain_range.start();
+ // In case we have a device without a range of gains:
+ if (gain_range_width == 0.0) {
+ return 0.0;
+ }
+ double norm_gain = (get_rx_gain(ALL_GAINS, chan) - gain_range.start()) / gain_range_width;
+ // Avoid rounding errors:
+ if (norm_gain > 1.0) return 1.0;
+ if (norm_gain < 0.0) return 0.0;
+ return norm_gain;
+ }
+
gain_range_t get_tx_gain_range(const std::string &name, size_t chan){
try {
return tx_gain_group(chan)->get_range(name);
- } catch (uhd::key_error &e) {
+ } catch (uhd::key_error &) {
THROW_GAIN_NAME_ERROR(name,chan,tx);
}
}
@@ -1162,7 +1352,7 @@ public:
{
if (_tree->exists(mb_root(mboard) / "gpio" / bank))
{
- return _tree->access<boost::uint64_t>(mb_root(mboard) / "gpio" / bank / attr).get();
+ return boost::uint32_t(_tree->access<boost::uint64_t>(mb_root(mboard) / "gpio" / bank / attr).get());
}
if (bank.size() > 2 and bank[1] == 'X')
{
diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp
index 9ee6abed0..81be97fa5 100644
--- a/host/lib/usrp/usrp2/io_impl.cpp
+++ b/host/lib/usrp/usrp2/io_impl.cpp
@@ -239,7 +239,8 @@ void usrp2_impl::io_init(void){
//init the tx xport and flow control monitor
_io_impl->tx_xports.push_back(_mbc[mb].tx_dsp_xport);
_io_impl->fc_mons.push_back(flow_control_monitor::sptr(new flow_control_monitor(
- USRP2_SRAM_BYTES/_mbc[mb].tx_dsp_xport->get_send_frame_size()
+ device_addr.cast("send_buff_size", USRP2_SRAM_BYTES) /
+ _mbc[mb].tx_dsp_xport->get_send_frame_size()
)));
}
diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp
index 65cf90a17..2f2c345be 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.cpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.cpp
@@ -387,7 +387,7 @@ public:
//create the burner commands
if (this->get_rev() == USRP2_REV3 or this->get_rev() == USRP2_REV4){
- 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 = (fs::path(uhd::get_pkg_path()) / UHD_LIB_DIR / "uhd" / "utils" / "usrp2_card_burner_gui.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_utility_error("uhd_images_downloader.py") % card_burner_cmd);
}
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index 16e8a1f22..50b8431a1 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -316,9 +316,10 @@ static zero_copy_if::sptr make_xport(
/***********************************************************************
* Structors
**********************************************************************/
-usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){
+usrp2_impl::usrp2_impl(const device_addr_t &_device_addr) :
+ device_addr(_device_addr)
+{
UHD_MSG(status) << "Opening a USRP2/N-Series device..." << std::endl;
- device_addr_t device_addr = _device_addr;
//setup the dsp transport hints (default to a large recv buff)
if (not device_addr.has_key("recv_buff_size")){
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
index edbb7888b..fac4b3907 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -116,6 +116,7 @@ private:
bool _ignore_cal_file;
//io impl methods and members
+ uhd::device_addr_t device_addr;
UHD_PIMPL_DECL(io_impl) _io_impl;
void io_init(void);
void update_tick_rate(const double rate);
diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp
index e35f73eab..d9b27b6b4 100644
--- a/host/lib/usrp/x300/x300_impl.cpp
+++ b/host/lib/usrp/x300/x300_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2013-2014 Ettus Research LLC
+// Copyright 2013-2015 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
@@ -41,7 +41,7 @@
#define NIUSRPRIO_DEFAULT_RPC_PORT "5444"
-#define X300_REV(x) (x - "A" + 1)
+#define X300_REV(x) ((x) - "A" + 1)
using namespace uhd;
using namespace uhd::usrp;
@@ -695,15 +695,14 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)
// front panel gpio
////////////////////////////////////////////////////////////////////
mb.fp_gpio = gpio_core_200::make(mb.radio_perifs[0].ctrl, TOREG(SR_FP_GPIO), RB32_FP_GPIO);
- const std::vector<std::string> GPIO_ATTRS = boost::assign::list_of("CTRL")("DDR")("OUT")("ATR_0X")("ATR_RX")("ATR_TX")("ATR_XX");
- BOOST_FOREACH(const std::string &attr, GPIO_ATTRS)
+ BOOST_FOREACH(const gpio_attr_map_t::value_type attr, gpio_attr_map)
{
- _tree->create<boost::uint32_t>(mb_path / "gpio" / "FP0" / attr)
+ _tree->create<boost::uint32_t>(mb_path / "gpio" / "FP0" / attr.second)
.set(0)
- .subscribe(boost::bind(&x300_impl::set_fp_gpio, this, mb.fp_gpio, attr, _1));
+ .subscribe(boost::bind(&x300_impl::set_fp_gpio, this, mb.fp_gpio, attr.first, _1));
}
_tree->create<boost::uint32_t>(mb_path / "gpio" / "FP0" / "READBACK")
- .publish(boost::bind(&x300_impl::get_fp_gpio, this, mb.fp_gpio, "READBACK"));
+ .publish(boost::bind(&x300_impl::get_fp_gpio, this, mb.fp_gpio));
////////////////////////////////////////////////////////////////////
// register the time keepers - only one can be the highlander
@@ -1353,7 +1352,7 @@ void x300_impl::set_time_source_out(mboard_members_t &mb, const bool enb)
void x300_impl::update_clock_source(mboard_members_t &mb, const std::string &source)
{
//Optimize for the case when the current source is internal and we are trying
- //to set it to internal. This is the only case where we are guaranteed that
+ //to set it to internal. This is the only case where we are guaranteed that
//the clock has not gone away so we can skip setting the MUX and reseting the LMK.
if (not (mb.current_refclk_src == "internal" and source == "internal")) {
//Update the clock MUX on the motherboard to select the requested source
@@ -1432,8 +1431,8 @@ bool x300_impl::wait_for_ref_locked(wb_iface::sptr ctrl, double timeout)
boost::this_thread::sleep(boost::posix_time::milliseconds(1));
} while (boost::get_system_time() < timeout_time);
- //failed to lock on reference
- return false;
+ //Check one last time
+ return get_ref_locked(ctrl).to_bool();
}
sensor_value_t x300_impl::get_ref_locked(wb_iface::sptr ctrl)
@@ -1534,20 +1533,24 @@ void x300_impl::set_mb_eeprom(i2c_iface::sptr i2c, const mboard_eeprom_t &mb_eep
* front-panel GPIO
**********************************************************************/
-boost::uint32_t x300_impl::get_fp_gpio(gpio_core_200::sptr gpio, const std::string &)
+boost::uint32_t x300_impl::get_fp_gpio(gpio_core_200::sptr gpio)
{
return boost::uint32_t(gpio->read_gpio(dboard_iface::UNIT_RX));
}
-void x300_impl::set_fp_gpio(gpio_core_200::sptr gpio, const std::string &attr, const boost::uint32_t value)
+void x300_impl::set_fp_gpio(gpio_core_200::sptr gpio, const gpio_attr_t attr, const boost::uint32_t value)
{
- if (attr == "CTRL") return gpio->set_pin_ctrl(dboard_iface::UNIT_RX, value);
- if (attr == "DDR") return gpio->set_gpio_ddr(dboard_iface::UNIT_RX, value);
- if (attr == "OUT") return gpio->set_gpio_out(dboard_iface::UNIT_RX, value);
- if (attr == "ATR_0X") return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, value);
- if (attr == "ATR_RX") return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, value);
- if (attr == "ATR_TX") return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, value);
- if (attr == "ATR_XX") return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, value);
+ switch (attr)
+ {
+ case GPIO_CTRL: return gpio->set_pin_ctrl(dboard_iface::UNIT_RX, value);
+ case GPIO_DDR: return gpio->set_gpio_ddr(dboard_iface::UNIT_RX, value);
+ case GPIO_OUT: return gpio->set_gpio_out(dboard_iface::UNIT_RX, value);
+ case GPIO_ATR_0X: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, value);
+ case GPIO_ATR_RX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, value);
+ case GPIO_ATR_TX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, value);
+ case GPIO_ATR_XX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, value);
+ default: UHD_THROW_INVALID_CODE_PATH();
+ }
}
/***********************************************************************
@@ -1720,14 +1723,20 @@ x300_impl::x300_mboard_t x300_impl::get_mb_type_from_pcie(const std::string& res
case X300_USRP_PCIE_SSID:
mb_type = USRP_X300_MB; break;
case X310_USRP_PCIE_SSID:
- case X310_2940R_PCIE_SSID:
- case X310_2942R_PCIE_SSID:
- case X310_2943R_PCIE_SSID:
- case X310_2944R_PCIE_SSID:
- case X310_2950R_PCIE_SSID:
- case X310_2952R_PCIE_SSID:
- case X310_2953R_PCIE_SSID:
- case X310_2954R_PCIE_SSID:
+ case X310_2940R_40MHz_PCIE_SSID:
+ case X310_2940R_120MHz_PCIE_SSID:
+ case X310_2942R_40MHz_PCIE_SSID:
+ case X310_2942R_120MHz_PCIE_SSID:
+ case X310_2943R_40MHz_PCIE_SSID:
+ case X310_2943R_120MHz_PCIE_SSID:
+ case X310_2944R_40MHz_PCIE_SSID:
+ case X310_2950R_40MHz_PCIE_SSID:
+ case X310_2950R_120MHz_PCIE_SSID:
+ case X310_2952R_40MHz_PCIE_SSID:
+ case X310_2952R_120MHz_PCIE_SSID:
+ case X310_2953R_40MHz_PCIE_SSID:
+ case X310_2953R_120MHz_PCIE_SSID:
+ case X310_2954R_40MHz_PCIE_SSID:
mb_type = USRP_X310_MB; break;
default:
mb_type = UNKNOWN; break;
@@ -1755,14 +1764,20 @@ x300_impl::x300_mboard_t x300_impl::get_mb_type_from_eeprom(const uhd::usrp::mbo
case X300_USRP_PCIE_SSID:
mb_type = USRP_X300_MB; break;
case X310_USRP_PCIE_SSID:
- case X310_2940R_PCIE_SSID:
- case X310_2942R_PCIE_SSID:
- case X310_2943R_PCIE_SSID:
- case X310_2944R_PCIE_SSID:
- case X310_2950R_PCIE_SSID:
- case X310_2952R_PCIE_SSID:
- case X310_2953R_PCIE_SSID:
- case X310_2954R_PCIE_SSID:
+ case X310_2940R_40MHz_PCIE_SSID:
+ case X310_2940R_120MHz_PCIE_SSID:
+ case X310_2942R_40MHz_PCIE_SSID:
+ case X310_2942R_120MHz_PCIE_SSID:
+ case X310_2943R_40MHz_PCIE_SSID:
+ case X310_2943R_120MHz_PCIE_SSID:
+ case X310_2944R_40MHz_PCIE_SSID:
+ case X310_2950R_40MHz_PCIE_SSID:
+ case X310_2950R_120MHz_PCIE_SSID:
+ case X310_2952R_40MHz_PCIE_SSID:
+ case X310_2952R_120MHz_PCIE_SSID:
+ case X310_2953R_40MHz_PCIE_SSID:
+ case X310_2953R_120MHz_PCIE_SSID:
+ case X310_2954R_40MHz_PCIE_SSID:
mb_type = USRP_X310_MB; break;
default:
UHD_MSG(warning) << "X300 unknown product code in EEPROM: " << product_num << std::endl;
diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp
index 70c5dccb4..9ad060c85 100644
--- a/host/lib/usrp/x300/x300_impl.hpp
+++ b/host/lib/usrp/x300/x300_impl.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2013-2014 Ettus Research LLC
+// Copyright 2013-2015 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
@@ -360,8 +360,8 @@ private:
void check_fpga_compat(const uhd::fs_path &mb_path, uhd::wb_iface::sptr iface);
void update_atr_leds(gpio_core_200_32wo::sptr, const std::string &ant);
- boost::uint32_t get_fp_gpio(gpio_core_200::sptr, const std::string &);
- void set_fp_gpio(gpio_core_200::sptr, const std::string &, const boost::uint32_t);
+ boost::uint32_t get_fp_gpio(gpio_core_200::sptr);
+ void set_fp_gpio(gpio_core_200::sptr, const gpio_attr_t, const boost::uint32_t);
//**PRECONDITION**
//This function assumes that all the VITA times in "radios" are synchronized
diff --git a/host/lib/usrp/x300/x300_io_impl.cpp b/host/lib/usrp/x300/x300_io_impl.cpp
index 334ae8168..e3515af0c 100644
--- a/host/lib/usrp/x300/x300_io_impl.cpp
+++ b/host/lib/usrp/x300/x300_io_impl.cpp
@@ -23,6 +23,7 @@
#include <uhd/transport/nirio_zero_copy.hpp>
#include "async_packet_handler.hpp"
#include <uhd/transport/bounded_buffer.hpp>
+#include <uhd/transport/chdr.hpp>
#include <boost/bind.hpp>
#include <uhd/utils/tasks.hpp>
#include <uhd/utils/log.hpp>
@@ -124,41 +125,6 @@ void x300_impl::update_subdev_spec(const std::string &tx_rx, const size_t mb_i,
/***********************************************************************
- * VITA stuff
- **********************************************************************/
-static void x300_if_hdr_unpack_be(
- const boost::uint32_t *packet_buff,
- vrt::if_packet_info_t &if_packet_info
-){
- if_packet_info.link_type = vrt::if_packet_info_t::LINK_TYPE_CHDR;
- return vrt::if_hdr_unpack_be(packet_buff, if_packet_info);
-}
-
-static void x300_if_hdr_pack_be(
- boost::uint32_t *packet_buff,
- vrt::if_packet_info_t &if_packet_info
-){
- if_packet_info.link_type = vrt::if_packet_info_t::LINK_TYPE_CHDR;
- return vrt::if_hdr_pack_be(packet_buff, if_packet_info);
-}
-
-static void x300_if_hdr_unpack_le(
- const boost::uint32_t *packet_buff,
- vrt::if_packet_info_t &if_packet_info
-){
- if_packet_info.link_type = vrt::if_packet_info_t::LINK_TYPE_CHDR;
- return vrt::if_hdr_unpack_le(packet_buff, if_packet_info);
-}
-
-static void x300_if_hdr_pack_le(
- boost::uint32_t *packet_buff,
- vrt::if_packet_info_t &if_packet_info
-){
- if_packet_info.link_type = vrt::if_packet_info_t::LINK_TYPE_CHDR;
- return vrt::if_hdr_pack_le(packet_buff, if_packet_info);
-}
-
-/***********************************************************************
* RX flow control handler
**********************************************************************/
static size_t get_rx_flow_control_window(size_t frame_size, size_t sw_buff_size, const device_addr_t& rx_args)
@@ -209,9 +175,9 @@ static void handle_rx_flowctrl(const boost::uint32_t sid, zero_copy_if::sptr xpo
//load header
if (big_endian)
- x300_if_hdr_pack_be(pkt, packet_info);
+ vrt::chdr::if_hdr_pack_be(pkt, packet_info);
else
- x300_if_hdr_pack_le(pkt, packet_info);
+ vrt::chdr::if_hdr_pack_le(pkt, packet_info);
//load payload
pkt[packet_info.num_header_words32+0] = uhd::htonx<boost::uint32_t>(0);
@@ -276,12 +242,12 @@ static void handle_tx_async_msgs(boost::shared_ptr<x300_tx_fc_guts_t> guts, zero
{
if (big_endian)
{
- x300_if_hdr_unpack_be(packet_buff, if_packet_info);
+ vrt::chdr::if_hdr_unpack_be(packet_buff, if_packet_info);
endian_conv = uhd::ntohx;
}
else
{
- x300_if_hdr_unpack_le(packet_buff, if_packet_info);
+ vrt::chdr::if_hdr_unpack_le(packet_buff, if_packet_info);
endian_conv = uhd::wtohx;
}
}
@@ -430,10 +396,10 @@ rx_streamer::sptr x300_impl::get_rx_stream(const uhd::stream_args_t &args_)
//init some streamer stuff
std::string conv_endianness;
if (mb.if_pkt_is_big_endian) {
- my_streamer->set_vrt_unpacker(&x300_if_hdr_unpack_be);
+ my_streamer->set_vrt_unpacker(&vrt::chdr::if_hdr_unpack_be);
conv_endianness = "be";
} else {
- my_streamer->set_vrt_unpacker(&x300_if_hdr_unpack_le);
+ my_streamer->set_vrt_unpacker(&vrt::chdr::if_hdr_unpack_le);
conv_endianness = "le";
}
@@ -594,10 +560,10 @@ tx_streamer::sptr x300_impl::get_tx_stream(const uhd::stream_args_t &args_)
std::string conv_endianness;
if (mb.if_pkt_is_big_endian) {
- my_streamer->set_vrt_packer(&x300_if_hdr_pack_be);
+ my_streamer->set_vrt_packer(&vrt::chdr::if_hdr_pack_be);
conv_endianness = "be";
} else {
- my_streamer->set_vrt_packer(&x300_if_hdr_pack_le);
+ my_streamer->set_vrt_packer(&vrt::chdr::if_hdr_pack_le);
conv_endianness = "le";
}
diff --git a/host/lib/usrp/x300/x300_regs.hpp b/host/lib/usrp/x300/x300_regs.hpp
index f920b5ae2..4c5729efe 100644
--- a/host/lib/usrp/x300/x300_regs.hpp
+++ b/host/lib/usrp/x300/x300_regs.hpp
@@ -25,40 +25,40 @@
#define localparam static const int
-localparam SR_DACSYNC = 5;
-localparam SR_LOOPBACK = 6;
-localparam SR_TEST = 7;
-localparam SR_SPI = 8;
-localparam SR_GPIO = 16;
-localparam SR_MISC_OUTS = 24;
-localparam SR_READBACK = 32;
-localparam SR_TX_CTRL = 64;
-localparam SR_RX_CTRL = 96;
-localparam SR_TIME = 128;
-localparam SR_RX_DSP = 144;
-localparam SR_TX_DSP = 184;
-localparam SR_LEDS = 195;
-localparam SR_FP_GPIO = 200;
-localparam SR_RX_FRONT = 208;
-localparam SR_TX_FRONT = 216;
-
-localparam RB32_GPIO = 0;
-localparam RB32_SPI = 4;
-localparam RB64_TIME_NOW = 8;
-localparam RB64_TIME_PPS = 16;
-localparam RB32_TEST = 24;
-localparam RB32_RX = 28;
-localparam RB32_FP_GPIO = 32;
-
-localparam BL_ADDRESS = 0;
-localparam BL_DATA = 1;
+localparam SR_DACSYNC = 5;
+localparam SR_LOOPBACK = 6;
+localparam SR_TEST = 7;
+localparam SR_SPI = 8;
+localparam SR_GPIO = 16;
+localparam SR_MISC_OUTS = 24;
+localparam SR_READBACK = 32;
+localparam SR_TX_CTRL = 64;
+localparam SR_RX_CTRL = 96;
+localparam SR_TIME = 128;
+localparam SR_RX_DSP = 144;
+localparam SR_TX_DSP = 184;
+localparam SR_LEDS = 195;
+localparam SR_FP_GPIO = 200;
+localparam SR_RX_FRONT = 208;
+localparam SR_TX_FRONT = 216;
+
+localparam RB32_GPIO = 0;
+localparam RB32_SPI = 4;
+localparam RB64_TIME_NOW = 8;
+localparam RB64_TIME_PPS = 16;
+localparam RB32_TEST = 24;
+localparam RB32_RX = 28;
+localparam RB32_FP_GPIO = 32;
+
+localparam BL_ADDRESS = 0;
+localparam BL_DATA = 1;
//wishbone settings map - relevant to host code
-#define SET0_BASE 0xa000
-#define SETXB_BASE 0xb000
-#define BOOT_LDR_BASE 0xFA00
-#define I2C0_BASE 0xfe00
-#define I2C1_BASE 0xff00
+#define SET0_BASE 0xa000
+#define SETXB_BASE 0xb000
+#define BOOT_LDR_BASE 0xfa00
+#define I2C0_BASE 0xfe00
+#define I2C1_BASE 0xff00
#define SR_ADDR(base, offset) ((base) + (offset)*4)
localparam ZPU_SR_LEDS = 00;
@@ -70,56 +70,62 @@ localparam ZPU_SR_ETHINT0 = 40;
localparam ZPU_SR_ETHINT1 = 56;
//clock controls
-#define ZPU_SR_CLOCK_CTRL_CLK_SRC_EXTERNAL 0x00
-#define ZPU_SR_CLOCK_CTRL_CLK_SRC_INTERNAL 0x02
-#define ZPU_SR_CLOCK_CTRL_CLK_SRC_GPSDO 0x03
-#define ZPU_SR_CLOCK_CTRL_PPS_SRC_EXTERNAL 0x00
-#define ZPU_SR_CLOCK_CTRL_PPS_SRC_INTERNAL 0x02
-#define ZPU_SR_CLOCK_CTRL_PPS_SRC_GPSDO 0x03
-
-localparam ZPU_RB_SPI = 2;
+#define ZPU_SR_CLOCK_CTRL_CLK_SRC_EXTERNAL 0x00
+#define ZPU_SR_CLOCK_CTRL_CLK_SRC_INTERNAL 0x02
+#define ZPU_SR_CLOCK_CTRL_CLK_SRC_GPSDO 0x03
+#define ZPU_SR_CLOCK_CTRL_PPS_SRC_EXTERNAL 0x00
+#define ZPU_SR_CLOCK_CTRL_PPS_SRC_INTERNAL 0x02
+#define ZPU_SR_CLOCK_CTRL_PPS_SRC_GPSDO 0x03
+
+localparam ZPU_RB_SPI = 2;
localparam ZPU_RB_CLK_STATUS = 3;
localparam ZPU_RB_COMPAT_NUM = 6;
localparam ZPU_RB_ETH_TYPE0 = 4;
localparam ZPU_RB_ETH_TYPE1 = 5;
//clock status
-#define ZPU_RB_CLK_STATUS_LMK_STATUS (0x3 << 0)
-#define ZPU_RB_CLK_STATUS_LMK_LOCK (0x1 << 2)
-#define ZPU_RB_CLK_STATUS_LMK_HOLDOVER (0x1 << 3)
-#define ZPU_RB_CLK_STATUS_PPS_DETECT (0x1 << 4)
+#define ZPU_RB_CLK_STATUS_LMK_STATUS (0x3 << 0)
+#define ZPU_RB_CLK_STATUS_LMK_LOCK (0x1 << 2)
+#define ZPU_RB_CLK_STATUS_LMK_HOLDOVER (0x1 << 3)
+#define ZPU_RB_CLK_STATUS_PPS_DETECT (0x1 << 4)
//spi slaves on radio
-#define DB_DAC_SEN (1 << 7)
-#define DB_ADC_SEN (1 << 6)
+#define DB_DAC_SEN (1 << 7)
+#define DB_ADC_SEN (1 << 6)
#define DB_RX_LSADC_SEN (1 << 5)
#define DB_RX_LSDAC_SEN (1 << 4)
#define DB_TX_LSADC_SEN (1 << 3)
#define DB_TX_LSDAC_SEN (1 << 2)
-#define DB_RX_SEN (1 << 1)
-#define DB_TX_SEN (1 << 0)
+#define DB_RX_SEN (1 << 1)
+#define DB_TX_SEN (1 << 0)
//-------------------------------------------------------------------
// PCIe Registers
//-------------------------------------------------------------------
-static const uint32_t X300_PCIE_VID = 0x1093;
-static const uint32_t X300_PCIE_PID = 0xC4C4;
-static const uint32_t X300_USRP_PCIE_SSID = 0x7736;
-static const uint32_t X310_USRP_PCIE_SSID = 0x76CA;
-static const uint32_t X310_2940R_PCIE_SSID = 0x772B;
-static const uint32_t X310_2942R_PCIE_SSID = 0x772C;
-static const uint32_t X310_2943R_PCIE_SSID = 0x772D;
-static const uint32_t X310_2944R_PCIE_SSID = 0x772E;
-static const uint32_t X310_2950R_PCIE_SSID = 0x772F;
-static const uint32_t X310_2952R_PCIE_SSID = 0x7730;
-static const uint32_t X310_2953R_PCIE_SSID = 0x7731;
-static const uint32_t X310_2954R_PCIE_SSID = 0x7732;
+static const uint32_t X300_PCIE_VID = 0x1093;
+static const uint32_t X300_PCIE_PID = 0xC4C4;
+static const uint32_t X300_USRP_PCIE_SSID = 0x7736;
+static const uint32_t X310_USRP_PCIE_SSID = 0x76CA;
+static const uint32_t X310_2940R_40MHz_PCIE_SSID = 0x772B;
+static const uint32_t X310_2940R_120MHz_PCIE_SSID = 0x77FB;
+static const uint32_t X310_2942R_40MHz_PCIE_SSID = 0x772C;
+static const uint32_t X310_2942R_120MHz_PCIE_SSID = 0x77FC;
+static const uint32_t X310_2943R_40MHz_PCIE_SSID = 0x772D;
+static const uint32_t X310_2943R_120MHz_PCIE_SSID = 0x77FD;
+static const uint32_t X310_2944R_40MHz_PCIE_SSID = 0x772E;
+static const uint32_t X310_2950R_40MHz_PCIE_SSID = 0x772F;
+static const uint32_t X310_2950R_120MHz_PCIE_SSID = 0x77FE;
+static const uint32_t X310_2952R_40MHz_PCIE_SSID = 0x7730;
+static const uint32_t X310_2952R_120MHz_PCIE_SSID = 0x77FF;
+static const uint32_t X310_2953R_40MHz_PCIE_SSID = 0x7731;
+static const uint32_t X310_2953R_120MHz_PCIE_SSID = 0x7800;
+static const uint32_t X310_2954R_40MHz_PCIE_SSID = 0x7732;
static const uint32_t FPGA_X3xx_SIG_VALUE = 0x58333030;
static const uint32_t PCIE_FPGA_ADDR_BASE = 0xC0000;
-#define PCIE_FPGA_REG(X) (PCIE_FPGA_ADDR_BASE + X)
+#define PCIE_FPGA_REG(X) (PCIE_FPGA_ADDR_BASE + (X))
static const uint32_t FPGA_PCIE_SIG_REG = PCIE_FPGA_REG(0x0000);
static const uint32_t FPGA_CNTR_LO_REG = PCIE_FPGA_REG(0x0004);
@@ -140,8 +146,8 @@ static const uint32_t DMA_FRAME_SIZE_REG = 0x4;
static const uint32_t DMA_SAMPLE_COUNT_REG = 0x8;
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)
+#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_DISABLED = 0x00000000;
static const uint32_t DMA_CTRL_ENABLED = 0x00000002;
@@ -154,15 +160,15 @@ 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)
+#define PCIE_ROUTER_REG(X) (PCIE_ROUTER_REG_BASE + (X))
static const uint32_t PCIE_ZPU_DATA_BASE = 0x30000;
static const uint32_t PCIE_ZPU_READ_BASE = 0x20000; //Trig and Status share the same base
static const uint32_t PCIE_ZPU_STATUS_BASE = 0x20000;
-#define PCIE_ZPU_DATA_REG(X) (PCIE_FPGA_REG(PCIE_ZPU_DATA_BASE) + X)
-#define PCIE_ZPU_READ_REG(X) (PCIE_FPGA_REG(PCIE_ZPU_READ_BASE) + X)
-#define PCIE_ZPU_STATUS_REG(X) (PCIE_FPGA_REG(PCIE_ZPU_STATUS_BASE) + X)
+#define PCIE_ZPU_DATA_REG(X) (PCIE_FPGA_REG(PCIE_ZPU_DATA_BASE) + (X))
+#define PCIE_ZPU_READ_REG(X) (PCIE_FPGA_REG(PCIE_ZPU_READ_BASE) + (X))
+#define PCIE_ZPU_STATUS_REG(X) (PCIE_FPGA_REG(PCIE_ZPU_STATUS_BASE) + (X))
static const uint32_t PCIE_ZPU_READ_START = 0x0;
static const uint32_t PCIE_ZPU_READ_CLOBBER = 0x80000000;