aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp')
-rw-r--r--host/lib/usrp/CMakeLists.txt1
-rw-r--r--host/lib/usrp/dboard/CMakeLists.txt3
-rw-r--r--host/lib/usrp/dboard/e3xx/e3xx_radio_control_impl.cpp1
-rw-r--r--host/lib/usrp/dboard/e3xx/e3xx_radio_control_init.cpp1
-rw-r--r--host/lib/usrp/dboard/eiscat/CMakeLists.txt14
-rw-r--r--host/lib/usrp/dboard/eiscat/eiscat_radio_ctrl_impl.cpp950
-rw-r--r--host/lib/usrp/dboard/eiscat/eiscat_radio_ctrl_impl.hpp295
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_radio_control.cpp3
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_radio_control_init.cpp1
-rw-r--r--host/lib/usrp/dboard/rhodium/rhodium_radio_control.cpp1
-rw-r--r--host/lib/usrp/dboard/rhodium/rhodium_radio_control_init.cpp1
-rw-r--r--host/lib/usrp/device3/CMakeLists.txt15
-rw-r--r--host/lib/usrp/device3/device3_flow_ctrl.hpp306
-rw-r--r--host/lib/usrp/device3/device3_impl.cpp206
-rw-r--r--host/lib/usrp/device3/device3_impl.hpp264
-rw-r--r--host/lib/usrp/device3/device3_io_impl.cpp827
-rw-r--r--host/lib/usrp/mpmd/mpmd_impl.cpp6
-rw-r--r--host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.cpp132
-rw-r--r--host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.hpp7
-rw-r--r--host/lib/usrp/mpmd/mpmd_link_if_mgr.hpp8
-rw-r--r--host/lib/usrp/multi_usrp.cpp7
-rw-r--r--host/lib/usrp/x300/x300_eth_mgr.cpp80
-rw-r--r--host/lib/usrp/x300/x300_pcie_mgr.cpp102
-rw-r--r--host/lib/usrp/x300/x300_radio_ctrl_impl.cpp1577
-rw-r--r--host/lib/usrp/x300/x300_radio_ctrl_impl.hpp246
25 files changed, 165 insertions, 4889 deletions
diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt
index 0b839a835..f15324608 100644
--- a/host/lib/usrp/CMakeLists.txt
+++ b/host/lib/usrp/CMakeLists.txt
@@ -35,7 +35,6 @@ endif(ENABLE_C_API)
INCLUDE_SUBDIRECTORY(cores)
INCLUDE_SUBDIRECTORY(dboard)
INCLUDE_SUBDIRECTORY(common)
-INCLUDE_SUBDIRECTORY(device3)
INCLUDE_SUBDIRECTORY(mpmd)
INCLUDE_SUBDIRECTORY(usrp1)
INCLUDE_SUBDIRECTORY(usrp2)
diff --git a/host/lib/usrp/dboard/CMakeLists.txt b/host/lib/usrp/dboard/CMakeLists.txt
index 8ee79103f..2dd4e7e26 100644
--- a/host/lib/usrp/dboard/CMakeLists.txt
+++ b/host/lib/usrp/dboard/CMakeLists.txt
@@ -49,6 +49,3 @@ endif(ENABLE_N300)
if(ENABLE_N320)
INCLUDE_SUBDIRECTORY(rhodium)
endif(ENABLE_N320)
-if(ENABLE_MPMD AND ENABLE_EISCAT)
- INCLUDE_SUBDIRECTORY(eiscat)
-endif(ENABLE_MPMD AND ENABLE_EISCAT)
diff --git a/host/lib/usrp/dboard/e3xx/e3xx_radio_control_impl.cpp b/host/lib/usrp/dboard/e3xx/e3xx_radio_control_impl.cpp
index 29381a53c..bc9ed9169 100644
--- a/host/lib/usrp/dboard/e3xx/e3xx_radio_control_impl.cpp
+++ b/host/lib/usrp/dboard/e3xx/e3xx_radio_control_impl.cpp
@@ -7,7 +7,6 @@
#include "e3xx_radio_control_impl.hpp"
#include "e3xx_constants.hpp"
-#include <uhd/transport/chdr.hpp>
#include <uhd/types/direction.hpp>
#include <uhd/types/eeprom.hpp>
#include <uhd/utils/algorithm.hpp>
diff --git a/host/lib/usrp/dboard/e3xx/e3xx_radio_control_init.cpp b/host/lib/usrp/dboard/e3xx/e3xx_radio_control_init.cpp
index f97feeb68..6ecf4ff2a 100644
--- a/host/lib/usrp/dboard/e3xx/e3xx_radio_control_init.cpp
+++ b/host/lib/usrp/dboard/e3xx/e3xx_radio_control_init.cpp
@@ -6,7 +6,6 @@
#include "e3xx_constants.hpp"
#include "e3xx_radio_control_impl.hpp"
-#include <uhd/transport/chdr.hpp>
#include <uhd/types/sensors.hpp>
#include <uhd/utils/log.hpp>
#include <uhdlib/rfnoc/reg_iface_adapter.hpp>
diff --git a/host/lib/usrp/dboard/eiscat/CMakeLists.txt b/host/lib/usrp/dboard/eiscat/CMakeLists.txt
deleted file mode 100644
index 076d26916..000000000
--- a/host/lib/usrp/dboard/eiscat/CMakeLists.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# Copyright 2017 Ettus Research, a National Instruments Company
-#
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-
-# This file is conditionally included if ENABLE_MPMD and ENABLE_EISCAT are
-# set to true.
-
-list(APPEND EISCAT_SOURCES
- ${CMAKE_CURRENT_SOURCE_DIR}/eiscat_radio_ctrl_impl.cpp
-)
-LIBUHD_APPEND_SOURCES(${EISCAT_SOURCES})
-
diff --git a/host/lib/usrp/dboard/eiscat/eiscat_radio_ctrl_impl.cpp b/host/lib/usrp/dboard/eiscat/eiscat_radio_ctrl_impl.cpp
deleted file mode 100644
index 73851656b..000000000
--- a/host/lib/usrp/dboard/eiscat/eiscat_radio_ctrl_impl.cpp
+++ /dev/null
@@ -1,950 +0,0 @@
-//
-// Copyright 2017 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include "eiscat_radio_ctrl_impl.hpp"
-
-#include <uhd/utils/log.hpp>
-#include <uhd/utils/math.hpp>
-#include <uhd/rfnoc/node_ctrl_base.hpp>
-#include <uhd/types/ranges.hpp>
-#include <boost/algorithm/string.hpp>
-#include <boost/make_shared.hpp>
-#include <boost/date_time/posix_time/posix_time_io.hpp>
-#include <boost/format.hpp>
-
-using namespace uhd;
-using namespace uhd::usrp;
-using namespace uhd::rfnoc;
-
-namespace {
- const size_t SR_ANTENNA_GAIN_BASE = 204;
- const size_t SR_ANTENNA_SELECT_BASE = 192; // Note: On other dboards, 192 is DB_GPIO address space
- const size_t RB_CHOOSE_BEAMS = 11;
-
- const double EISCAT_TICK_RATE = 208e6; // Hz
- const double EISCAT_RADIO_RATE = 104e6; // Hz
- const double EISCAT_CENTER_FREQ = 208e6; // Hz
- const double EISCAT_DEFAULT_NULL_GAIN = 0.0; // dB. This is not the digital antenna gain, this a fake stub value.
- const double EISCAT_DEFAULT_BANDWIDTH = 104e6; // Hz
- const char* EISCAT_DEFAULT_ANTENNA = "BF";
- const size_t EISCAT_NUM_ANTENNAS = 16;
- const size_t EISCAT_NUM_BEAMS = 10;
- const size_t EISCAT_NUM_PORTS = 5;
- const size_t EISCAT_MAX_GAIN_RANGE = 18; // Bits, *signed*.
- const size_t EISCAT_UNIT_GAIN_RANGE = 14; // Bits, *signed*.
- const int32_t EISCAT_MAX_GAIN = (1<<(EISCAT_MAX_GAIN_RANGE-1))-1;
- const int32_t EISCAT_UNIT_GAIN = (1<<(EISCAT_UNIT_GAIN_RANGE-1))-1;
- const int32_t EISCAT_MIN_GAIN = -(1<<(EISCAT_MAX_GAIN_RANGE-1));
- const double EISCAT_DEFAULT_NORM_GAIN = 1.0; // Normalized. This is the actual digital gain value.
- const size_t EISCAT_BITS_PER_TAP = 18;
- const eiscat_radio_ctrl_impl::fir_tap_t EISCAT_MAX_TAP_VALUE = (1<<(EISCAT_BITS_PER_TAP-1))-1;
- const eiscat_radio_ctrl_impl::fir_tap_t EISCAT_MIN_TAP_VALUE = -(1<<(EISCAT_BITS_PER_TAP-1));
- const size_t EISCAT_NUM_FIR_TAPS = 10;
- const size_t EISCAT_NUM_FIR_SETS = 1024; // BRAM must be at least EISCAT_NUM_FIR_TAPS * EISCAT_NUM_FIR_SETS
- const size_t EISCAT_FIR_INDEX_IMPULSE = 1002;
- const size_t EISCAT_FIR_INDEX_ZEROS = 1003;
-
- const uint32_t EISCAT_CONTRIB_LOWER = 0<<0;
- const uint32_t EISCAT_CONTRIB_UPPER = 1<<0;
- const uint32_t EISCAT_SKIP_NEIGHBOURS = 1<<1;
- const uint32_t EISCAT_BYPASS_MATRIX = 1<<2;
- const uint32_t EISCAT_OUTPUT_COUNTER = 1<<3;
-};
-
-
-UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR(eiscat_radio_ctrl)
-{
- UHD_LOG_TRACE("EISCAT", "eiscat_radio_ctrl_impl::ctor() ");
- _num_ports = get_output_ports().size();
- UHD_LOG_TRACE("EISCAT", "Number of channels: " << _num_ports);
- UHD_LOG_TRACE("EISCAT",
- "Tick rate is " << EISCAT_TICK_RATE/1e6 << " MHz"
- );
-
- /**** Configure the radio_ctrl itself ***********************************/
- // This also sets the command tick rate:
- radio_ctrl_impl::set_rate(EISCAT_TICK_RATE);
- for (size_t chan = 0; chan < _num_ports; chan++) {
- radio_ctrl_impl::set_rx_frequency(EISCAT_CENTER_FREQ, chan);
- radio_ctrl_impl::set_rx_gain(EISCAT_DEFAULT_NULL_GAIN, chan);
- radio_ctrl_impl::set_rx_antenna(EISCAT_DEFAULT_ANTENNA, chan);
- radio_ctrl_impl::set_rx_bandwidth(EISCAT_DEFAULT_BANDWIDTH, chan);
- // We might get tx async messages from upstream radios, we send them to the
- // nevernever by default or they interfere with our streamers or ctrl_iface
- // objects. The assumption is that FF:FF is never a valid SID.
- this->sr_write(uhd::rfnoc::SR_RESP_IN_DST_SID, 0xFFFF, chan);
- }
-
- /**** Set up arg-based control API **************************************/
- // None of these properties are defined in the XML file. Some of them have
- // non-Noc-Script-compatible types.
- _tree->create<bool>(get_arg_path("sysref", 0) / "value")
- .set(true)
- .add_coerced_subscriber([this](bool){
- try {
- this->send_sysref();
- } catch (const uhd::exception &ex) {
- UHD_LOGGER_WARNING("EISCAT")
- << "Failed to send SYSREF: " << ex.what();
- throw uhd::runtime_error(str(
- boost::format("Failed to send SYSREF: %s")
- % ex.what()
- ));
- }
- })
- .set_publisher([](){ return true; })
- ;
- _tree->create<bool>(get_arg_path("assert_adcs_deframers", 0) / "value")
- .set(true)
- .set_publisher([this](){ return this->assert_adcs_deframers(); })
- ;
- _tree->create<bool>(get_arg_path("assert_deframer_status", 0) / "value")
- .set(true)
- .set_publisher([this](){ return this->assert_adcs_deframers(); })
- ;
- _tree->create<time_spec_t>(get_arg_path("fir_ctrl_time", 0) / "value")
- .add_coerced_subscriber([this](time_spec_t switch_time){
- this->set_fir_ctrl_time(switch_time);
- })
- .set(time_spec_t(0.0))
- ;
- for (size_t beam = 0; beam < EISCAT_NUM_BEAMS; beam++) {
- for (size_t ant = 0; ant < EISCAT_NUM_ANTENNAS; ant++) {
- const size_t fir_index = beam * EISCAT_NUM_ANTENNAS + ant;
- // These are not in the XML file
- _tree->create<int>(get_arg_path("fir_select", fir_index) / "value")
- .add_coerced_subscriber([beam, ant, this](const size_t ram_idx){
- UHD_ASSERT_THROW(ram_idx < EISCAT_NUM_FIR_SETS);
- this->select_filter(
- beam,
- ant,
- ram_idx,
- this->get_arg<time_spec_t>("fir_ctrl_time", 0),
- false
- );
- })
- ;
- }
- }
- for (size_t fir_set = 0; fir_set < EISCAT_NUM_FIR_SETS; fir_set++) {
- _tree->create<std::vector<fir_tap_t>>(
- get_arg_path("fir_taps", fir_set) / "value")
- .add_coerced_subscriber(
- [this, fir_set](const std::vector<fir_tap_t> &taps){
- this->write_fir_taps(fir_set, taps);
- }
- )
- ;
- }
-
-
- /**** Add subscribers for our special properties ************************/
- // The difference between this block and the previous that these *are*
- // defined in the XML file, and can have defaults set there.
- _tree->access<int>(get_arg_path("choose_beams", 0) / "value")
- .add_coerced_subscriber([this](int choose_beams){
- this->set_beam_selection(choose_beams);
- })
- .update()
- ;
- _tree->access<bool>(get_arg_path("enable_firs", 0) / "value")
- .add_coerced_subscriber([this](int enable){
- this->enable_firs(bool(enable));
- })
- .update()
- ;
- _tree->access<bool>(get_arg_path("enable_counter", 0) / "value")
- .add_coerced_subscriber([this](int enable){
- this->enable_counter(bool(enable));
- })
- .update()
- ;
- _tree->access<int>(get_arg_path("configure_beams", 0) / "value")
- .add_coerced_subscriber([this](int reg_value){
- this->configure_beams(uint32_t(reg_value));
- }) // No update! This would override the previous settings.
- .set_publisher([this](){
- return this->user_reg_read32(RB_CHOOSE_BEAMS);
- })
- ;
-
- /**** Configure the digital gain controls *******************************/
- for (size_t i = 0; i < EISCAT_NUM_ANTENNAS; i++) {
- _tree->access<double>(get_arg_path("gain", i) / "value")
- .set_coercer([](double gain){
- return std::max(-16.0, std::min(16.0, gain));
- })
- .add_coerced_subscriber([this, i](double gain){
- this->set_antenna_gain(i, gain);
- })
- .update()
- ;
- }
-
- /**** Set up legacy compatible properties *******************************/
- // For use with multi_usrp APIs etc.
- // For legacy prop tree init:
- fs_path fe_path = fs_path("dboards") / "A" / "rx_frontends";
-
- // The EISCAT dboards have 16 frontends total, but they map to 10 beams
- // each through a matrix of FIR filters and summations, and then only 5 of
- // those channels go out through the Noc-Shell.
- // UHD will thus get much less confused if we create 5 fake frontends (i.e.,
- // number of Noc-Block-ports). Since we have no control over the frontends,
- // nothing is lost here.
- for (size_t fe_idx = 0; fe_idx < _num_ports; fe_idx++) {
- _tree->create<std::string>(fe_path / fe_idx / "name")
- .set(str(boost::format("EISCAT Beam Contributions %d") % fe_idx))
- ;
- _tree->create<std::string>(fe_path / fe_idx / "connection")
- .set("I")
- ;
- _tree->create<double>(fe_path / fe_idx / "freq" / "value")
- .set_coercer([this](const double freq){
- return this->set_rx_frequency(freq, 0);
- })
- .set_publisher([this](){
- return this->get_rx_frequency(0);
- })
- ;
- _tree->create<meta_range_t>(fe_path / fe_idx / "freq" / "range")
- .set(meta_range_t(EISCAT_CENTER_FREQ, EISCAT_CENTER_FREQ))
- ;
- _tree->create<double>(fe_path / fe_idx / "gains" / "null" / "value")
- .set_coercer([this](const double gain){
- return this->set_rx_gain(gain, 0);
- })
- .set_publisher([this](){
- return this->get_rx_gain(0);
- })
- ;
- _tree->create<meta_range_t>(fe_path / fe_idx / "gains" / "null" / "range")
- .set(meta_range_t(EISCAT_DEFAULT_NULL_GAIN, EISCAT_DEFAULT_NULL_GAIN))
- ;
- _tree->create<double>(fe_path / fe_idx / "bandwidth" / "value")
- .set_coercer([this](const double bw){
- return this->set_rx_bandwidth(bw, 0);
- })
- .set_publisher([this](){
- return this->get_rx_bandwidth(0);
- })
- ;
- _tree->create<meta_range_t>(fe_path / fe_idx / "bandwidth" / "range")
- .set(meta_range_t(EISCAT_DEFAULT_BANDWIDTH, EISCAT_DEFAULT_BANDWIDTH))
- ;
- _tree->create<bool>(fe_path / fe_idx / "use_lo_offset")
- .set(false)
- ;
- }
-
- auto antenna_options = std::vector<std::string>{"BF"};
- for (size_t i = 0; i < EISCAT_NUM_ANTENNAS; i++) {
- antenna_options.push_back(str(boost::format("Rx%d") % i));
- antenna_options.push_back(str(boost::format("BF%d") % i));
- }
- antenna_options.push_back("FI0");
- antenna_options.push_back("FI250");
- antenna_options.push_back("FI500");
- antenna_options.push_back("FI750");
- for (size_t beam_idx = 0; beam_idx < _num_ports; beam_idx++) {
- _tree->create<std::string>(fe_path / beam_idx / "antenna" / "value")
- .set(EISCAT_DEFAULT_ANTENNA)
- .add_coerced_subscriber([this, beam_idx](const std::string &name){
- this->set_rx_antenna(name, beam_idx);
- })
- .set_publisher([this, beam_idx](){
- return this->get_rx_antenna(beam_idx);
- })
- ;
- _tree->create<std::vector<std::string>>(
- fe_path / beam_idx / "antenna" / "options")
- .set(antenna_options)
- ;
- }
-
- // We can actually stream data to an EISCAT board, so it needs some tx
- // frontends too:
- fe_path = fs_path("dboards") / "A" / "tx_frontends";
- for (size_t fe_idx = 0; fe_idx < _num_ports; fe_idx++) {
- _tree->create<std::string>(fe_path / fe_idx / "name")
- .set(str(boost::format("EISCAT Uplink %d") % fe_idx))
- ;
- }
-
- for (size_t i = 0; i < EISCAT_NUM_PORTS; i++) {
- _tree->create<uhd::time_spec_t>(get_arg_path("pseudo_stream_cmd", i) / "value")
- .add_coerced_subscriber([this, i](uhd::time_spec_t stream_time){
- if (stream_time != uhd::time_spec_t(0.0)) {
- uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
- cmd.stream_now = false;
- cmd.time_spec = stream_time;
- this->issue_stream_cmd(cmd, i);
- } else {
- this->issue_stream_cmd(
- uhd::stream_cmd_t(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS),
- i
- );
- }
- })
- ;
- }
- //FIXME elaborate this more, but for now it works.
- _tree->create<int>("rx_codecs/A/gains");
- _tree->create<std::string>("rx_codecs/A/name").set("ADS54J66");
-
-
- // There is only ever one EISCAT radio per mboard, so this should be unset
- // when we reach this line:
- UHD_ASSERT_THROW(not _tree->exists("tick_rate"));
- _tree->create<double>("tick_rate")
- .set(EISCAT_TICK_RATE)
- .set_coercer(boost::bind(&eiscat_radio_ctrl_impl::set_rate, this, _1))
- ;
-}
-
-eiscat_radio_ctrl_impl::~eiscat_radio_ctrl_impl()
-{
- UHD_LOG_TRACE("EISCAT", "eiscat_radio_ctrl_impl::dtor() ");
-}
-
-
-/****************************************************************************
- * Public API calls
- ***************************************************************************/
-void eiscat_radio_ctrl_impl::set_tx_antenna(const std::string &, const size_t)
-{
- throw uhd::runtime_error("Cannot set Tx antenna on EISCAT daughterboard");
-}
-
-void eiscat_radio_ctrl_impl::set_rx_antenna(
- const std::string &ant,
- const size_t port
-) {
- UHD_ASSERT_THROW(port < EISCAT_NUM_BEAMS);
- if (ant == "BF") {
- UHD_LOG_TRACE("EISCAT", "Setting antenna to 'BF' (which is a no-op)");
- return;
- }
- if (ant.size() < 3) {
- throw uhd::value_error(str(
- boost::format("EISCAT: Invalid antenna selection: %s")
- % ant
- ));
- }
-
- const std::string ant_mode = ant.substr(0, 2);
- const size_t antenna_idx = [&ant](){
- try {
- return boost::lexical_cast<size_t>(ant.substr(2));
- } catch (const boost::bad_lexical_cast&) {
- throw uhd::value_error(str(
- boost::format("EISCAT: Invalid antenna selection: %s")
- % ant
- ));
- }
- }();
-
- if (ant_mode == "BF") {
- int new_choose_beams =
- get_arg<int>("choose_beams") | EISCAT_SKIP_NEIGHBOURS;
- set_arg<int>("choose_beams", new_choose_beams);
- size_t beam_select_offset =
- (get_arg<int>("choose_beams") & EISCAT_CONTRIB_UPPER) ?
- EISCAT_NUM_PORTS : 0;
- const size_t beam_index = port + beam_select_offset;
- uhd::time_spec_t send_now(0.0);
- UHD_LOG_TRACE("EISCAT", str(
- boost::format("Setting block port %d to only receive from beam %d "
- "connected to antenna %d via FIR matrix")
- % port
- % beam_index
- % antenna_idx
- ));
- for (size_t i = 0; i < EISCAT_NUM_ANTENNAS; i++) {
- select_filter(
- beam_index,
- i,
- (i == antenna_idx) ?
- EISCAT_FIR_INDEX_IMPULSE : EISCAT_FIR_INDEX_ZEROS,
- send_now
- );
- }
- enable_firs(true);
- } else if (ant_mode == "RX" or ant_mode == "Rx") {
- int new_choose_beams =
- get_arg<int>("choose_beams") | EISCAT_SKIP_NEIGHBOURS;
- set_arg<int>("choose_beams", new_choose_beams);
- UHD_LOG_TRACE("EISCAT", str(
- boost::format("Setting port %d to only receive on antenna %d "
- "directly, bypassing neighbours and FIR matrix")
- % port % antenna_idx
- ));
- sr_write(SR_ANTENNA_SELECT_BASE + port, antenna_idx);
- enable_firs(false);
- } else if (ant_mode == "FI") {
- size_t beam_index = port % EISCAT_NUM_PORTS;
- UHD_LOG_TRACE("EISCAT", str(
- boost::format("Setting port %d to filter index %d on all antennas "
- "using beam indices %d and %d.")
- % port
- % antenna_idx
- % beam_index % (beam_index + EISCAT_NUM_PORTS)
- ));
- // Note: antenna_idx is not indexing a physical antenna in this scenario.
- uhd::time_spec_t send_now(0.0);
- for (size_t i = 0; i < EISCAT_NUM_ANTENNAS; i++) {
- select_filter(
- beam_index,
- i,
- antenna_idx,
- send_now
- );
- select_filter(
- beam_index + EISCAT_NUM_PORTS,
- i,
- antenna_idx,
- send_now
- );
- }
- enable_firs(true);
- } else if (ant_mode == "CN") {
- const size_t beam_index = port % EISCAT_NUM_PORTS;
- UHD_LOG_TRACE("EISCAT", str(
- boost::format("Setting port %d to filter index %d on all antennas "
- "using beam indices %d and %d.")
- % port
- % antenna_idx
- % beam_index % (beam_index + EISCAT_NUM_PORTS)
- ));
- // Note: antenna_idx is not indexing a physical antenna in this scenario.
- uhd::time_spec_t send_now(0.0);
- for (size_t i = 0; i < EISCAT_NUM_ANTENNAS; i+=2) {
- select_filter(
- beam_index,
- i,
- 0,
- send_now
- );
- select_filter(
- beam_index + EISCAT_NUM_PORTS,
- i,
- 0,
- send_now
- );
- select_filter(
- beam_index,
- i+1,
- antenna_idx,
- send_now
- );
- select_filter(
- beam_index + EISCAT_NUM_PORTS,
- i+1,
- antenna_idx,
- send_now
- );
- }
- enable_firs(true);
- } else {
- throw uhd::value_error(str(
- boost::format("EISCAT: Invalid antenna selection: %s")
- % ant
- ));
- }
-}
-
-double eiscat_radio_ctrl_impl::get_tx_frequency(const size_t /* chan */)
-{
- UHD_LOG_WARNING("EISCAT", "Ignoring attempt to read Tx frequency");
- return 0.0;
-}
-
-double eiscat_radio_ctrl_impl::set_tx_frequency(const double /* freq */, const size_t /* chan */)
-{
- throw uhd::runtime_error("Cannot set Tx frequency on EISCAT daughterboard");
-}
-
-double eiscat_radio_ctrl_impl::set_rx_frequency(const double freq, const size_t chan)
-{
- if (freq != get_rx_frequency(chan)) {
- UHD_LOG_WARNING("EISCAT", "Ignoring attempt to set Rx frequency");
- }
- return get_rx_frequency(chan);
-}
-
-double eiscat_radio_ctrl_impl::set_rx_bandwidth(const double bandwidth, const size_t chan)
-{
- if (bandwidth != get_rx_bandwidth(chan)) {
- UHD_LOG_WARNING("EISCAT", "Ignoring attempt to set Rx bandwidth");
- }
- return get_rx_bandwidth(chan);
-}
-
-
-double eiscat_radio_ctrl_impl::set_tx_gain(const double /* gain */, const size_t /* chan */)
-{
- throw uhd::runtime_error("Cannot set Tx gain on EISCAT daughterboard");
-}
-
-double eiscat_radio_ctrl_impl::set_rx_gain(const double gain, const size_t chan)
-{
- // TODO: Add ability to set digital gain or make it explicit this function is not supported.
- if (gain != get_rx_gain(chan)) {
- UHD_LOG_WARNING("EISCAT", "Ignoring attempt to set Rx gain.");
- }
- return get_rx_gain(chan);
-}
-
-double eiscat_radio_ctrl_impl::set_rate(double rate)
-{
- if (rate != get_rate()) {
- UHD_LOG_WARNING("EISCAT", "Attempting to set sampling rate to invalid value " << rate);
- }
- return get_rate();
-}
-
-size_t eiscat_radio_ctrl_impl::get_chan_from_dboard_fe(
- const std::string &fe,
- const uhd::direction_t /* dir */
-) {
- return boost::lexical_cast<size_t>(fe);
-}
-
-std::string eiscat_radio_ctrl_impl::get_dboard_fe_from_chan(
- const size_t chan,
- const uhd::direction_t /* dir */
-) {
- return std::to_string(chan);
-}
-
-double eiscat_radio_ctrl_impl::get_output_samp_rate(size_t /* port */)
-{
- return EISCAT_RADIO_RATE;
-}
-
-void eiscat_radio_ctrl_impl::set_rx_streamer(bool active, const size_t port)
-{
- UHD_RFNOC_BLOCK_TRACE() << "radio_ctrl_impl::set_rx_streamer() " << port << " -> " << active ;
- if (port > EISCAT_NUM_PORTS) {
- throw uhd::value_error(str(
- boost::format("[%s] Can't (un)register RX streamer on port %d (invalid port)")
- % unique_id() % port
- ));
- }
- _rx_streamer_active[port] = active;
- if (not check_radio_config()) {
- throw std::runtime_error(str(
- boost::format("[%s]: Invalid radio configuration.")
- % unique_id()
- ));
- }
-
- if (list_upstream_nodes().empty() or not bool(get_arg<int>("use_prev"))) {
- UHD_LOG_DEBUG(unique_id(), "No prevs found, or prevs disabled, not passing on set_rx_streamer");
- } else {
- UHD_LOG_DEBUG(unique_id(), "set_rx_streamer(): We have prevs, so passing on set_rx_streamer");
- source_node_ctrl::sptr this_upstream_block_ctrl =
- boost::dynamic_pointer_cast<source_node_ctrl>(list_upstream_nodes().at(0).lock());
- if (this_upstream_block_ctrl) {
- this_upstream_block_ctrl->set_rx_streamer(active, port);
- } else {
- UHD_LOG_WARNING(unique_id(), "Oh noes, couldn't lock sptr!");
- }
- }
-}
-
-void eiscat_radio_ctrl_impl::issue_stream_cmd(const uhd::stream_cmd_t &stream_cmd, const size_t chan)
-{
- std::lock_guard<std::mutex> lock(_mutex);
-
- // Turn on/off top ones
- if (list_upstream_nodes().empty() or not bool(get_arg<int>("use_prev"))) {
- UHD_LOG_DEBUG(unique_id(), "No prevs found, or prevs disabled, not passing on stream cmd");
- } else {
- UHD_LOG_DEBUG(unique_id(), "issue_stream_cmd(): We have prevs, so passing on stream command");
- source_node_ctrl::sptr this_upstream_block_ctrl =
- boost::dynamic_pointer_cast<source_node_ctrl>(list_upstream_nodes().at(0).lock());
- if (this_upstream_block_ctrl) {
- this_upstream_block_ctrl->issue_stream_cmd(
- stream_cmd,
- chan
- );
- } else {
- UHD_LOG_WARNING(unique_id(), "Oh noes, couldn't lock sptr!");
- }
- }
-
- // Turn on/off this one
- UHD_LOGGER_DEBUG(unique_id()) << "eiscat_radio_ctrl_impl::issue_stream_cmd() " << chan << " " << char(stream_cmd.stream_mode);
- if (not _is_streamer_active(uhd::RX_DIRECTION, chan)) {
- UHD_RFNOC_BLOCK_TRACE() << "radio_ctrl_impl::issue_stream_cmd() called on inactive channel. Skipping." ;
- return;
- }
- UHD_ASSERT_THROW(stream_cmd.num_samps <= 0x0fffffff);
- _continuous_streaming[chan] = (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
-
- if (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS &&
- stream_cmd.stream_now == false) {
- UHD_LOG_TRACE("EISCAT", "Stop cmd timed, setting cmd time!");
- set_command_time(stream_cmd.time_spec, chan);
- }
-
- //setup the mode to instruction flags
- typedef boost::tuple<bool, bool, bool, bool> inst_t;
- static const uhd::dict<stream_cmd_t::stream_mode_t, inst_t> mode_to_inst = boost::assign::map_list_of
- //reload, chain, samps, stop
- (stream_cmd_t::STREAM_MODE_START_CONTINUOUS, inst_t(true, true, false, false))
- (stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS, inst_t(false, false, false, true))
- (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE, inst_t(false, false, true, false))
- (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE, inst_t(false, true, true, false))
- ;
-
- //setup the instruction flag values
- bool inst_reload, inst_chain, inst_samps, inst_stop;
- boost::tie(inst_reload, inst_chain, inst_samps, inst_stop) = mode_to_inst[stream_cmd.stream_mode];
-
- //calculate the word from flags and length
- uint32_t cmd_word = 0;
- cmd_word |= uint32_t((stream_cmd.stream_now)? 1 : 0) << 31;
- cmd_word |= uint32_t((inst_chain)? 1 : 0) << 30;
- cmd_word |= uint32_t((inst_reload)? 1 : 0) << 29;
- cmd_word |= uint32_t((inst_stop)? 1 : 0) << 28;
- cmd_word |= (inst_samps)? stream_cmd.num_samps : ((inst_stop)? 0 : 1);
-
- //issue the stream command
- const uint64_t ticks = (stream_cmd.stream_now)? 0 : stream_cmd.time_spec.to_ticks(get_rate());
- sr_write(regs::RX_CTRL_CMD, cmd_word, chan);
- sr_write(regs::RX_CTRL_TIME_HI, uint32_t(ticks >> 32), chan);
- sr_write(regs::RX_CTRL_TIME_LO, uint32_t(ticks >> 0), chan); //latches the command
- UHD_LOG_INFO(unique_id(), "issued stream command.");
- if (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS &&
- stream_cmd.stream_now == false) {
- UHD_LOG_TRACE("EISCAT", "Stop cmd timed, setting cmd time!");
- set_command_time(uhd::time_spec_t(0.0), chan);
- }
-
-}
-
-bool eiscat_radio_ctrl_impl::check_radio_config()
-{
- const uint32_t config_beams = get_arg<int>("configure_beams");
- bool skipping_neighbours = config_beams & EISCAT_SKIP_NEIGHBOURS;
- bool upper_contrib = config_beams & EISCAT_CONTRIB_UPPER;
- const fs_path rx_fe_path = fs_path("dboards/A/rx_frontends");
- uint32_t chan_enables = 0;
- for (const auto &enb: _rx_streamer_active) {
- if (enb.second) {
- chan_enables |= (1<<enb.first);
- }
- }
- if (not skipping_neighbours) {
- chan_enables = chan_enables | (chan_enables << EISCAT_NUM_PORTS);
- } else if (upper_contrib) {
- chan_enables <<= EISCAT_NUM_PORTS;
- }
- UHD_LOG_TRACE("EISCAT", str(
- boost::format("check_radio_config(): Setting channel enables to 0x%02X"
- " Using %s beams, %saccepting neighbour contributions")
- % chan_enables
- % (upper_contrib ? "upper" : "lower")
- % (skipping_neighbours ? "not " : "")
- ));
- sr_write("SR_RX_STREAM_ENABLE", chan_enables);
-
- return true;
-}
-
-void eiscat_radio_ctrl_impl::set_rpc_client(
- uhd::rpc_client::sptr rpcc,
- const uhd::device_addr_t &block_args
-) {
- _rpcc = rpcc;
- _block_args = block_args;
- auto dboard_info =
- _rpcc->request<std::vector<std::map<std::string, std::string>>>(
- "get_dboard_info"
- );
- _num_dboards = dboard_info.size();
- UHD_LOG_DEBUG("EISCAT", "Using " << _num_dboards << " daughterboards.");
- if (_num_dboards == 1) {
- UHD_LOG_WARNING("EISCAT",
- "Found 1 dboard, expected 2 for optimal operation."
- );
- } else if (_num_dboards > 2) {
- UHD_LOG_ERROR("EISCAT", "Detected too many dboards: " << _num_dboards);
- throw uhd::runtime_error("Too many dboards detected.");
- }
-
- UHD_LOG_INFO(
- "EISCAT",
- "Finalizing dboard initialization; initializing JESD cores and ADCs."
- );
-
- /* Start of the ADC synchronization operation.
- * These steps must be repeated if any ADC fails its deframer check
- * Changing the sync line from SyncbAB to SyncnCD usually resolves the error
- */
- const size_t possible_sync_combinations = 16; // 2 sync lines ^ (2 ADCs * 2 Daughtercards)
- for (size_t iteration = 0; iteration < possible_sync_combinations; iteration++) {
- UHD_LOG_INFO(
- "EISCAT",
- "looping to initialize JESD cores and ADCs."
- );
- if (not assert_jesd_cores_initialized()) {
- throw uhd::runtime_error("Failed to initialize JESD cores and reset ADCs!");
- }
- send_sysref();
-
- if (not assert_adcs_deframers()) {
- throw uhd::runtime_error("Failed to initialize ADCs and JESD deframers!");
- }
- send_sysref();
- std::this_thread::sleep_for(std::chrono::milliseconds(500));
-
- if (assert_deframer_status()) {
- return;
- }
- }
-
- // Unable to find a sync line combination which works
- throw uhd::runtime_error("Failed to finalize JESD core setup!");
-}
-
-/****************************************************************************
- * Internal methods
- ***************************************************************************/
-void eiscat_radio_ctrl_impl::write_fir_taps(
- const size_t fir_idx,
- const std::vector<eiscat_radio_ctrl_impl::fir_tap_t> &taps
-) {
- if (taps.size() > EISCAT_NUM_FIR_TAPS) {
- throw uhd::value_error(str(
- boost::format("Too many FIR taps for EISCAT filters (%d)")
- % taps.size()
- ));
- }
- for (const auto &tap: taps) {
- if (tap > EISCAT_MAX_TAP_VALUE or tap < EISCAT_MIN_TAP_VALUE) {
- throw uhd::value_error(str(
- boost::format("Filter tap for filter_idx %d exceeds dynamic range (%d bits are allowed)")
- % fir_idx % EISCAT_BITS_PER_TAP
- ));
- }
- }
-
- UHD_LOG_TRACE("EISCAT", str(
- boost::format("Writing %d filter taps for filter index %d")
- % taps.size() % fir_idx
- ));
- for (size_t i = 0; i < EISCAT_NUM_FIR_TAPS; i++) {
- // Payload:
- // - bottom 14 bits address, fir_idx * 16 + tap_index
- // - top 18 bits are value
- uint32_t reg_value = (fir_idx * 16) + i;;
- if (taps.size() > i) {
- reg_value |= (taps[i] & 0x3FFFF) << 14;
- }
- sr_write("SR_FIR_BRAM_WRITE_TAPS", reg_value);
- }
-}
-
-void eiscat_radio_ctrl_impl::select_filter(
- const size_t beam_index,
- const size_t antenna_index,
- const size_t fir_index,
- const uhd::time_spec_t &time_spec,
- const bool write_time
-) {
- if (antenna_index >= EISCAT_NUM_ANTENNAS) {
- throw uhd::value_error(str(
- boost::format("Antenna index %d out of range. There are %d antennas in EISCAT.")
- % antenna_index % EISCAT_NUM_ANTENNAS
- ));
- }
- if (beam_index >= EISCAT_NUM_BEAMS) {
- throw uhd::value_error(str(
- boost::format("Beam index %d out of range. "
- "There are %d beam channels in EISCAT.")
- % beam_index
- % EISCAT_NUM_BEAMS
- ));
- }
-
- UHD_LOGGER_TRACE("EISCAT")
- << "Selecting filter " << fir_index
- << " for beam " << beam_index
- << " and antenna " << antenna_index
- ;
- bool send_now = (time_spec == uhd::time_spec_t(0.0));
- uint32_t reg_value = 0
- | (fir_index * 16)
- | (antenna_index & 0xF) << 14
- | (beam_index & 0xF) << 18
- | send_now << 22
- ;
- if (not send_now) {
- UHD_LOG_TRACE("EISCAT", str(
- boost::format("Filter selection will be applied at "
- "time %f (0x%016X == %u). %s")
- % time_spec.get_full_secs()
- % time_spec.to_ticks(EISCAT_TICK_RATE)
- % time_spec.to_ticks(EISCAT_TICK_RATE)
- % (write_time ? "Writing time regs now."
- : "Assuming time regs already up-to-date.")
- ));
- if (write_time) {
- set_fir_ctrl_time(time_spec);
- }
- }
- sr_write("SR_FIR_COMMANDS_RELOAD", reg_value);
-}
-
-void eiscat_radio_ctrl_impl::set_fir_ctrl_time(
- const uhd::time_spec_t &time_spec
-) {
- const uint64_t cmd_time_ticks = time_spec.to_ticks(EISCAT_TICK_RATE);
- sr_write(
- "SR_FIR_COMMANDS_CTRL_TIME_LO",
- uint32_t(cmd_time_ticks & 0xFFFFFFFF)
- );
- sr_write(
- "SR_FIR_COMMANDS_CTRL_TIME_HI",
- uint32_t((cmd_time_ticks >> 32) & 0xFFFFFFFF)
- );
-}
-
-void eiscat_radio_ctrl_impl::set_antenna_gain(
- const size_t antenna_idx,
- const double normalized_gain
-) {
- if (normalized_gain < -16.0 or normalized_gain > 16.0) {
- throw uhd::value_error(str(
- boost::format("Invalid digital gain value for antenna %d: %f")
- % antenna_idx % normalized_gain
- ));
- }
-
- const auto fixpoint_gain = std::max<int32_t>(
- EISCAT_MIN_GAIN,
- std::min(
- EISCAT_MAX_GAIN,
- int32_t(normalized_gain * EISCAT_UNIT_GAIN)
- )
- );
-
- UHD_LOG_TRACE("EISCAT", str(
- boost::format("Setting digital gain value for antenna %d to %f (%d)")
- % antenna_idx % normalized_gain % fixpoint_gain
- ));
- sr_write(SR_ANTENNA_GAIN_BASE + antenna_idx, fixpoint_gain);
-}
-
-void eiscat_radio_ctrl_impl::configure_beams(uint32_t reg_value)
-{
- UHD_LOGGER_TRACE("EISCAT")
- << "Selecting " <<
- ((reg_value & EISCAT_CONTRIB_UPPER) ? "upper" : "lower") << " beams.";
- UHD_LOGGER_TRACE("EISCAT")
- << ((reg_value & EISCAT_SKIP_NEIGHBOURS) ? "Disabling" : "Enabling")
- << " neighbour contributions.";
- UHD_LOGGER_TRACE("EISCAT")
- << ((reg_value & EISCAT_BYPASS_MATRIX) ? "Disabling" : "Enabling")
- << " FIR matrix.";
- UHD_LOGGER_TRACE("EISCAT")
- << ((reg_value & EISCAT_OUTPUT_COUNTER) ? "Enabling" : "Disabling")
- << " counter.";
- UHD_LOG_TRACE("EISCAT", str(
- boost::format("Setting SR_BEAMS_TO_NEIGHBOR to 0x%08X.")
- % reg_value
- ));
- sr_write("SR_BEAMS_TO_NEIGHBOR", reg_value);
-}
-
-void eiscat_radio_ctrl_impl::set_beam_selection(int beam_selection)
-{
- UHD_ASSERT_THROW(beam_selection < 4 and beam_selection >= 0);
- const uint32_t old_value = user_reg_read32(RB_CHOOSE_BEAMS);
- const uint32_t new_value =
- (old_value & (~uint32_t(EISCAT_CONTRIB_UPPER|EISCAT_SKIP_NEIGHBOURS)))
- | (uint32_t(beam_selection)
- & uint32_t(EISCAT_CONTRIB_UPPER|EISCAT_SKIP_NEIGHBOURS))
- ;
- configure_beams(new_value);
-}
-
-void eiscat_radio_ctrl_impl::enable_firs(bool enable)
-{
- const uint32_t old_value = user_reg_read32(RB_CHOOSE_BEAMS);
- const uint32_t new_value = enable ?
- (old_value & ~EISCAT_BYPASS_MATRIX)
- : old_value | EISCAT_BYPASS_MATRIX
- ;
- configure_beams(new_value);
-}
-
-void eiscat_radio_ctrl_impl::send_sysref()
-{
- if (_block_args.has_key("use_mpm_sysref")) {
- _rpcc->notify_with_token("db_0_send_sysref");
- } else {
- // This value needs to be big enough that we actually hit it between
- // reading back the time, and applying the command:
- const int CMD_DELAY_MS = 100;
- auto sysref_time = get_time_now()
- + uhd::time_spec_t(double(CMD_DELAY_MS * 1000));
- uint64_t sysref_time_ticks = sysref_time.to_ticks(EISCAT_TICK_RATE);
- // The tick value must be even, or we'd still have the 180 degree phase
- // ambiguity! The actual value doesn't matter.
- sysref_time_ticks += sysref_time_ticks % 2;
- set_command_time(uhd::time_spec_t::from_ticks(
- sysref_time_ticks, EISCAT_TICK_RATE
- ));
- this->sr_write("SR_SYSREF", 1);
- std::this_thread::sleep_for(std::chrono::milliseconds(CMD_DELAY_MS));
- }
-}
-
-void eiscat_radio_ctrl_impl::enable_counter(bool enable)
-{
- const uint32_t old_value = user_reg_read32(RB_CHOOSE_BEAMS);
- const uint32_t new_value = enable ?
- old_value | EISCAT_OUTPUT_COUNTER
- : (old_value & ~EISCAT_OUTPUT_COUNTER)
- ;
- configure_beams(new_value);
-}
-
-bool eiscat_radio_ctrl_impl::assert_jesd_cores_initialized()
-{
- if (_num_dboards == 1) {
- return _rpcc->request_with_token<bool>("db_0_init_jesd_core_reset_adcs");
- }
- return _rpcc->request_with_token<bool>("db_0_init_jesd_core_reset_adcs")
- and _rpcc->request_with_token<bool>("db_1_init_jesd_core_reset_adcs");
-}
-
-bool eiscat_radio_ctrl_impl::assert_adcs_deframers()
-{
- if (_num_dboards == 1) {
- return _rpcc->request_with_token<bool>("db_0_init_adcs_and_deframers");
- }
- return _rpcc->request_with_token<bool>("db_0_init_adcs_and_deframers")
- and _rpcc->request_with_token<bool>("db_1_init_adcs_and_deframers");
-}
-
-bool eiscat_radio_ctrl_impl::assert_deframer_status()
-{
- if (_num_dboards == 1) {
- return _rpcc->request_with_token<bool>("db_0_check_deframer_status");
- }
- return _rpcc->request_with_token<bool>("db_0_check_deframer_status")
- and _rpcc->request_with_token<bool>("db_1_check_deframer_status");
-}
-
-/****************************************************************************
- * Registry
- ***************************************************************************/
-UHD_RFNOC_BLOCK_REGISTER(eiscat_radio_ctrl, "EISCATRadio");
diff --git a/host/lib/usrp/dboard/eiscat/eiscat_radio_ctrl_impl.hpp b/host/lib/usrp/dboard/eiscat/eiscat_radio_ctrl_impl.hpp
deleted file mode 100644
index 3ce0b48fd..000000000
--- a/host/lib/usrp/dboard/eiscat/eiscat_radio_ctrl_impl.hpp
+++ /dev/null
@@ -1,295 +0,0 @@
-//
-// Copyright 2017 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#ifndef INCLUDED_LIBUHD_RFNOC_EISCAT_RADIO_CTRL_IMPL_HPP
-#define INCLUDED_LIBUHD_RFNOC_EISCAT_RADIO_CTRL_IMPL_HPP
-
-#include <uhd/types/direction.hpp>
-#include <uhdlib/rfnoc/rpc_block_ctrl.hpp>
-#include <uhdlib/rfnoc/radio_ctrl_impl.hpp>
-
-namespace uhd {
- namespace rfnoc {
-
-/*! \brief Provide access to an EISCAT radio, including beamformer.
- *
- * Note: This will control both daughterboards. Since we have a single RFNoC
- * block, we only have one of these per motherboard.
- *
- * EISCAT radios have a whole bunch of features which don't have APIs provided
- * by radio_ctrl. This means the most interesting features are controlled by
- * set_arg() and get_arg(). Notable exception is set_rx_antenna(), which is
- * heavily abused for all sorts of things.
- *
- * List of relevant args:
- * - sysref (bool): Write to this to trigger a SYSREF pulse to *both*
- * daughterboards. Will honor command time. Will always return
- * true when read.
- * - gain (double): Set the gain for antenna X, where X is the set_arg() `port`
- * value. The gain is normalized in [0,1]. Can be read to get
- * the current value. Example: `set_arg("gain", 0.5, 5)` will
- * set the digital gain for antenna 5 to mid-point.
- * - fir_ctrl_time (time_spec_t): This time will be used for following
- * fir_select writes. Will return the last value
- * that was written.
- * - fir_select (int): Will queue a filter for manipulating a specific
- * contribution. The value is the filter index in the BRAM.
- * The port parameter specifies which filter; filters are
- * indexed 0...159 using the equation beam_index * 16 +
- * antenna_idx. Example: `set_arg("fir_select", 357, 16)`
- * will apply filter number 357 to the zeroth antenna for
- * beam number 1 (i.e. the second beam). Returns the last
- * value that was written. May be incorrect before written
- * for the first time.
- * - fir_taps (vector<int32_t>): Updates FIR tap values in the BRAM. Port is
- * the filter index. Will always return an impulse
- * response, not the actual filter value.
- * - assert_adcs_deframers (bool): Writing this does nothing. Reading it back
- * will run the initialization of ADCs and
- * deframers. Return value is success.
- * - assert_deframer_status (bool): Writing this does nothing. Reading it will
- * run the final step of the JESD deframer
- * initialization routine. Returns success.
- * - choose_beams (int): Configures beam selection (upper, lower, are neighbour
- * contributions included). See set_beam_selection() for
- * details.
- * - enable_firs (int): Can be used to disable fir FIR matrix. This routes the
- * JESD output directly to the noc_shell.
- * - enable_counter (int): If the feature is available in the given FPGA image,
- * setting this to true will disable the JESD core
- * output and will input a counter signal (ramp)
- * instead.
- * - configure_beams (int): Danger, danger: Directly writes the
- * SR_BEAMS_TO_NEIGHBOR register. Writing this can put
- * some of the other properties out of sync, because
- * writing to those will also write to this, but not
- * vice versa.
- *
- *
- * ## Time-aligned synchronization sequence:
- *
- * 0. Make sure all devices are getting the same ref clock and PPS!
- * 1. Call set_command_time() with the same time on all blocks (make it far
- * enough in the future)
- * 2. Call set_arg<bool>("sysref") on all blocks. This should SYSREF all dboards
- * synchronously.
- * 3. On all blocks, call get_arg<bool>("assert_adcs_deframers") and verify it
- * returns true.
- * 4. Repeat steps 1 and 2 with, obviously, another time that's in the future.
- * 5. On all blocks, call get_arg<bool>("assert_deframer_status") and make sure
- * it returned true.
- */
-class eiscat_radio_ctrl_impl : public radio_ctrl_impl, public rpc_block_ctrl
-{
-public:
- using sptr = boost::shared_ptr<eiscat_radio_ctrl_impl>;
- using fir_tap_t = int32_t; // See also EISCAT_BITS_PER_TAP
-
- /************************************************************************
- * Structors
- ***********************************************************************/
- UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR_DECL(eiscat_radio_ctrl)
- virtual ~eiscat_radio_ctrl_impl();
-
- /************************************************************************
- * API calls
- * Note: Tx calls are here mostly to throw errors.
- ***********************************************************************/
- //! Returns the actual tick rate. Will display a warning if rate is not that
- // value.
- double set_rate(double rate);
-
- //! \throws uhd::runtime_error
- void set_tx_antenna(const std::string &ant, const size_t chan);
-
- /*! Configures FPGA switching for antenna selection
- *
- * Valid antenna values:
- * - BF: This is the default. Will apply the beamforming matrix in whatever
- * state it currently is.
- * - RX0...RX15: Will mux the antenna signal 0...15 straight to this
- * channel. Note that this will disable the FIR matrix entirely, and will
- * also disable contributions from other USRPs globally.
- * - BF0...BF15: Will configure the FIR filter matrix such that only the
- * contributions from antenna 0...15 are passed to this channel. This
- * should produce the same signal as RX0..RX15, reduced by 12 dB (because
- * the FIR matri needs to account for bit growth from adding 16 channels).
- * Will also disable contributions from other channels globally.
- * - FI$idx: Here, $idx is a number (the filter index, hence the name).
- * This will apply filter index $idx to all input channels. Useful for
- * testing actual beamforming applications, when the same signal is
- * applied to all inputs.
- *
- * Note that this is very useful for testing and debugging. For actual
- * beamforming operations, this API call won't be enough. Rather, set this
- * to 'BF' (or don't do anything) and use the block properties
- *
- * \throws uhd::value_error if the antenna value was not valid
- */
- void set_rx_antenna(const std::string &ant, const size_t chan);
-
- //! \throws uhd::runtime_error
- double set_tx_frequency(const double freq, const size_t chan);
- //! \returns Some value in the EISCAT passband
- double set_rx_frequency(const double freq, const size_t chan);
- //! \returns Width of the EISCAT analog frontend filters
- double set_rx_bandwidth(const double bandwidth, const size_t chan);
- //! \throws uhd::runtime_error
- double get_tx_frequency(const size_t chan);
-
- //! \throws uhd::runtime_error
- double set_tx_gain(const double gain, const size_t chan);
- //! \returns zero
- double set_rx_gain(const double gain, const size_t chan);
-
- size_t get_chan_from_dboard_fe(const std::string &fe, const uhd::direction_t dir);
- std::string get_dboard_fe_from_chan(const size_t chan, const uhd::direction_t dir);
-
- //! \returns The EISCAT sampling rate
- double get_output_samp_rate(size_t port);
-
- void set_rx_streamer(bool active, const size_t port);
- void issue_stream_cmd(const uhd::stream_cmd_t &stream_cmd, const size_t port);
-
-protected:
- virtual bool check_radio_config();
-
- /*! Finalize initialization sequence (ADCs, deframers) etc.
- */
- void set_rpc_client(
- uhd::rpc_client::sptr rpcc,
- const uhd::device_addr_t &block_args
- );
-
-private:
- /*************************************************************************
- * Private methods
- * To control the dboard (and execute these), take a look at the block
- * properties.
- ************************************************************************/
- /*! Write filter taps for a specific FIR filter.
- *
- * Note: If the number of taps is smaller than the number of available
- * filter taps, it is padded with zero (i.e., all taps are always written
- * and this can't be use to partially update filters).
- *
- * \param fir_idx The index of the FIR filter we are reprogramming
- * \param taps A list of FIR filter taps for this filter.
- *
- * \throws uhd::value_error if the number of taps is longer than the number
- * of taps that the filter can handle, or if any
- * tap has more bits than allowed.
- */
- void write_fir_taps(
- const size_t fir_idx,
- const std::vector<fir_tap_t> &taps
- );
-
- /*! Choose a filter to be applied between an output beam and antenna input
- *
- * \param beam_index Beam index
- * \param antenna_index Antenna index
- * \param fir_index The index of the FIR filter taps that get applied
- * \param time_spec If non-zero, the taps get applied at this time.
- * Otherwise, they get sent out now.
- * \param write_time If false, time will never get written *even if* it is
- * non-zero. The assumption is that someone else wrote
- * the value previously
- * \param write_time If false, time will never get written *even if* it is
- * non-zero. The assumption is that someone else wrote
- * the value previously
- */
- void select_filter(
- const size_t beam_index,
- const size_t antenna_index,
- const size_t fir_index,
- const uhd::time_spec_t &time_spec,
- const bool write_time=true
- );
-
-
- /*! Sets the command time for the next call to select_filter()
- *
- * \param time_spec This value gets written to the FPGA and is applied to
- * *all* subsequent filter selections. To request
- * immediate application of filters, set this to zero.
- */
- void set_fir_ctrl_time(const uhd::time_spec_t &time_spec);
-
- /*! Sets the digital gain on a specific antenna
- *
- * \param antenna_idx Antenna for which this gain setting applies
- * \param normalized_gain A value in [0, 1] which gets converted to a
- * digital gain value
- */
- void set_antenna_gain(
- const size_t antenna_idx,
- const double normalized_gain
- );
-
- /*! Directly writes a value to the beam configuration register.
- */
- void configure_beams(uint32_t reg_value);
-
- /*! Controls selection of beams coming from the FIR matrix.
- *
- * The following values are allowed:
- * - 0: We stream the lower 5 beams, plus the neighbours contribution
- * - 1: We stream the upper 5 beams, plus the neighbours contribution
- * - 2: We stream the lower 5 beams, without the neighbours contribution
- * - 3: We stream the upper 5 beams, without the neighbours contribution
- */
- void set_beam_selection(int beam_selection);
-
- /*! Controls if we're using the FIR matrix
- *
- * If this is false, the beam selection is irrelevant.
- */
- void enable_firs(bool enable);
-
- /*! Enables counter instead of JESD core output
- */
- void enable_counter(bool enable);
-
- //! Sends a SYSREF pulse. Device arg use_mpm_sysref can be used to send it
- // via MPM. Default is to send it via CHDR, in which case calling this
- // function *will modify the command time!*, but it will ensure that the
- // sysref is sent on an even time
- void send_sysref();
-
- //! Run initialization of JESD cores, put ADCs into reset
- bool assert_jesd_cores_initialized();
-
- //! Run initialization of ADCs and deframers; returns success status
- bool assert_adcs_deframers();
-
- //! Run final step of JESD core setup; returns success status
- bool assert_deframer_status();
-
- /*! The number of channels this block outputs
- *
- * This is *not* the number of antennas, but the number of streams a single
- * block outputs to the crossbar.
- */
- size_t _num_ports;
-
- //! Running with 1 dboard is theoretically possible; thus, store the
- // number of active dboards.
- size_t _num_dboards = 0;
-
- //! Additional block args; gets set during set_rpc_client()
- uhd::device_addr_t _block_args;
-
- /*! Reference to the RPC client
- */
- uhd::rpc_client::sptr _rpcc;
-
-}; /* class radio_ctrl_impl */
-
-}} /* namespace uhd::rfnoc */
-
-#endif /* INCLUDED_LIBUHD_RFNOC_EISCAT_RADIO_CTRL_IMPL_HPP */
-
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_control.cpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_control.cpp
index dc78cee7d..13186e146 100644
--- a/host/lib/usrp/dboard/magnesium/magnesium_radio_control.cpp
+++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_control.cpp
@@ -1,5 +1,6 @@
//
// Copyright 2017 Ettus Research, a National Instruments Company
+// Copyright 2019 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
@@ -8,9 +9,7 @@
#include "magnesium_constants.hpp"
#include "magnesium_gain_table.hpp"
#include <uhd/exception.hpp>
-#include <uhd/rfnoc/node_ctrl_base.hpp>
#include <uhd/rfnoc/registry.hpp>
-#include <uhd/transport/chdr.hpp>
#include <uhd/types/direction.hpp>
#include <uhd/types/eeprom.hpp>
#include <uhd/utils/algorithm.hpp>
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_control_init.cpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_control_init.cpp
index db2ec9494..d8a1ccba8 100644
--- a/host/lib/usrp/dboard/magnesium/magnesium_radio_control_init.cpp
+++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_control_init.cpp
@@ -6,7 +6,6 @@
#include "magnesium_constants.hpp"
#include "magnesium_radio_control.hpp"
-#include <uhd/transport/chdr.hpp>
#include <uhd/types/eeprom.hpp>
#include <uhd/types/sensors.hpp>
#include <uhd/utils/log.hpp>
diff --git a/host/lib/usrp/dboard/rhodium/rhodium_radio_control.cpp b/host/lib/usrp/dboard/rhodium/rhodium_radio_control.cpp
index a3b072e74..df2c3aadd 100644
--- a/host/lib/usrp/dboard/rhodium/rhodium_radio_control.cpp
+++ b/host/lib/usrp/dboard/rhodium/rhodium_radio_control.cpp
@@ -9,7 +9,6 @@
#include "rhodium_constants.hpp"
#include <uhd/exception.hpp>
#include <uhd/rfnoc/registry.hpp>
-#include <uhd/transport/chdr.hpp>
#include <uhd/types/direction.hpp>
#include <uhd/types/eeprom.hpp>
#include <uhd/utils/algorithm.hpp>
diff --git a/host/lib/usrp/dboard/rhodium/rhodium_radio_control_init.cpp b/host/lib/usrp/dboard/rhodium/rhodium_radio_control_init.cpp
index d6b7afd09..850e5aff3 100644
--- a/host/lib/usrp/dboard/rhodium/rhodium_radio_control_init.cpp
+++ b/host/lib/usrp/dboard/rhodium/rhodium_radio_control_init.cpp
@@ -7,7 +7,6 @@
#include "rhodium_constants.hpp"
#include "rhodium_radio_control.hpp"
-#include <uhd/transport/chdr.hpp>
#include <uhd/types/eeprom.hpp>
#include <uhd/types/sensors.hpp>
#include <uhd/utils/algorithm.hpp>
diff --git a/host/lib/usrp/device3/CMakeLists.txt b/host/lib/usrp/device3/CMakeLists.txt
deleted file mode 100644
index 979225c2c..000000000
--- a/host/lib/usrp/device3/CMakeLists.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-#
-# Copyright 2014 Ettus Research LLC
-# Copyright 2018 Ettus Research, a National Instruments Company
-#
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-
-########################################################################
-# This file included, use CMake directory variables
-########################################################################
-
-LIBUHD_APPEND_SOURCES(
- ${CMAKE_CURRENT_SOURCE_DIR}/device3_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/device3_io_impl.cpp
-)
diff --git a/host/lib/usrp/device3/device3_flow_ctrl.hpp b/host/lib/usrp/device3/device3_flow_ctrl.hpp
deleted file mode 100644
index fd445effd..000000000
--- a/host/lib/usrp/device3/device3_flow_ctrl.hpp
+++ /dev/null
@@ -1,306 +0,0 @@
-//
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#ifndef INCLUDED_DEVICE3_FLOW_CTRL_HPP
-#define INCLUDED_DEVICE3_FLOW_CTRL_HPP
-
-#include "device3_impl.hpp"
-#include <uhd/transport/vrt_if_packet.hpp>
-#include <uhd/transport/zero_copy.hpp>
-#include <uhd/types/sid.hpp>
-#include <uhd/utils/log.hpp>
-#include <boost/shared_ptr.hpp>
-
-namespace uhd { namespace usrp {
-
-//! Stores the state of RX flow control
-struct rx_fc_cache_t
-{
- rx_fc_cache_t()
- : interval(0)
- , last_byte_count(0)
- , total_bytes_consumed(0)
- , total_packets_consumed(0)
- , seq_num(0)
- {
- }
-
- //! Flow control interval in bytes
- size_t interval;
- //! Byte count at last flow control packet
- uint32_t last_byte_count;
- //! This will wrap around, but that's OK, because math.
- uint32_t total_bytes_consumed;
- //! This will wrap around, but that's OK, because math.
- uint32_t total_packets_consumed;
- //! Sequence number of next flow control packet
- uint64_t seq_num;
- uhd::sid_t sid;
- uhd::transport::zero_copy_if::sptr xport;
- std::function<uint32_t(uint32_t)> to_host;
- std::function<uint32_t(uint32_t)> from_host;
- std::function<void(
- const uint32_t* packet_buff, uhd::transport::vrt::if_packet_info_t&)>
- unpack;
- std::function<void(uint32_t* packet_buff, uhd::transport::vrt::if_packet_info_t&)>
- pack;
-};
-
-/*! Send out RX flow control packets.
- *
- * This function handles updating the counters for the consumed
- * bytes and packets, determines if a flow control message is
- * is necessary, and sends one if it is. Passing a nullptr for
- * the buff parameter will skip the counter update.
- *
- * \param fc_cache RX flow control state information
- * \param buff Receive buffer. Setting to nullptr will
- * skip the counter update.
- */
-inline bool rx_flow_ctrl(
- boost::shared_ptr<rx_fc_cache_t> fc_cache, uhd::transport::managed_buffer::sptr buff)
-{
- // If the caller supplied a buffer
- if (buff) {
- // Unpack the header
- uhd::transport::vrt::if_packet_info_t packet_info;
- packet_info.num_packet_words32 = buff->size() / sizeof(uint32_t);
- const uint32_t* pkt = buff->cast<const uint32_t*>();
- try {
- fc_cache->unpack(pkt, packet_info);
- } catch (const std::exception& ex) {
- // Log and ignore
- UHD_LOGGER_ERROR("RX FLOW CTRL")
- << "Error unpacking packet: " << ex.what() << std::endl;
- return true;
- }
-
- // Update counters assuming the buffer is a consumed packet
- if (not packet_info.error) {
- const size_t bytes = 4 * (packet_info.num_header_words32 + packet_info.num_payload_words32);
- fc_cache->total_bytes_consumed += bytes;
- fc_cache->total_packets_consumed++;
- }
- }
-
- // Just return if there is no need to send a flow control packet
- if (fc_cache->total_bytes_consumed - fc_cache->last_byte_count < fc_cache->interval) {
- return true;
- }
-
- // Time to send a flow control packet
- // Get a send buffer
- uhd::transport::managed_send_buffer::sptr fc_buff =
- fc_cache->xport->get_send_buff(0.0);
- if (not fc_buff) {
- throw uhd::runtime_error("rx_flowctrl timed out getting a send buffer");
- }
- uint32_t* pkt = fc_buff->cast<uint32_t*>();
-
- // load packet info
- uhd::transport::vrt::if_packet_info_t packet_info;
- packet_info.packet_type = uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_FC;
- packet_info.num_payload_words32 = uhd::usrp::DEVICE3_FC_PACKET_LEN_IN_WORDS32;
- packet_info.num_payload_bytes = packet_info.num_payload_words32 * sizeof(uint32_t);
- packet_info.packet_count = fc_cache->seq_num++;
- packet_info.sob = false;
- packet_info.eob = false;
- packet_info.error = false;
- packet_info.fc_ack = false;
- packet_info.sid = fc_cache->sid.get();
- packet_info.has_sid = true;
- packet_info.has_cid = false;
- packet_info.has_tsi = false;
- packet_info.has_tsf = false;
- packet_info.has_tlr = false;
-
- // Load Header:
- fc_cache->pack(pkt, packet_info);
- // Load Payload: Packet count, and byte count
- pkt[packet_info.num_header_words32 + uhd::usrp::DEVICE3_FC_PACKET_COUNT_OFFSET] =
- fc_cache->from_host(fc_cache->total_packets_consumed);
- pkt[packet_info.num_header_words32 + uhd::usrp::DEVICE3_FC_BYTE_COUNT_OFFSET] =
- fc_cache->from_host(fc_cache->total_bytes_consumed);
-
- // send the buffer over the interface
- fc_buff->commit(sizeof(uint32_t) * (packet_info.num_packet_words32));
-
- // update byte count
- fc_cache->last_byte_count = fc_cache->total_bytes_consumed;
-
- return true;
-}
-
-/*! Handle RX flow control ACK packets.
- *
- */
-inline void handle_rx_flowctrl_ack(
- boost::shared_ptr<rx_fc_cache_t> fc_cache, const uint32_t* payload)
-{
- const uint32_t pkt_count = fc_cache->to_host(payload[0]);
- const uint32_t byte_count = fc_cache->to_host(payload[1]);
- if (fc_cache->total_bytes_consumed != byte_count) {
- UHD_LOGGER_DEBUG("device3")
- << "oh noes: byte_count==" << byte_count
- << " total_bytes_consumed==" << fc_cache->total_bytes_consumed << std::hex
- << " sid==" << fc_cache->sid << std::dec << std::endl;
- }
- fc_cache->total_bytes_consumed = byte_count;
- fc_cache->total_packets_consumed = pkt_count; // guess we need a pkt offset too?
-
- // This will send a flow control packet if there is a significant discrepancy
- rx_flow_ctrl(fc_cache, nullptr);
-}
-
-//! Stores the state of TX flow control
-struct tx_fc_cache_t
-{
- tx_fc_cache_t(uint32_t capacity)
- : last_byte_ack(0)
- , last_seq_ack(0)
- , byte_count(0)
- , pkt_count(0)
- , window_size(capacity)
- , fc_ack_seqnum(0)
- , fc_received(false)
- {
- }
-
- uint32_t last_byte_ack;
- uint32_t last_seq_ack;
- uint32_t byte_count;
- uint32_t pkt_count;
- uint32_t window_size;
- uint32_t fc_ack_seqnum;
- bool fc_received;
- std::function<uint32_t(uint32_t)> to_host;
- std::function<uint32_t(uint32_t)> from_host;
- std::function<void(
- const uint32_t* packet_buff, uhd::transport::vrt::if_packet_info_t&)>
- unpack;
- std::function<void(uint32_t* packet_buff, uhd::transport::vrt::if_packet_info_t&)>
- pack;
-};
-
-inline bool tx_flow_ctrl(boost::shared_ptr<tx_fc_cache_t> fc_cache,
- uhd::transport::zero_copy_if::sptr xport,
- uhd::transport::managed_buffer::sptr buff)
-{
- while (true) {
- // If there is space
- if (fc_cache->window_size - (fc_cache->byte_count - fc_cache->last_byte_ack)
- >= buff->size()) {
- // All is good - packet will be sent
- fc_cache->byte_count += buff->size();
- // Round up to nearest word
- if (fc_cache->byte_count % uhd::usrp::DEVICE3_LINE_SIZE) {
- fc_cache->byte_count +=
- uhd::usrp::DEVICE3_LINE_SIZE
- - (fc_cache->byte_count % uhd::usrp::DEVICE3_LINE_SIZE);
- }
- fc_cache->pkt_count++;
- return true;
- }
-
- // Look for a flow control message to update the space available in the buffer.
- uhd::transport::managed_recv_buffer::sptr buff = xport->get_recv_buff(0.1);
- if (buff) {
- uhd::transport::vrt::if_packet_info_t if_packet_info;
- if_packet_info.num_packet_words32 = buff->size() / sizeof(uint32_t);
- const uint32_t* packet_buff = buff->cast<const uint32_t*>();
- try {
- fc_cache->unpack(packet_buff, if_packet_info);
- } catch (const std::exception& ex) {
- UHD_LOGGER_ERROR("TX FLOW CTRL")
- << "Error unpacking flow control packet: " << ex.what() << std::endl;
- continue;
- }
-
- if (if_packet_info.packet_type
- != uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_FC) {
- UHD_LOGGER_ERROR("TX FLOW CTRL")
- << "Unexpected packet received by flow control handler: "
- << if_packet_info.packet_type << std::endl;
- continue;
- }
-
- const uint32_t* payload = &packet_buff[if_packet_info.num_header_words32];
- const uint32_t pkt_count = fc_cache->to_host(payload[0]);
- const uint32_t byte_count = fc_cache->to_host(payload[1]);
-
- // update the amount of space
- fc_cache->last_byte_ack = byte_count;
- fc_cache->last_seq_ack = pkt_count;
-
- fc_cache->fc_received = true;
- }
- }
- return false;
-}
-
-inline void tx_flow_ctrl_ack(boost::shared_ptr<tx_fc_cache_t> fc_cache,
- uhd::transport::zero_copy_if::sptr send_xport,
- uhd::sid_t send_sid)
-{
- if (not fc_cache->fc_received) {
- return;
- }
-
- // Time to send a flow control ACK packet
- // Get a send buffer
- uhd::transport::managed_send_buffer::sptr fc_buff = send_xport->get_send_buff(0.0);
- if (not fc_buff) {
- UHD_LOGGER_ERROR("tx_flow_ctrl_ack") << "timed out getting a send buffer";
- return;
- }
- uint32_t* pkt = fc_buff->cast<uint32_t*>();
-
- // Load packet info
- uhd::transport::vrt::if_packet_info_t packet_info;
- packet_info.packet_type = uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_ACK;
- packet_info.num_payload_words32 = uhd::usrp::DEVICE3_FC_PACKET_LEN_IN_WORDS32;
- packet_info.num_payload_bytes = packet_info.num_payload_words32 * sizeof(uint32_t);
- packet_info.packet_count = fc_cache->fc_ack_seqnum++;
- packet_info.sob = false;
- packet_info.eob = true;
- packet_info.error = false;
- packet_info.fc_ack = false;
- packet_info.sid = send_sid.get();
- packet_info.has_sid = true;
- packet_info.has_cid = false;
- packet_info.has_tsi = false;
- packet_info.has_tsf = false;
- packet_info.has_tlr = false;
-
- // Load Header:
- fc_cache->pack(pkt, packet_info);
-
- // Update counters to include this packet
- size_t fc_ack_pkt_size = sizeof(uint32_t) * (packet_info.num_packet_words32);
- fc_cache->byte_count += fc_ack_pkt_size;
- // Round up to nearest word
- if (fc_cache->byte_count % uhd::usrp::DEVICE3_LINE_SIZE) {
- fc_cache->byte_count += uhd::usrp::DEVICE3_LINE_SIZE
- - (fc_cache->byte_count % uhd::usrp::DEVICE3_LINE_SIZE);
- }
- fc_cache->pkt_count++;
-
- // Load Payload: Packet count, and byte count
- pkt[packet_info.num_header_words32 + uhd::usrp::DEVICE3_FC_PACKET_COUNT_OFFSET] =
- fc_cache->from_host(fc_cache->pkt_count);
- pkt[packet_info.num_header_words32 + uhd::usrp::DEVICE3_FC_BYTE_COUNT_OFFSET] =
- fc_cache->from_host(fc_cache->byte_count);
-
- // Send the buffer over the interface
- fc_buff->commit(fc_ack_pkt_size);
-
- // Reset for next FC
- fc_cache->fc_received = false;
-}
-
-}}; // namespace uhd::usrp
-
-#endif /* INCLUDED_DEVICE3_FLOW_CTRL_HPP */
diff --git a/host/lib/usrp/device3/device3_impl.cpp b/host/lib/usrp/device3/device3_impl.cpp
deleted file mode 100644
index bc1cf9002..000000000
--- a/host/lib/usrp/device3/device3_impl.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-//
-// Copyright 2014-2016 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include "device3_impl.hpp"
-#include <uhd/rfnoc/block_ctrl_base.hpp>
-#include <uhd/utils/log.hpp>
-#include <uhdlib/rfnoc/ctrl_iface.hpp>
-#include <uhdlib/rfnoc/graph_impl.hpp>
-#include <boost/make_shared.hpp>
-#include <algorithm>
-
-using namespace uhd::usrp;
-
-device3_impl::device3_impl()
-{
- _type = uhd::device::USRP;
- _async_md.reset(new async_md_type(1000 /*messages deep*/));
- _tree = uhd::property_tree::make();
-};
-
-//! Returns true if the integer value stored in lhs is smaller than that in rhs
-bool _compare_string_indexes(const std::string& lhs, const std::string& rhs)
-{
- return boost::lexical_cast<size_t>(lhs) < boost::lexical_cast<size_t>(rhs);
-}
-
-void device3_impl::merge_channel_defs(const std::vector<uhd::rfnoc::block_id_t>& chan_ids,
- const std::vector<uhd::device_addr_t>& chan_args,
- const uhd::direction_t dir)
-{
- UHD_ASSERT_THROW(chan_ids.size() == chan_args.size());
- if (dir == uhd::DX_DIRECTION) {
- merge_channel_defs(chan_ids, chan_args, RX_DIRECTION);
- merge_channel_defs(chan_ids, chan_args, TX_DIRECTION);
- return;
- }
-
- uhd::fs_path chans_root =
- uhd::fs_path("/channels/") / (dir == RX_DIRECTION ? "rx" : "tx");
- // Store the new positions of the channels:
- std::vector<size_t> chan_idxs;
-
- // 1. Get sorted list of currently defined channels
- std::vector<std::string> curr_channels;
- if (_tree->exists(chans_root)) {
- curr_channels = _tree->list(chans_root);
- std::sort(curr_channels.begin(), curr_channels.end(), _compare_string_indexes);
- }
-
- // 2. Cycle through existing channels to find out where to merge
- // the new channels. Rules are:
- // - The order of chan_ids must be preserved
- // - All block indices that are in chan_ids may be overwritten in the channel
- // definition
- // - If the channels in chan_ids are not yet in the property tree channel list,
- // they are appended.
- for (const std::string& chan_idx : curr_channels) {
- if (_tree->exists(chans_root / chan_idx)) {
- rfnoc::block_id_t chan_block_id =
- _tree->access<rfnoc::block_id_t>(chans_root / chan_idx).get();
- if (std::find(chan_ids.begin(), chan_ids.end(), chan_block_id)
- != chan_ids.end()) {
- chan_idxs.push_back(boost::lexical_cast<size_t>(chan_idx));
- }
- }
- }
- size_t last_chan_idx = curr_channels.empty()
- ? 0
- : (boost::lexical_cast<size_t>(curr_channels.back()) + 1);
- while (chan_idxs.size() < chan_ids.size()) {
- chan_idxs.push_back(last_chan_idx);
- last_chan_idx++;
- }
-
- // 3. Write the new channels
- for (size_t i = 0; i < chan_ids.size(); i++) {
- if (not _tree->exists(chans_root / chan_idxs[i])) {
- _tree->create<rfnoc::block_id_t>(chans_root / chan_idxs[i]);
- }
- _tree->access<rfnoc::block_id_t>(chans_root / chan_idxs[i]).set(chan_ids[i]);
- if (not _tree->exists(chans_root / chan_idxs[i] / "args")) {
- _tree->create<uhd::device_addr_t>(chans_root / chan_idxs[i] / "args");
- }
- _tree->access<uhd::device_addr_t>(chans_root / chan_idxs[i] / "args")
- .set(chan_args[i]);
- }
-}
-
-/***********************************************************************
- * RFNoC-Specific
- **********************************************************************/
-void device3_impl::enumerate_rfnoc_blocks(size_t device_index,
- size_t n_blocks,
- size_t base_port,
- const uhd::sid_t& base_sid,
- uhd::device_addr_t transport_args)
-{
- // entries that are already connected to this block
- uhd::sid_t ctrl_sid = base_sid;
- uhd::property_tree::sptr subtree =
- _tree->subtree(uhd::fs_path("/mboards") / device_index);
- // 1) Clean property tree entries
- // TODO put this back once radios are actual rfnoc blocks!!!!!!
- // if (subtree->exists("xbar")) {
- // subtree->remove("xbar");
- //}
- // 2) Destroy existing block controllers
- // TODO: Clear out all the old block control classes
- // 3) Create new block controllers
- for (size_t i = 0; i < n_blocks; i++) {
- // First, make a transport for port number zero, because we always need that:
- ctrl_sid.set_dst_xbarport(base_port + i);
- ctrl_sid.set_dst_blockport(0);
- both_xports_t xport = this->make_transport(ctrl_sid, CTRL, transport_args);
- UHD_LOG_TRACE("DEVICE3",
- str(boost::format("Setting up NoC-Shell Control for port #0 (SID: %s)...")
- % xport.send_sid.to_pp_string_hex()));
- uhd::rfnoc::ctrl_iface::sptr ctrl = uhd::rfnoc::ctrl_iface::make(xport,
- str(boost::format("CE_%02d_Port_%02X") % i % ctrl_sid.get_dst_endpoint()));
- uint64_t noc_id = ctrl->send_cmd_pkt(
- uhd::rfnoc::SR_READBACK, uhd::rfnoc::SR_READBACK_REG_ID, true);
- UHD_LOG_DEBUG("DEVICE3",
- str(boost::format("Port 0x%02X: Found NoC-Block with ID %016X.")
- % int(ctrl_sid.get_dst_endpoint()) % noc_id));
- uhd::rfnoc::make_args_t make_args;
- uhd::rfnoc::blockdef::sptr block_def =
- uhd::rfnoc::blockdef::make_from_noc_id(noc_id);
- if (not block_def) {
- UHD_LOG_WARNING("DEVICE3",
- "No block definition found, using default block configuration "
- "for block with NOC ID: "
- + str(boost::format("0x%08X") % noc_id));
- block_def =
- uhd::rfnoc::blockdef::make_from_noc_id(uhd::rfnoc::DEFAULT_NOC_ID_64);
- }
- UHD_ASSERT_THROW(block_def);
- make_args.ctrl_ifaces[0] = ctrl;
- for (const size_t port_number : block_def->get_all_port_numbers()) {
- if (port_number == 0) { // We've already set this up
- continue;
- }
- ctrl_sid.set_dst_blockport(port_number);
- both_xports_t xport1 = this->make_transport(ctrl_sid, CTRL, transport_args);
- UHD_LOG_TRACE("DEVICE3",
- str(boost::format("Setting up NoC-Shell Control for port #%d "
- "(SID: %s)...")
- % port_number % xport1.send_sid.to_pp_string_hex()));
- uhd::rfnoc::ctrl_iface::sptr ctrl1 = uhd::rfnoc::ctrl_iface::make(xport1,
- str(boost::format("CE_%02d_Port_%02X") % i
- % ctrl_sid.get_dst_endpoint()));
- make_args.ctrl_ifaces[port_number] = ctrl1;
- }
- UHD_LOG_TRACE("DEVICE3",
- "All control transports successfully created for block with ID "
- << str(boost::format("0x%08X") % noc_id));
-
- make_args.base_address = xport.send_sid.get_dst();
- make_args.device_index = device_index;
- make_args.tree = subtree;
- { // Critical section for block_ctrl vector access
- boost::lock_guard<boost::mutex> lock(_block_ctrl_mutex);
- _rfnoc_block_ctrl.push_back(
- uhd::rfnoc::block_ctrl_base::make(make_args, noc_id));
- _rfnoc_block_ctrl.back()->set_graph_update_cb([this]() {
- update_rx_streamers();
- update_tx_streamers();
- });
- }
- }
-}
-
-
-uhd::rfnoc::graph::sptr device3_impl::create_graph(const std::string& name)
-{
- // Create an async message handler
- UHD_LOGGER_TRACE("DEVICE3")
- << "Creating async message handler for graph `" << name << "'...";
- // FIXME: right now this only can only handle source sid of 0 and xbar local addr
- // of 2. This is ok for now because that most of our device has xbard local addr
- // hardcode to 2.
- sid_t async_sid(0);
- async_sid.set_dst_addr(2);
- both_xports_t async_xports = make_transport(async_sid,
- ASYNC_MSG,
- // FIXME: only get rx_hints from mb index of 0
- get_rx_hints(0));
- UHD_LOGGER_TRACE("DEVICE3") << " Async transport ready." << std::endl;
- uhd::rfnoc::async_msg_handler::sptr async_msg_handler =
- uhd::rfnoc::async_msg_handler::make(async_xports.recv,
- async_xports.send,
- async_xports.send_sid,
- async_xports.endianness);
- UHD_LOGGER_TRACE("DEVICE3")
- << "Async message has address " << async_xports.send_sid << std::endl;
-
- // Create the graph
- UHD_LOGGER_TRACE("DEVICE3") << "Creating graph `" << name << "'..." << std::endl;
- uhd::rfnoc::graph::sptr graph = boost::make_shared<uhd::rfnoc::graph_impl>(
- name, shared_from_this(), async_msg_handler);
-
- return graph;
-}
diff --git a/host/lib/usrp/device3/device3_impl.hpp b/host/lib/usrp/device3/device3_impl.hpp
deleted file mode 100644
index 17f6a3f6f..000000000
--- a/host/lib/usrp/device3/device3_impl.hpp
+++ /dev/null
@@ -1,264 +0,0 @@
-//
-// Copyright 2014-2015 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-// Declares the device3_impl class which is a layer between device3 and
-// the different 3-rd gen device impls (e.g. x300_impl)
-
-#ifndef INCLUDED_DEVICE3_IMPL_HPP
-#define INCLUDED_DEVICE3_IMPL_HPP
-
-#include "../../transport/super_recv_packet_handler.hpp"
-#include "../../transport/super_send_packet_handler.hpp"
-#include <uhd/device3.hpp>
-#include <uhd/transport/bounded_buffer.hpp>
-#include <uhd/transport/chdr.hpp>
-#include <uhd/transport/vrt_if_packet.hpp>
-#include <uhd/transport/zero_copy.hpp>
-#include <uhd/types/direction.hpp>
-#include <uhd/types/endianness.hpp>
-#include <uhd/types/metadata.hpp>
-#include <uhd/types/sid.hpp>
-#include <uhd/utils/tasks.hpp>
-#include <uhdlib/rfnoc/rx_stream_terminator.hpp>
-#include <uhdlib/rfnoc/tx_stream_terminator.hpp>
-#include <uhdlib/rfnoc/xports.hpp>
-
-namespace uhd { namespace usrp {
-
-/***********************************************************************
- * Default settings (any device3 may override these)
- **********************************************************************/
-static const size_t DEVICE3_RX_FC_REQUEST_FREQ = 32; // per flow-control window
-static const size_t DEVICE3_TX_FC_RESPONSE_FREQ = 8;
-static const size_t DEVICE3_FC_PACKET_LEN_IN_WORDS32 = 2;
-static const size_t DEVICE3_FC_PACKET_COUNT_OFFSET = 0;
-static const size_t DEVICE3_FC_BYTE_COUNT_OFFSET = 1;
-static const size_t DEVICE3_LINE_SIZE = 8;
-
-static const size_t DEVICE3_TX_MAX_HDR_LEN =
- uhd::transport::vrt::chdr::max_if_hdr_words64 * sizeof(uint64_t); // Bytes
-static const size_t DEVICE3_RX_MAX_HDR_LEN =
- uhd::transport::vrt::chdr::max_if_hdr_words64 * sizeof(uint64_t); // Bytes
-
-// This class manages the lifetime of the TX async message handler task, transports, and
-// terminator
-class device3_send_packet_streamer : public uhd::transport::sph::send_packet_streamer
-{
-public:
- device3_send_packet_streamer(const size_t max_num_samps,
- const uhd::rfnoc::tx_stream_terminator::sptr terminator,
- const both_xports_t data_xport,
- const both_xports_t async_msg_xport)
- : uhd::transport::sph::send_packet_streamer(max_num_samps)
- , _terminator(terminator)
- , _data_xport(data_xport)
- , _async_msg_xport(async_msg_xport)
- {
- }
-
- ~device3_send_packet_streamer()
- {
- // Make sure the async task is destroyed before the transports
- _tx_async_msg_tasks.clear();
- }
-
- uhd::rfnoc::tx_stream_terminator::sptr get_terminator()
- {
- return _terminator;
- }
-
- void add_async_msg_task(task::sptr task)
- {
- _tx_async_msg_tasks.push_back(task);
- }
-
-private:
- uhd::rfnoc::tx_stream_terminator::sptr _terminator;
- both_xports_t _data_xport;
- both_xports_t _async_msg_xport;
- std::vector<task::sptr> _tx_async_msg_tasks;
-};
-
-// This class manages the lifetime of the RX transports and terminator and provides access
-// to both
-class device3_recv_packet_streamer : public uhd::transport::sph::recv_packet_streamer
-{
-public:
- device3_recv_packet_streamer(const size_t max_num_samps,
- const uhd::rfnoc::rx_stream_terminator::sptr terminator,
- const both_xports_t xport)
- : uhd::transport::sph::recv_packet_streamer(max_num_samps)
- , _terminator(terminator)
- , _xport(xport)
- {
- }
-
- ~device3_recv_packet_streamer() {}
-
- both_xports_t get_xport()
- {
- return _xport;
- }
-
- uhd::rfnoc::rx_stream_terminator::sptr get_terminator()
- {
- return _terminator;
- }
-
-private:
- uhd::rfnoc::rx_stream_terminator::sptr _terminator;
- both_xports_t _xport;
-};
-
-class device3_impl : public uhd::device3,
- public boost::enable_shared_from_this<device3_impl>
-{
-public:
- /***********************************************************************
- * device3-specific Types
- **********************************************************************/
- typedef uhd::transport::bounded_buffer<uhd::async_metadata_t> async_md_type;
-
- //! The purpose of a transport
- enum xport_type_t { CTRL = 0, ASYNC_MSG, TX_DATA, RX_DATA };
-
- enum xport_t { AXI, ETH, PCIE };
-
- //! Stores all streaming-related options
- struct stream_options_t
- {
- //! Max size of the header in bytes for TX
- size_t tx_max_len_hdr;
- //! Max size of the header in bytes for RX
- size_t rx_max_len_hdr;
- //! How often we send ACKs to the upstream block per one full FC window
- size_t rx_fc_request_freq;
- //! How often the downstream block should send ACKs per one full FC window
- size_t tx_fc_response_freq;
- stream_options_t(void)
- : tx_max_len_hdr(DEVICE3_TX_MAX_HDR_LEN)
- , rx_max_len_hdr(DEVICE3_RX_MAX_HDR_LEN)
- , rx_fc_request_freq(DEVICE3_RX_FC_REQUEST_FREQ)
- , tx_fc_response_freq(DEVICE3_TX_FC_RESPONSE_FREQ)
- {
- }
- };
-
- /***********************************************************************
- * I/O Interface
- **********************************************************************/
- uhd::tx_streamer::sptr get_tx_stream(const uhd::stream_args_t&);
- uhd::rx_streamer::sptr get_rx_stream(const uhd::stream_args_t&);
- bool recv_async_msg(uhd::async_metadata_t& async_metadata, double timeout);
-
- /***********************************************************************
- * Other public APIs
- **********************************************************************/
- rfnoc::graph::sptr create_graph(const std::string& name = "");
-
-protected:
- /***********************************************************************
- * Structors
- **********************************************************************/
- device3_impl();
- virtual ~device3_impl() {}
-
- /***********************************************************************
- * Streaming-related
- **********************************************************************/
-public: // TODO make these protected again
- /*! Update tick rate, samp rate, and scaling on the streamers by querying
- * the graph.
- */
- void update_rx_streamers();
- /*! Update tick rate, samp rate, and scaling on the streamers by querying
- * the graph.
- */
- void update_tx_streamers();
-
-protected:
- /***********************************************************************
- * Transport-related
- **********************************************************************/
- stream_options_t stream_options;
-
- /*! \brief Create a transport to a given endpoint.
- *
- * \param address The endpoint address of the block we're creating a transport to.
- * The source address in this value is not considered, only the
- * destination address.
- * \param xport_type Specify which kind of transport this is.
- * \param args Additional arguments for the transport generation. See \ref
- * page_transport for valid arguments.
- */
- virtual uhd::both_xports_t make_transport(const uhd::sid_t& address,
- const xport_type_t xport_type,
- const uhd::device_addr_t& args) = 0;
-
- virtual uhd::device_addr_t get_tx_hints(size_t)
- {
- return uhd::device_addr_t();
- }
- virtual uhd::device_addr_t get_rx_hints(size_t)
- {
- return uhd::device_addr_t();
- }
-
- //! Is called after a streamer is generated
- virtual void post_streamer_hooks(uhd::direction_t) {}
-
- //! get mtu
- virtual size_t get_mtu(const size_t, const uhd::direction_t) = 0;
-
- /***********************************************************************
- * Channel-related
- **********************************************************************/
- /*! Merge a list of channels into the existing channel definition.
- *
- * Intelligently merge the channels described in \p chan_ids
- * into the current channel definition. If none of the channels in
- * \p chan_ids is in the current definition, they simply get appended.
- * Otherwise, they get overwritten in the order of \p chan_ids.
- *
- * \param chan_ids List of block IDs for the channels.
- * \param chan_args New channel args. Must have same length as chan_ids.
- *
- */
- void merge_channel_defs(const std::vector<rfnoc::block_id_t>& chan_ids,
- const std::vector<uhd::device_addr_t>& chan_args,
- const uhd::direction_t dir);
-
- /***********************************************************************
- * RFNoC-Specific
- **********************************************************************/
- void enumerate_rfnoc_blocks(size_t device_index,
- size_t n_blocks,
- size_t base_port,
- const uhd::sid_t& base_sid,
- uhd::device_addr_t transport_args);
-
- /***********************************************************************
- * Members
- **********************************************************************/
- // TODO: Maybe move these to private
- uhd::dict<std::string, boost::weak_ptr<uhd::rx_streamer>> _rx_streamers;
- uhd::dict<std::string, boost::weak_ptr<uhd::tx_streamer>> _tx_streamers;
-
-private:
- /***********************************************************************
- * Private Members
- **********************************************************************/
- //! Buffer for async metadata
- boost::shared_ptr<async_md_type> _async_md;
-
- //! This mutex locks the get_xx_stream() functions.
- boost::mutex _transport_setup_mutex;
-};
-
-}} /* namespace uhd::usrp */
-
-#endif /* INCLUDED_DEVICE3_IMPL_HPP */
diff --git a/host/lib/usrp/device3/device3_io_impl.cpp b/host/lib/usrp/device3/device3_io_impl.cpp
deleted file mode 100644
index 800d2f5a8..000000000
--- a/host/lib/usrp/device3/device3_io_impl.cpp
+++ /dev/null
@@ -1,827 +0,0 @@
-//
-// Copyright 2014-2016 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-// Provides streaming-related functions which are used by device3 objects.
-
-#include "device3_flow_ctrl.hpp"
-#include "device3_impl.hpp"
-#include <uhd/rfnoc/constants.hpp>
-#include <uhd/rfnoc/radio_ctrl.hpp>
-#include <uhd/rfnoc/rate_node_ctrl.hpp>
-#include <uhd/rfnoc/sink_block_ctrl_base.hpp>
-#include <uhd/rfnoc/source_block_ctrl_base.hpp>
-#include <uhd/transport/zero_copy_flow_ctrl.hpp>
-#include <uhd/utils/byteswap.hpp>
-#include <uhd/utils/log.hpp>
-#include <uhdlib/rfnoc/rx_stream_terminator.hpp>
-#include <uhdlib/rfnoc/tx_stream_terminator.hpp>
-#include <uhdlib/usrp/common/async_packet_handler.hpp>
-#include <boost/atomic.hpp>
-
-#define UHD_TX_STREAMER_LOG() UHD_LOGGER_TRACE("STREAMER")
-#define UHD_RX_STREAMER_LOG() UHD_LOGGER_TRACE("STREAMER")
-
-using namespace uhd;
-using namespace uhd::usrp;
-using namespace uhd::transport;
-
-/***********************************************************************
- * Helper functions for get_?x_stream()
- **********************************************************************/
-static uhd::stream_args_t sanitize_stream_args(const uhd::stream_args_t& args_)
-{
- uhd::stream_args_t args = args_;
- if (args.channels.empty()) {
- args.channels = std::vector<size_t>(1, 0);
- }
-
- return args;
-}
-
-static void check_stream_sig_compatible(
- const rfnoc::stream_sig_t& stream_sig, stream_args_t& args, const std::string& tx_rx)
-{
- if (args.otw_format.empty()) {
- if (stream_sig.item_type.empty()) {
- throw uhd::runtime_error(
- str(boost::format("[%s Streamer] No otw_format defined!") % tx_rx));
- } else {
- args.otw_format = stream_sig.item_type;
- }
- } else if (not stream_sig.item_type.empty()
- and stream_sig.item_type != args.otw_format) {
- throw uhd::runtime_error(
- str(boost::format("[%s Streamer] Conflicting OTW types defined: "
- "args.otw_format = '%s' <=> stream_sig.item_type = '%s'")
- % tx_rx % args.otw_format % stream_sig.item_type));
- }
- const size_t bpi = convert::get_bytes_per_item(args.otw_format); // bytes per item
- if (stream_sig.packet_size) {
- if (args.args.has_key("spp")) {
- size_t args_spp = args.args.cast<size_t>("spp", 0);
- if (args_spp * bpi != stream_sig.packet_size) {
- throw uhd::runtime_error(
- str(boost::format(
- "[%s Streamer] Conflicting packet sizes defined: args yields "
- "%d bytes but stream_sig.packet_size is %d bytes")
- % tx_rx % (args_spp * bpi) % stream_sig.packet_size));
- }
- } else {
- args.args["spp"] = str(boost::format("%d") % (stream_sig.packet_size / bpi));
- }
- }
-}
-
-/*! \brief Returns a list of rx or tx channels for a streamer.
- *
- * If the given stream args contain instructions to set up channels,
- * those are used. Otherwise, the current device's channel definition
- * is consulted.
- *
- * \param args_ Stream args.
- * \param[out] chan_list The list of channels in the correct order.
- * \param[out] chan_args Channel args for every channel. `chan_args.size() ==
- * chan_list.size()`
- */
-void generate_channel_list(const uhd::stream_args_t& args_,
- std::vector<uhd::rfnoc::block_id_t>& chan_list,
- std::vector<device_addr_t>& chan_args)
-{
- uhd::stream_args_t args = args_;
- std::vector<uhd::rfnoc::block_id_t> chan_list_(args.channels.size());
- std::vector<device_addr_t> chan_args_(args.channels.size());
-
- for (size_t i = 0; i < args.channels.size(); i++) {
- // Extract block ID
- size_t chan_idx = args.channels[i];
- std::string key = str(boost::format("block_id%d") % chan_idx);
- if (args.args.has_key(key)) {
- chan_list_[i] = args.args.pop(key);
- } else if (args.args.has_key("block_id")) {
- chan_list_[i] = args.args["block_id"];
- } else {
- throw uhd::runtime_error(
- str(boost::format(
- "Cannot create streamers: No block_id specified for channel %d.")
- % chan_idx));
- }
-
- // Split off known channel specific args
- key = str(boost::format("block_port%d") % chan_idx);
- if (args.args.has_key(key)) {
- chan_args_[i]["block_port"] = args.args.pop(key);
- }
- key = str(boost::format("radio_id%d") % chan_idx);
- if (args.args.has_key(key)) {
- chan_args_[i]["radio_id"] = args.args.pop(key);
- }
- key = str(boost::format("radio_port%d") % chan_idx);
- if (args.args.has_key(key)) {
- chan_args_[i]["radio_port"] = args.args.pop(key);
- }
- }
-
- // Add all remaining args to all channel args
- for (device_addr_t& chan_arg : chan_args_) {
- chan_arg = chan_arg.to_string() + "," + args.args.to_string();
- }
-
- chan_list = chan_list_;
- chan_args = chan_args_;
-}
-
-
-/***********************************************************************
- * RX Flow Control Functions
- **********************************************************************/
-/*! Determine the size of the flow control window in number of packets.
- *
- * This value depends on three things:
- * - The packet size (in bytes), P
- * - The size of the software buffer (in bytes), B
- * - The desired buffer fullness, F
- *
- * The FC window size is thus X = floor(B*F/P).
- *
- * \param pkt_size The maximum packet size in bytes
- * \param sw_buff_size Software buffer size in bytes
- * \param rx_args If this has a key 'recv_buff_fullness', this value will
- * be used for said fullness. Must be between 0.01 and 1.
- *
- * \returns The size of the flow control window in number of packets
- */
-static size_t get_rx_flow_control_window(
- size_t pkt_size, size_t sw_buff_size, const device_addr_t& rx_args)
-{
- double fullness_factor = rx_args.cast<double>(
- "recv_buff_fullness", uhd::rfnoc::DEFAULT_FC_RX_SW_BUFF_FULL_FACTOR);
-
- if (fullness_factor < 0.01 || fullness_factor > 1) {
- throw uhd::value_error(
- "recv_buff_fullness must be in [0.01, 1] inclusive (1% to 100%)");
- }
-
- size_t window_in_bytes = (static_cast<size_t>(fullness_factor * sw_buff_size));
- if (rx_args.has_key("max_recv_window")) {
- window_in_bytes = std::min(
- window_in_bytes,
- pkt_size * rx_args.cast<size_t>("max_recv_window", 1)
- );
- }
- if (window_in_bytes < pkt_size) {
- throw uhd::value_error("recv_buff_size must be larger than the recv_frame_size.");
- }
- UHD_ASSERT_THROW(size_t(sw_buff_size * fullness_factor) >= window_in_bytes);
- return window_in_bytes;
-}
-
-
-/***********************************************************************
- * TX Async Message Functions
- **********************************************************************/
-#define DEVICE3_ASYNC_EVENT_CODE_FLOW_CTRL 0
-
-struct async_tx_info_t
-{
- size_t stream_channel;
- size_t device_channel;
- boost::shared_ptr<device3_impl::async_md_type> async_queue;
- boost::shared_ptr<device3_impl::async_md_type> old_async_queue;
-};
-
-/*! Handle incoming messages.
- * Send them to the async message queue for the user to poll.
- *
- * This is run inside a uhd::task as long as this streamer lives.
- */
-static void handle_tx_async_msgs(boost::shared_ptr<async_tx_info_t> async_info,
- zero_copy_if::sptr xport,
- uint32_t (*to_host)(uint32_t),
- void (*unpack)(const uint32_t* packet_buff, vrt::if_packet_info_t&),
- boost::function<double(void)> get_tick_rate)
-{
- managed_recv_buffer::sptr buff = xport->get_recv_buff();
- if (not buff) {
- return;
- }
-
- // extract packet info
- vrt::if_packet_info_t if_packet_info;
- if_packet_info.num_packet_words32 = buff->size() / sizeof(uint32_t);
- const uint32_t* packet_buff = buff->cast<const uint32_t*>();
-
- // unpacking can fail
- try {
- unpack(packet_buff, if_packet_info);
- } catch (const std::exception& ex) {
- UHD_LOGGER_ERROR("STREAMER")
- << "Error parsing async message packet: " << ex.what();
- return;
- }
-
- double tick_rate = get_tick_rate();
- if (tick_rate == rfnoc::tick_node_ctrl::RATE_UNDEFINED) {
- tick_rate = 1;
- }
-
- // fill in the async metadata
- async_metadata_t metadata;
- load_metadata_from_buff(to_host,
- metadata,
- if_packet_info,
- packet_buff,
- tick_rate,
- async_info->stream_channel);
-
- // Filter out any flow control messages and cache the rest
- if (metadata.event_code == DEVICE3_ASYNC_EVENT_CODE_FLOW_CTRL) {
- UHD_LOGGER_ERROR("TX ASYNC MSG")
- << "Unexpected flow control message found in async message handling"
- << std::endl;
- } else {
- async_info->async_queue->push_with_pop_on_full(metadata);
- metadata.channel = async_info->device_channel;
- async_info->old_async_queue->push_with_pop_on_full(metadata);
- standard_async_msg_prints(metadata);
- }
-}
-
-bool device3_impl::recv_async_msg(async_metadata_t& async_metadata, double timeout)
-{
- return _async_md->pop_with_timed_wait(async_metadata, timeout);
-}
-
-/***********************************************************************
- * Receive streamer
- **********************************************************************/
-void device3_impl::update_rx_streamers()
-{
- for (const std::string& block_id : _rx_streamers.keys()) {
- UHD_RX_STREAMER_LOG() << "updating RX streamer to " << block_id;
- boost::shared_ptr<device3_recv_packet_streamer> my_streamer =
- boost::dynamic_pointer_cast<device3_recv_packet_streamer>(
- _rx_streamers[block_id].lock());
- if (my_streamer) {
- double tick_rate = my_streamer->get_terminator()->get_tick_rate();
- if (tick_rate == rfnoc::tick_node_ctrl::RATE_UNDEFINED) {
- tick_rate = 1.0;
- }
- double samp_rate = my_streamer->get_terminator()->get_output_samp_rate();
- if (samp_rate == rfnoc::rate_node_ctrl::RATE_UNDEFINED) {
- samp_rate = 1.0;
- }
- double scaling = my_streamer->get_terminator()->get_output_scale_factor();
- if (scaling == rfnoc::scalar_node_ctrl::SCALE_UNDEFINED) {
- scaling = 1 / 32767.;
- }
- UHD_RX_STREAMER_LOG()
- << " New tick_rate == " << tick_rate
- << " New samp_rate == " << samp_rate << " New scaling == " << scaling;
-
- my_streamer->set_tick_rate(tick_rate);
- my_streamer->set_samp_rate(samp_rate);
- my_streamer->set_scale_factor(scaling);
- }
- }
-}
-
-rx_streamer::sptr device3_impl::get_rx_stream(const stream_args_t& args_)
-{
- boost::mutex::scoped_lock lock(_transport_setup_mutex);
- stream_args_t args = sanitize_stream_args(args_);
-
- // I. Generate the channel list
- std::vector<uhd::rfnoc::block_id_t> chan_list;
- std::vector<device_addr_t> chan_args;
- generate_channel_list(args, chan_list, chan_args);
- // Note: All 'args.args' are merged into chan_args now.
-
- // II. Iterate over all channels
- boost::shared_ptr<device3_recv_packet_streamer> my_streamer;
- // The terminator's lifetime is coupled to the streamer.
- // There is only one terminator. If the streamer has multiple channels,
- // it will be connected to each upstream block.
- rfnoc::rx_stream_terminator::sptr recv_terminator =
- rfnoc::rx_stream_terminator::make();
- for (size_t stream_i = 0; stream_i < chan_list.size(); stream_i++) {
- // First, configure blocks and create transport
-
- // Get block ID and mb index
- uhd::rfnoc::block_id_t block_id = chan_list[stream_i];
- UHD_RX_STREAMER_LOG() << "chan " << stream_i << " connecting to " << block_id;
- // Update args so args.args is always valid for this particular channel:
- args.args = chan_args[stream_i];
- size_t mb_index = block_id.get_device_no();
- size_t suggested_block_port =
- args.args.cast<size_t>("block_port", rfnoc::ANY_PORT);
-
- // Access to this channel's block control
- uhd::rfnoc::source_block_ctrl_base::sptr blk_ctrl =
- boost::dynamic_pointer_cast<uhd::rfnoc::source_block_ctrl_base>(
- get_block_ctrl(block_id));
-
- // Connect the terminator with this channel's block.
- size_t block_port = blk_ctrl->connect_downstream(
- recv_terminator, suggested_block_port, args.args);
- const size_t terminator_port = recv_terminator->connect_upstream(blk_ctrl);
- blk_ctrl->set_downstream_port(block_port, terminator_port);
- recv_terminator->set_upstream_port(terminator_port, block_port);
-
- // Check if the block connection is compatible (spp and item type)
- check_stream_sig_compatible(
- blk_ctrl->get_output_signature(block_port), args, "RX");
-
- // Setup the DSP transport hints
- device_addr_t rx_hints = get_rx_hints(mb_index);
-
- // Search the device and all nodes for lowest MTU
- size_t mtu = std::min(
- get_mtu(mb_index, uhd::direction_t::RX_DIRECTION),
- blk_ctrl->get_mtu(block_port));
- UHD_RX_STREAMER_LOG() << "Maximum MTU supported by "
- << blk_ctrl->unique_id()
- << ": " << blk_ctrl->get_mtu(block_port);
- std::vector<boost::shared_ptr<uhd::rfnoc::source_block_ctrl_base>>
- upstream_source_nodes =
- blk_ctrl->find_upstream_node<uhd::rfnoc::source_block_ctrl_base>();
- for (const boost::shared_ptr<uhd::rfnoc::source_block_ctrl_base>& node :
- upstream_source_nodes) {
- // Get MTU from Port 0 of the upstream nodes. This is okay for now as
- // currently we use port 0 of a block in case of channel 1.
- UHD_RX_STREAMER_LOG() << "Maximum MTU supported by " << node->unique_id()
- << ": " << node->get_mtu(0);
- mtu = std::min(mtu, node->get_mtu(0));
- }
- rx_hints["mtu"] = std::to_string(mtu);
-
- // Make sure user supplied recv_frame_size is less than the MTU
- if (rx_hints.cast<size_t>("recv_frame_size", mtu) > mtu) {
- UHD_LOGGER_WARNING("STREAMER")
- << "Requested recv_frame_size of "
- << rx_hints["recv_frame_size"]
- << " exceeds the maximum possible on this stream. Using "
- << mtu;
- rx_hints["recv_frame_size"] = std::to_string(mtu);
- }
-
- // allocate sid and create transport
- uhd::sid_t stream_address = blk_ctrl->get_address(block_port);
- UHD_RX_STREAMER_LOG() << "creating rx stream " << rx_hints.to_string();
- both_xports_t xport = make_transport(stream_address, RX_DATA, rx_hints);
- UHD_RX_STREAMER_LOG() << std::hex << "data_sid = " << xport.send_sid << std::dec
- << " actual recv_buff_size = " << xport.recv_buff_size;
-
- // Configure the block
- // Flow control setup
- const size_t pkt_size = xport.recv->get_recv_frame_size();
- // Leave one pkt_size space for overrun packets - TODO make this obsolete
- const size_t fc_window =
- get_rx_flow_control_window(pkt_size, xport.recv_buff_size, rx_hints)
- - pkt_size;
- const size_t fc_handle_window =
- std::max<size_t>(pkt_size, fc_window / stream_options.rx_fc_request_freq);
- UHD_RX_STREAMER_LOG() << "Flow Control Window = " << (fc_window)
- << ", Flow Control Handler Window = " << fc_handle_window;
- blk_ctrl->configure_flow_control_out(true,
- xport.lossless,
- fc_window,
- rx_hints.cast<size_t>("recv_pkt_limit",
- 0), // On rfnoc-devel, update e300_impl::get_rx_hints() to set this to 32
- block_port);
-
- // Add flow control transport
- boost::shared_ptr<rx_fc_cache_t> fc_cache(new rx_fc_cache_t());
- fc_cache->sid = xport.send_sid;
- fc_cache->xport = xport.send;
- fc_cache->interval = fc_handle_window;
- if (xport.endianness == ENDIANNESS_BIG) {
- fc_cache->to_host = uhd::ntohx<uint32_t>;
- fc_cache->from_host = uhd::htonx<uint32_t>;
- fc_cache->pack = vrt::chdr::if_hdr_pack_be;
- fc_cache->unpack = vrt::chdr::if_hdr_unpack_be;
- } else {
- fc_cache->to_host = uhd::wtohx<uint32_t>;
- fc_cache->from_host = uhd::htowx<uint32_t>;
- fc_cache->pack = vrt::chdr::if_hdr_pack_le;
- fc_cache->unpack = vrt::chdr::if_hdr_unpack_le;
- }
- xport.recv = zero_copy_flow_ctrl::make(
- xport.recv, 0, [fc_cache](managed_buffer::sptr buff) {
- return rx_flow_ctrl(fc_cache, buff);
- });
-
- // Configure the block
- // Note: We need to set_destination() after writing to SR_CLEAR_TX_FC.
- // See noc_shell.v, in the section called Stream Source for details.
- // Setting SR_CLEAR_TX_FC will actually also clear the destination and
- // other settings.
- blk_ctrl->sr_write(uhd::rfnoc::SR_CLEAR_TX_FC, 0x1, block_port);
- blk_ctrl->sr_write(uhd::rfnoc::SR_CLEAR_TX_FC, 0x0, block_port);
- // Configure routing for data
- blk_ctrl->set_destination(xport.send_sid.get_src(), block_port);
-
- // Configure routing for responses
- blk_ctrl->sr_write(
- uhd::rfnoc::SR_RESP_OUT_DST_SID, xport.send_sid.get_src(), block_port);
- UHD_RX_STREAMER_LOG() << "resp_out_dst_sid == " << xport.send_sid.get_src();
-
- // Find all upstream radio nodes and set their response in SID to the host
- std::vector<boost::shared_ptr<uhd::rfnoc::radio_ctrl>> upstream_radio_nodes =
- blk_ctrl->find_upstream_node<uhd::rfnoc::radio_ctrl>();
- UHD_RX_STREAMER_LOG() << "Number of upstream radio nodes: "
- << upstream_radio_nodes.size();
- for (const boost::shared_ptr<uhd::rfnoc::radio_ctrl>& node :
- upstream_radio_nodes) {
- node->sr_write(
- uhd::rfnoc::SR_RESP_OUT_DST_SID, xport.send_sid.get_src(), block_port);
- }
-
- // Second, configure the streamer
-
- // make the new streamer given the samples per packet
- if (not my_streamer) {
- // To calculate the max number of samples per packet, we assume the maximum
- // header length to avoid fragmentation should the entire header be used.
- const size_t bpp =
- pkt_size - stream_options.rx_max_len_hdr; // bytes per packet
- const size_t bpi =
- convert::get_bytes_per_item(args.otw_format); // bytes per item
- const size_t spp = std::min(args.args.cast<size_t>("spp", bpp / bpi),
- bpp / bpi); // samples per packet
- UHD_RX_STREAMER_LOG() << "bpp == " << bpp << ", bpi == " << bpi << ", spp == " << spp;
-
- my_streamer = boost::make_shared<device3_recv_packet_streamer>(
- spp, recv_terminator, xport);
- my_streamer->resize(chan_list.size());
- }
-
- // init some streamer stuff
- std::string conv_endianness;
- if (xport.endianness == ENDIANNESS_BIG) {
- my_streamer->set_vrt_unpacker(&vrt::chdr::if_hdr_unpack_be);
- conv_endianness = "be";
- } else {
- my_streamer->set_vrt_unpacker(&vrt::chdr::if_hdr_unpack_le);
- conv_endianness = "le";
- }
-
- // set the converter
- uhd::convert::id_type id;
- id.input_format = args.otw_format + "_item32_" + conv_endianness;
- id.num_inputs = 1;
- id.output_format = args.cpu_format;
- id.num_outputs = 1;
- my_streamer->set_converter(id);
-
- // Give the streamer a functor to handle flow control ACK messages
- my_streamer->set_xport_handle_flowctrl_ack(
- stream_i, [fc_cache](const uint32_t* payload) {
- handle_rx_flowctrl_ack(fc_cache, payload);
- });
-
- // Give the streamer a functor to get the recv_buffer
- my_streamer->set_xport_chan_get_buff(stream_i,
- [xport](double timeout) { return xport.recv->get_recv_buff(timeout); },
- true /*flush*/
- );
-
- // Give the streamer a functor to handle overruns
- // bind requires a weak_ptr to break the a streamer->streamer circular dependency
- // Using "this" is OK because we know that this device3_impl will outlive the
- // streamer
- boost::weak_ptr<uhd::rx_streamer> weak_ptr(my_streamer);
- my_streamer->set_overflow_handler(
- stream_i, [recv_terminator, weak_ptr, stream_i]() {
- recv_terminator->handle_overrun(weak_ptr, stream_i);
- });
-
- // Give the streamer a functor issue stream cmd
- my_streamer->set_issue_stream_cmd(
- stream_i, [blk_ctrl, block_port](const stream_cmd_t& stream_cmd) {
- blk_ctrl->issue_stream_cmd(stream_cmd, block_port);
- });
- }
-
- // Notify all blocks in this chain that they are connected to an active streamer
- recv_terminator->set_rx_streamer(true, 0);
-
- // Store a weak pointer to prevent a streamer->device3_impl->streamer circular
- // dependency. Note that we store the streamer only once, and use its terminator's ID
- // to do so.
- _rx_streamers[recv_terminator->unique_id()] =
- boost::weak_ptr<uhd::rx_streamer>(my_streamer);
-
- // Sets tick rate, samp rate and scaling on this streamer.
- // A registered terminator is required to do this.
- update_rx_streamers();
-
- post_streamer_hooks(RX_DIRECTION);
- return my_streamer;
-}
-
-/***********************************************************************
- * Transmit streamer
- **********************************************************************/
-void device3_impl::update_tx_streamers()
-{
- for (const std::string& block_id : _tx_streamers.keys()) {
- UHD_TX_STREAMER_LOG() << "updating TX streamer: " << block_id;
- boost::shared_ptr<device3_send_packet_streamer> my_streamer =
- boost::dynamic_pointer_cast<device3_send_packet_streamer>(
- _tx_streamers[block_id].lock());
- if (my_streamer) {
- double tick_rate = my_streamer->get_terminator()->get_tick_rate();
- if (tick_rate == rfnoc::tick_node_ctrl::RATE_UNDEFINED) {
- tick_rate = 1.0;
- }
- double samp_rate = my_streamer->get_terminator()->get_input_samp_rate();
- if (samp_rate == rfnoc::rate_node_ctrl::RATE_UNDEFINED) {
- samp_rate = 1.0;
- }
- double scaling = my_streamer->get_terminator()->get_input_scale_factor();
- if (scaling == rfnoc::scalar_node_ctrl::SCALE_UNDEFINED) {
- scaling = 32767.;
- }
- UHD_TX_STREAMER_LOG()
- << "New tick_rate == " << tick_rate << " New samp_rate == " << samp_rate
- << " New scaling == " << scaling;
- my_streamer->set_tick_rate(tick_rate);
- my_streamer->set_samp_rate(samp_rate);
- my_streamer->set_scale_factor(scaling);
- }
- }
-}
-
-tx_streamer::sptr device3_impl::get_tx_stream(const uhd::stream_args_t& args_)
-{
- boost::mutex::scoped_lock lock(_transport_setup_mutex);
- stream_args_t args = sanitize_stream_args(args_);
-
- // I. Generate the channel list
- std::vector<uhd::rfnoc::block_id_t> chan_list;
- std::vector<device_addr_t> chan_args;
- generate_channel_list(args, chan_list, chan_args);
- // Note: All 'args.args' are merged into chan_args now.
-
- // shared async queue for all channels in streamer
- boost::shared_ptr<async_md_type> async_md(new async_md_type(1000 /*messages deep*/));
-
- // II. Iterate over all channels
- boost::shared_ptr<device3_send_packet_streamer> my_streamer;
- // The terminator's lifetime is coupled to the streamer.
- // There is only one terminator. If the streamer has multiple channels,
- // it will be connected to each downstream block.
- rfnoc::tx_stream_terminator::sptr send_terminator =
- rfnoc::tx_stream_terminator::make();
- for (size_t stream_i = 0; stream_i < chan_list.size(); stream_i++) {
- // First, configure the downstream blocks and create the transports
-
- // Get block ID and mb index
- uhd::rfnoc::block_id_t block_id = chan_list[stream_i];
- // Update args so args.args is always valid for this particular channel:
- args.args = chan_args[stream_i];
- size_t mb_index = block_id.get_device_no();
- size_t suggested_block_port =
- args.args.cast<size_t>("block_port", rfnoc::ANY_PORT);
-
- // Access to this channel's block control
- uhd::rfnoc::sink_block_ctrl_base::sptr blk_ctrl =
- boost::dynamic_pointer_cast<uhd::rfnoc::sink_block_ctrl_base>(
- get_block_ctrl(block_id));
-
- // Connect the terminator with this channel's block.
- // This will throw if the connection is not possible.
- size_t block_port =
- blk_ctrl->connect_upstream(send_terminator, suggested_block_port, args.args);
- const size_t terminator_port = send_terminator->connect_downstream(blk_ctrl);
- blk_ctrl->set_upstream_port(block_port, terminator_port);
- send_terminator->set_downstream_port(terminator_port, block_port);
-
- // Check if the block connection is compatible (spp and item type)
- check_stream_sig_compatible(
- blk_ctrl->get_input_signature(block_port), args, "TX");
-
- // Setup the dsp transport hints
- device_addr_t tx_hints = get_tx_hints(mb_index);
-
- // Search the device and all nodes for lowest MTU
- size_t mtu = std::min(
- get_mtu(mb_index, uhd::direction_t::TX_DIRECTION),
- blk_ctrl->get_mtu(block_port));
- UHD_TX_STREAMER_LOG() << "Maximum MTU supported by "
- << blk_ctrl->unique_id() << ": "
- << blk_ctrl->get_mtu(block_port);
- std::vector<boost::shared_ptr<uhd::rfnoc::sink_block_ctrl_base>>
- downstream_sink_nodes =
- blk_ctrl->find_downstream_node<uhd::rfnoc::sink_block_ctrl_base>();
- for (const boost::shared_ptr<uhd::rfnoc::sink_block_ctrl_base>& node :
- downstream_sink_nodes) {
- // Get MTU from Port 0 of the downstream nodes. This is okay for now as
- // currently we use port 0 of a block in case of channel 1.
- UHD_TX_STREAMER_LOG() << "Maximum MTU supported by "
- << node->unique_id() << ": "
- << node->get_mtu(0);
- mtu = std::min(mtu, node->get_mtu(0));
- }
- tx_hints["mtu"] = std::to_string(mtu);
-
- // Make sure user supplied send_frame_size is less than the MTU
- if (tx_hints.cast<size_t>("send_frame_size", mtu) > mtu) {
- UHD_LOGGER_WARNING("STREAMER")
- << "Requested send_frame_size of "
- << tx_hints["send_frame_size"]
- << " exceeds the maximum possible on this stream. Using "
- << mtu;
- tx_hints["send_frame_size"] = std::to_string(mtu);
- }
-
- const size_t fifo_size = blk_ctrl->get_fifo_size(block_port);
- // Allocate sid and create transport
- uhd::sid_t stream_address = blk_ctrl->get_address(block_port);
- UHD_TX_STREAMER_LOG() << "creating tx stream " << tx_hints.to_string();
- both_xports_t xport = make_transport(stream_address, TX_DATA, tx_hints);
- both_xports_t async_xport =
- make_transport(stream_address, ASYNC_MSG, device_addr_t(""));
- UHD_TX_STREAMER_LOG() << std::hex << "data_sid = " << xport.send_sid << std::dec;
-
- // Configure flow control
- // This disables the FC module's output, do this before configuring flow control
- blk_ctrl->sr_write(uhd::rfnoc::SR_CLEAR_RX_FC, 0x1, block_port);
- blk_ctrl->sr_write(uhd::rfnoc::SR_CLEAR_RX_FC, 0x0, block_port);
- // Configure flow control on downstream block
- const size_t pkt_size = xport.send->get_send_frame_size();
- const size_t fc_window =
- std::min(tx_hints.cast<size_t>("send_buff_size", fifo_size), fifo_size);
- const size_t fc_handle_window =
- std::max<size_t>(pkt_size, fc_window / stream_options.tx_fc_response_freq);
- UHD_TX_STREAMER_LOG() << "Flow Control Window = " << fc_window
- << ", Flow Control Handler Window = " << fc_handle_window
- << ", FIFO size = " << fifo_size;
- blk_ctrl->configure_flow_control_in(fc_handle_window, /*bytes*/
- block_port);
- // Add flow control transport
- boost::shared_ptr<tx_fc_cache_t> fc_cache(new tx_fc_cache_t(fc_window));
- if (xport.endianness == ENDIANNESS_BIG) {
- fc_cache->to_host = uhd::ntohx<uint32_t>;
- fc_cache->from_host = uhd::htonx<uint32_t>;
- fc_cache->pack = vrt::chdr::if_hdr_pack_be;
- fc_cache->unpack = vrt::chdr::if_hdr_unpack_be;
- } else {
- fc_cache->to_host = uhd::wtohx<uint32_t>;
- fc_cache->from_host = uhd::htowx<uint32_t>;
- fc_cache->pack = vrt::chdr::if_hdr_pack_le;
- fc_cache->unpack = vrt::chdr::if_hdr_unpack_le;
- }
- xport.send = zero_copy_flow_ctrl::make(xport.send,
- [fc_cache, xport](managed_buffer::sptr buff) {
- return tx_flow_ctrl(fc_cache, xport.recv, buff);
- },
- 0);
-
- // Configure return path for async messages
- blk_ctrl->sr_write(
- uhd::rfnoc::SR_RESP_IN_DST_SID, async_xport.recv_sid.get_dst(), block_port);
- UHD_TX_STREAMER_LOG() << "resp_in_dst_sid == "
- << boost::format("0x%04X") % xport.recv_sid.get_dst();
-
- // FIXME: Once there is a better way to map the radio block and port
- // to the channel or another way to receive asynchronous messages that
- // is not in-band, this should be removed.
- if (args.args.has_key("radio_id") and args.args.has_key("radio_port")) {
- // Find downstream radio node and set the response SID to the host
- uhd::rfnoc::block_id_t radio_id(args.args["radio_id"]);
- size_t radio_port = args.args.cast<size_t>("radio_port", 0);
- std::vector<boost::shared_ptr<uhd::rfnoc::radio_ctrl>>
- downstream_radio_nodes =
- blk_ctrl->find_downstream_node<uhd::rfnoc::radio_ctrl>();
- UHD_TX_STREAMER_LOG()
- << "Number of downstream radio nodes: " << downstream_radio_nodes.size();
- for (const boost::shared_ptr<uhd::rfnoc::radio_ctrl>& node :
- downstream_radio_nodes) {
- if (node->get_block_id() == radio_id) {
- node->sr_write(uhd::rfnoc::SR_RESP_IN_DST_SID,
- async_xport.recv_sid.get_dst(),
- radio_port);
- }
- }
- } else {
- // FIXME: This block is preserved for legacy behavior where the
- // radio_id and radio_port are not provided. It fails if more
- // than one radio is visible downstream or the port on the radio
- // is not the same as the block_port. It should be removed as
- // soon as possible.
- // Find all downstream radio nodes and set their response SID to the host
- std::vector<boost::shared_ptr<uhd::rfnoc::radio_ctrl>>
- downstream_radio_nodes =
- blk_ctrl->find_downstream_node<uhd::rfnoc::radio_ctrl>();
- UHD_TX_STREAMER_LOG()
- << "Number of downstream radio nodes: " << downstream_radio_nodes.size();
- for (const boost::shared_ptr<uhd::rfnoc::radio_ctrl>& node :
- downstream_radio_nodes) {
- node->sr_write(uhd::rfnoc::SR_RESP_IN_DST_SID,
- async_xport.recv_sid.get_dst(),
- block_port);
- }
- }
-
- // Second, configure the streamer now that the blocks and transports are
- // configured
-
- // make the new streamer given the samples per packet
- if (not my_streamer) {
- // To calculate the max number of samples per packet, we assume the maximum
- // header length to avoid fragmentation should the entire header be used.
- const size_t bpp =
- tx_hints.cast<size_t>("bpp", pkt_size) -
- stream_options.tx_max_len_hdr;
- const size_t bpi =
- convert::get_bytes_per_item(args.otw_format); // bytes per item
- const size_t spp = std::min(args.args.cast<size_t>("spp", bpp / bpi),
- bpp / bpi); // samples per packet
- UHD_TX_STREAMER_LOG()
- << "bpp == " << bpp
- << ", bpi == " << bpi
- << ", spp == " << spp;
-
- my_streamer = boost::make_shared<device3_send_packet_streamer>(
- spp, send_terminator, xport, async_xport);
- my_streamer->resize(chan_list.size());
- }
-
- // init some streamer stuff
- std::string conv_endianness;
- if (xport.endianness == ENDIANNESS_BIG) {
- my_streamer->set_vrt_packer(&vrt::chdr::if_hdr_pack_be);
- conv_endianness = "be";
- } else {
- my_streamer->set_vrt_packer(&vrt::chdr::if_hdr_pack_le);
- conv_endianness = "le";
- }
-
- // set the converter
- uhd::convert::id_type id;
- id.input_format = args.cpu_format;
- id.num_inputs = 1;
- id.output_format = args.otw_format + "_item32_" + conv_endianness;
- id.num_outputs = 1;
- my_streamer->set_converter(id);
-
- boost::shared_ptr<async_tx_info_t> async_tx_info(new async_tx_info_t());
- async_tx_info->stream_channel = args.channels[stream_i];
- async_tx_info->device_channel = mb_index;
- async_tx_info->async_queue = async_md;
- async_tx_info->old_async_queue = _async_md;
-
- task::sptr async_task =
- task::make([async_tx_info, async_xport, xport, send_terminator]() {
- handle_tx_async_msgs(async_tx_info,
- async_xport.recv,
- xport.endianness == ENDIANNESS_BIG ? uhd::ntohx<uint32_t>
- : uhd::wtohx<uint32_t>,
- xport.endianness == ENDIANNESS_BIG ? vrt::chdr::if_hdr_unpack_be
- : vrt::chdr::if_hdr_unpack_le,
- [send_terminator]() { return send_terminator->get_tick_rate(); });
- });
- my_streamer->add_async_msg_task(async_task);
-
- // Give the streamer a functor to get the send buffer
- my_streamer->set_xport_chan_get_buff(stream_i,
- [xport](const double timeout) { return xport.send->get_send_buff(timeout); });
- // Give the streamer a functor handled received async messages
- my_streamer->set_async_receiver(
- [async_md](uhd::async_metadata_t& md, const double timeout) {
- return async_md->pop_with_timed_wait(md, timeout);
- });
- my_streamer->set_xport_chan_sid(stream_i, true, xport.send_sid);
- // CHDR does not support trailers
- my_streamer->set_enable_trailer(false);
-
- // Avoid sending FC ACKs if the transport is lossless or the user
- // has explictly requested not to send them
- if (not(xport.lossless or tx_hints.has_key("send_no_fc_acks"))) {
- my_streamer->set_xport_chan_post_send_cb(stream_i, [fc_cache, xport]() {
- tx_flow_ctrl_ack(fc_cache, xport.send, xport.send_sid);
- });
- }
- }
-
- // Notify all blocks in this chain that they are connected to an active streamer
- send_terminator->set_tx_streamer(true, 0);
-
- // Store a weak pointer to prevent a streamer->device3_impl->streamer circular
- // dependency. Note that we store the streamer only once, and use its terminator's ID
- // to do so.
- _tx_streamers[send_terminator->unique_id()] =
- boost::weak_ptr<uhd::tx_streamer>(my_streamer);
-
- // Sets tick rate, samp rate and scaling on this streamer
- // A registered terminator is required to do this.
- update_tx_streamers();
-
- post_streamer_hooks(TX_DIRECTION);
- return my_streamer;
-}
diff --git a/host/lib/usrp/mpmd/mpmd_impl.cpp b/host/lib/usrp/mpmd/mpmd_impl.cpp
index 30a3c5804..69f990807 100644
--- a/host/lib/usrp/mpmd/mpmd_impl.cpp
+++ b/host/lib/usrp/mpmd/mpmd_impl.cpp
@@ -7,15 +7,9 @@
#include "mpmd_impl.hpp"
#include <uhd/exception.hpp>
#include <uhd/types/component_file.hpp>
-#include <uhd/types/eeprom.hpp>
-#include <uhd/types/sensors.hpp>
-#include <uhd/usrp/mboard_eeprom.hpp>
#include <uhd/utils/static.hpp>
#include <uhd/utils/tasks.hpp>
-#include <uhdlib/rfnoc/radio_ctrl_impl.hpp>
-#include <uhdlib/rfnoc/rpc_block_ctrl.hpp>
#include <boost/algorithm/string.hpp>
-#include <boost/asio.hpp>
#include <boost/make_shared.hpp>
#include <boost/thread.hpp>
#include <chrono>
diff --git a/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.cpp b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.cpp
index baf0dde3e..2a3a48b62 100644
--- a/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.cpp
+++ b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.cpp
@@ -192,77 +192,79 @@ mpmd_link_if_ctrl_dpdk_udp::mpmd_link_if_ctrl_dpdk_udp(
}
}
-uhd::both_xports_t
-mpmd_link_if_ctrl_dpdk_udp::make_transport(
- mpmd_link_if_mgr::xport_info_t &xport_info,
- const usrp::device3_impl::xport_type_t xport_type,
- const uhd::device_addr_t& xport_args
-) {
+// uhd::both_xports_t
+// mpmd_link_if_ctrl_dpdk_udp::make_transport(
+// mpmd_link_if_mgr::xport_info_t &xport_info,
+// const uhd::transport::link_type_t xport_type,
+// const uhd::device_addr_t& xport_args
+//) {
- // Constrain by this transport's MTU and the MTU in the xport_args
- const size_t send_mtu = std::min(get_mtu(uhd::TX_DIRECTION),
- xport_args.cast<size_t>("mtu", get_mtu(uhd::TX_DIRECTION)));
- const size_t recv_mtu = std::min(get_mtu(uhd::RX_DIRECTION),
- xport_args.cast<size_t>("mtu", get_mtu(uhd::RX_DIRECTION)));
+//// Constrain by this transport's MTU and the MTU in the xport_args
+// const size_t send_mtu = std::min(get_mtu(uhd::TX_DIRECTION),
+// xport_args.cast<size_t>("mtu", get_mtu(uhd::TX_DIRECTION)));
+// const size_t recv_mtu = std::min(get_mtu(uhd::RX_DIRECTION),
+// xport_args.cast<size_t>("mtu", get_mtu(uhd::RX_DIRECTION)));
- // Create actual UHD-DPDK UDP transport
- transport::zero_copy_xport_params default_buff_args;
- default_buff_args.num_recv_frames = MPMD_ETH_NUM_CTRL_FRAMES;
- default_buff_args.num_send_frames = MPMD_ETH_NUM_CTRL_FRAMES;
- default_buff_args.recv_frame_size = MPMD_10GE_MSG_FRAME_DEFAULT_SIZE;
- default_buff_args.send_frame_size = MPMD_10GE_MSG_FRAME_DEFAULT_SIZE;
+//// Create actual UHD-DPDK UDP transport
+// transport::zero_copy_xport_params default_buff_args;
+// default_buff_args.num_recv_frames = MPMD_ETH_NUM_CTRL_FRAMES;
+// default_buff_args.num_send_frames = MPMD_ETH_NUM_CTRL_FRAMES;
+// default_buff_args.recv_frame_size = MPMD_10GE_MSG_FRAME_DEFAULT_SIZE;
+// default_buff_args.send_frame_size = MPMD_10GE_MSG_FRAME_DEFAULT_SIZE;
- if (xport_type == usrp::device3_impl::RX_DATA) {
- default_buff_args.num_recv_frames =
- xport_args.cast<size_t>("num_recv_frames", MPMD_ETH_NUM_RECV_FRAMES);
- default_buff_args.recv_frame_size = std::min(
- xport_args.cast<size_t>("recv_frame_size",
- MPMD_10GE_DATA_FRAME_DEFAULT_SIZE),
- recv_mtu);
- } else if (xport_type == usrp::device3_impl::TX_DATA) {
- default_buff_args.num_send_frames =
- xport_args.cast<size_t>("num_send_frames", MPMD_ETH_NUM_SEND_FRAMES);
- default_buff_args.send_frame_size = std::min(
- xport_args.cast<size_t>("send_frame_size",
- MPMD_10GE_DATA_FRAME_DEFAULT_SIZE),
- send_mtu);
- }
+// if (xport_type == uhd::transport::link_type_t::RX_DATA) {
+// default_buff_args.num_recv_frames =
+// xport_args.cast<size_t>("num_recv_frames", MPMD_ETH_NUM_RECV_FRAMES);
+// default_buff_args.recv_frame_size = std::min(
+// xport_args.cast<size_t>("recv_frame_size",
+// MPMD_10GE_DATA_FRAME_DEFAULT_SIZE),
+// recv_mtu);
+//} else if (xport_type == uhd::transport::link_type_t::TX_DATA) {
+// default_buff_args.num_send_frames =
+// xport_args.cast<size_t>("num_send_frames", MPMD_ETH_NUM_SEND_FRAMES);
+// default_buff_args.send_frame_size = std::min(
+// xport_args.cast<size_t>("send_frame_size",
+// MPMD_10GE_DATA_FRAME_DEFAULT_SIZE),
+// send_mtu);
+//}
- UHD_LOG_TRACE("BUFF", "num_recv_frames=" << default_buff_args.num_recv_frames
- << ", num_send_frames=" << default_buff_args.num_send_frames
- << ", recv_frame_size=" << default_buff_args.recv_frame_size
- << ", send_frame_size=" << default_buff_args.send_frame_size);
+// UHD_LOG_TRACE("BUFF", "num_recv_frames=" << default_buff_args.num_recv_frames
+//<< ", num_send_frames=" << default_buff_args.num_send_frames
+//<< ", recv_frame_size=" << default_buff_args.recv_frame_size
+//<< ", send_frame_size=" << default_buff_args.send_frame_size);
- int dpdk_port_id = _ctx.get_route(xport_info["ipv4"]);
- if (dpdk_port_id < 0) {
- throw uhd::runtime_error("Could not find a DPDK port with route to " +
- xport_info["ipv4"]);
- }
- auto recv = transport::dpdk_zero_copy::make(
- _ctx,
- (const unsigned int) dpdk_port_id,
- xport_info["ipv4"],
- xport_info["port"],
- "0",
- default_buff_args,
- uhd::device_addr_t()
- );
- const uint16_t port = recv->get_local_port();
- const std::string src_ip_addr = recv->get_local_addr();
- xport_info["src_port"] = std::to_string(port);
- xport_info["src_ipv4"] = src_ip_addr;
+// int dpdk_port_id = _ctx.get_route(xport_info["ipv4"]);
+// if (dpdk_port_id < 0) {
+// throw uhd::runtime_error("Could not find a DPDK port with route to " +
+// xport_info["ipv4"]);
+//}
+// auto recv = transport::dpdk_zero_copy::make(
+//_ctx,
+//(const unsigned int) dpdk_port_id,
+// xport_info["ipv4"],
+// xport_info["port"],
+//"0",
+// default_buff_args,
+// uhd::device_addr_t()
+//);
+// const uint16_t port = recv->get_local_port();
+// const std::string src_ip_addr = recv->get_local_addr();
+// xport_info["src_port"] = std::to_string(port);
+// xport_info["src_ipv4"] = src_ip_addr;
- // Create both_xports_t object and finish:
- both_xports_t xports;
- xports.endianness = uhd::ENDIANNESS_BIG;
- xports.send_sid = sid_t(xport_info["send_sid"]);
- xports.recv_sid = xports.send_sid.reversed();
- xports.recv_buff_size = (default_buff_args.recv_frame_size-MPMD_UDP_RESERVED_FRAME_SIZE)*default_buff_args.num_recv_frames;
- xports.send_buff_size = (default_buff_args.send_frame_size-MPMD_UDP_RESERVED_FRAME_SIZE)*default_buff_args.num_send_frames;
- xports.recv = recv; // Note: This is a type cast!
- xports.send = recv; // This too
- return xports;
-}
+//// Create both_xports_t object and finish:
+// both_xports_t xports;
+// xports.endianness = uhd::ENDIANNESS_BIG;
+// xports.send_sid = sid_t(xport_info["send_sid"]);
+// xports.recv_sid = xports.send_sid.reversed();
+// xports.recv_buff_size =
+// (default_buff_args.recv_frame_size-MPMD_UDP_RESERVED_FRAME_SIZE)*default_buff_args.num_recv_frames;
+// xports.send_buff_size =
+// (default_buff_args.send_frame_size-MPMD_UDP_RESERVED_FRAME_SIZE)*default_buff_args.num_send_frames;
+// xports.recv = recv; // Note: This is a type cast!
+// xports.send = recv; // This too
+// return xports;
+//}
bool mpmd_link_if_ctrl_dpdk_udp::is_valid(
const mpmd_link_if_mgr::xport_info_t& xport_info
diff --git a/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.hpp b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.hpp
index 4423b4340..8f4f1c7d1 100644
--- a/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.hpp
+++ b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.hpp
@@ -10,7 +10,6 @@
#include "mpmd_link_if_ctrl_base.hpp"
#include <uhd/types/device_addr.hpp>
#include <uhdlib/transport/dpdk_zero_copy.hpp>
-#include "../device3/device3_impl.hpp"
namespace uhd { namespace mpmd { namespace xport {
@@ -25,12 +24,6 @@ public:
const uhd::device_addr_t& mb_args
);
- both_xports_t make_transport(
- mpmd_link_if_mgr::xport_info_t& xport_info,
- const usrp::device3_impl::xport_type_t xport_type,
- const uhd::device_addr_t& xport_args
- );
-
bool is_valid(
const mpmd_link_if_mgr::xport_info_t& xport_info
) const;
diff --git a/host/lib/usrp/mpmd/mpmd_link_if_mgr.hpp b/host/lib/usrp/mpmd/mpmd_link_if_mgr.hpp
index 4b0ba4212..a1d11bad7 100644
--- a/host/lib/usrp/mpmd/mpmd_link_if_mgr.hpp
+++ b/host/lib/usrp/mpmd/mpmd_link_if_mgr.hpp
@@ -130,10 +130,10 @@ public:
* The latter needs to get sent back to MPM to complete the
* transport handshake.
*/
- //virtual both_xports_t make_transport(const xport_info_list_t& xport_info_list,
- //const usrp::device3_impl::xport_type_t xport_type,
- //const uhd::device_addr_t& xport_args,
- //xport_info_t& xport_info_out) = 0;
+ // virtual both_xports_t make_transport(const xport_info_list_t& xport_info_list,
+ // const uhd::transport::link_type_t::xport_type_t xport_type,
+ // const uhd::device_addr_t& xport_args,
+ // xport_info_t& xport_info_out) = 0;
/*! Return the path MTU for whatever this manager lets us do
*/
diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp
index 227ba4212..6f8b794ce 100644
--- a/host/lib/usrp/multi_usrp.cpp
+++ b/host/lib/usrp/multi_usrp.cpp
@@ -20,7 +20,6 @@
#include <uhd/convert.hpp>
#include <uhd/utils/soft_register.hpp>
#include <uhdlib/usrp/gpio_defs.hpp>
-#include <uhdlib/rfnoc/legacy_compat.hpp>
#include <uhdlib/rfnoc/rfnoc_device.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/format.hpp>
@@ -397,8 +396,7 @@ static double derive_freq_from_xx_subdev_and_dsp(
**********************************************************************/
class multi_usrp_impl : public multi_usrp{
public:
- multi_usrp_impl(device::sptr dev, const device_addr_t& addr)
- : _dev(dev)
+ multi_usrp_impl(device::sptr dev) : _dev(dev)
{
_tree = _dev->get_tree();
}
@@ -2259,7 +2257,6 @@ public:
private:
device::sptr _dev;
property_tree::sptr _tree;
- uhd::rfnoc::legacy_compat::sptr _legacy_compat;
struct mboard_chan_pair{
size_t mboard, chan;
@@ -2517,5 +2514,5 @@ multi_usrp::sptr multi_usrp::make(const device_addr_t& dev_addr)
if (rfnoc_dev) {
return rfnoc::detail::make_rfnoc_device(rfnoc_dev, dev_addr);
}
- return boost::make_shared<multi_usrp_impl>(dev, dev_addr);
+ return boost::make_shared<multi_usrp_impl>(dev);
}
diff --git a/host/lib/usrp/x300/x300_eth_mgr.cpp b/host/lib/usrp/x300/x300_eth_mgr.cpp
index b1d9f40ee..8ff63b050 100644
--- a/host/lib/usrp/x300/x300_eth_mgr.cpp
+++ b/host/lib/usrp/x300/x300_eth_mgr.cpp
@@ -239,46 +239,46 @@ both_links_t eth_manager::get_links(link_type_t link_type,
//#ifdef HAVE_DPDK
// auto& dpdk_ctx = uhd::transport::uhd_dpdk_ctx::get();
- // default_buff_args.num_recv_frames = ETH_MSG_NUM_FRAMES;
- // default_buff_args.num_send_frames = ETH_MSG_NUM_FRAMES;
- // if (link_type == link_type_t::CTRL) {
- //// Increasing number of recv frames here because ctrl_iface uses it
- //// to determine how many control packets can be in flight before it
- //// must wait for an ACK
- // default_buff_args.num_recv_frames =
- // uhd::rfnoc::CMD_FIFO_SIZE / uhd::rfnoc::MAX_CMD_PKT_SIZE;
- //} else if (xport_type == uhd::usrp::device3_impl::TX_DATA) {
- // size_t default_frame_size = conn.link_rate == MAX_RATE_1GIGE
- //? GE_DATA_FRAME_SEND_SIZE
- //: XGE_DATA_FRAME_SEND_SIZE;
- // default_buff_args.send_frame_size = args.cast<size_t>(
- //"send_frame_size", std::min(default_frame_size, send_mtu));
- // default_buff_args.num_send_frames =
- // args.cast<size_t>("num_send_frames", default_buff_args.num_send_frames);
- // default_buff_args.send_buff_size = args.cast<size_t>("send_buff_size", 0);
- //} else if (xport_type == uhd::usrp::device3_impl::RX_DATA) {
- // size_t default_frame_size = conn.link_rate == MAX_RATE_1GIGE
- //? GE_DATA_FRAME_RECV_SIZE
- //: XGE_DATA_FRAME_RECV_SIZE;
- // default_buff_args.recv_frame_size = args.cast<size_t>(
- //"recv_frame_size", std::min(default_frame_size, recv_mtu));
- // default_buff_args.num_recv_frames =
- // args.cast<size_t>("num_recv_frames", default_buff_args.num_recv_frames);
- // default_buff_args.recv_buff_size = args.cast<size_t>("recv_buff_size", 0);
- //}
-
- // int dpdk_port_id = dpdk_ctx.get_route(conn.addr);
- // if (dpdk_port_id < 0) {
- // throw uhd::runtime_error(
- //"Could not find a DPDK port with route to " + conn.addr);
- //}
- // auto recv = transport::dpdk_zero_copy::make(dpdk_ctx,
- //(const unsigned int)dpdk_port_id,
- // conn.addr,
- // BOOST_STRINGIZE(X300_VITA_UDP_PORT),
- //"0",
- // default_buff_args,
- // uhd::device_addr_t());
+// default_buff_args.num_recv_frames = ETH_MSG_NUM_FRAMES;
+// default_buff_args.num_send_frames = ETH_MSG_NUM_FRAMES;
+// if (link_type == link_type_t::CTRL) {
+//// Increasing number of recv frames here because ctrl_iface uses it
+//// to determine how many control packets can be in flight before it
+//// must wait for an ACK
+// default_buff_args.num_recv_frames =
+// uhd::rfnoc::CMD_FIFO_SIZE / uhd::rfnoc::MAX_CMD_PKT_SIZE;
+//} else if (xport_type == uhd::transport::link_type_t::TX_DATA) {
+// size_t default_frame_size = conn.link_rate == MAX_RATE_1GIGE
+//? GE_DATA_FRAME_SEND_SIZE
+//: XGE_DATA_FRAME_SEND_SIZE;
+// default_buff_args.send_frame_size = args.cast<size_t>(
+//"send_frame_size", std::min(default_frame_size, send_mtu));
+// default_buff_args.num_send_frames =
+// args.cast<size_t>("num_send_frames", default_buff_args.num_send_frames);
+// default_buff_args.send_buff_size = args.cast<size_t>("send_buff_size", 0);
+//} else if (xport_type == uhd::transport::link_type_t::RX_DATA) {
+// size_t default_frame_size = conn.link_rate == MAX_RATE_1GIGE
+//? GE_DATA_FRAME_RECV_SIZE
+//: XGE_DATA_FRAME_RECV_SIZE;
+// default_buff_args.recv_frame_size = args.cast<size_t>(
+//"recv_frame_size", std::min(default_frame_size, recv_mtu));
+// default_buff_args.num_recv_frames =
+// args.cast<size_t>("num_recv_frames", default_buff_args.num_recv_frames);
+// default_buff_args.recv_buff_size = args.cast<size_t>("recv_buff_size", 0);
+//}
+
+// int dpdk_port_id = dpdk_ctx.get_route(conn.addr);
+// if (dpdk_port_id < 0) {
+// throw uhd::runtime_error(
+//"Could not find a DPDK port with route to " + conn.addr);
+//}
+// auto recv = transport::dpdk_zero_copy::make(dpdk_ctx,
+//(const unsigned int)dpdk_port_id,
+// conn.addr,
+// BOOST_STRINGIZE(X300_VITA_UDP_PORT),
+//"0",
+// default_buff_args,
+// uhd::device_addr_t());
//#else
UHD_LOG_WARNING("X300", "Cannot create DPDK transport, falling back to UDP");
diff --git a/host/lib/usrp/x300/x300_pcie_mgr.cpp b/host/lib/usrp/x300/x300_pcie_mgr.cpp
index 220a96530..6560f2770 100644
--- a/host/lib/usrp/x300/x300_pcie_mgr.cpp
+++ b/host/lib/usrp/x300/x300_pcie_mgr.cpp
@@ -275,13 +275,13 @@ uint32_t pcie_manager::allocate_pcie_dma_chan(
const rfnoc::sep_id_t& /*remote_epid*/, const link_type_t /*link_type*/)
{
throw uhd::not_implemented_error("allocate_pcie_dma_chan()");
- //constexpr uint32_t CTRL_CHANNEL = 0;
- //constexpr uint32_t ASYNC_MSG_CHANNEL = 1;
- //constexpr uint32_t FIRST_DATA_CHANNEL = 2;
- //if (link_type == uhd::usrp::device3_impl::CTRL) {
- //return CTRL_CHANNEL;
- //} else if (link_type == uhd::usrp::device3_impl::ASYNC_MSG) {
- //return ASYNC_MSG_CHANNEL;
+ // constexpr uint32_t CTRL_CHANNEL = 0;
+ // constexpr uint32_t ASYNC_MSG_CHANNEL = 1;
+ // constexpr uint32_t FIRST_DATA_CHANNEL = 2;
+ // if (link_type == uhd::transport::link_type_t::CTRL) {
+ // return CTRL_CHANNEL;
+ //} else if (link_type == uhd::transport::link_type_t::ASYNC_MSG) {
+ // return ASYNC_MSG_CHANNEL;
//} else {
//// sid_t has no comparison defined, so we need to convert it uint32_t
//uint32_t raw_sid = tx_sid.get();
@@ -330,50 +330,50 @@ both_links_t pcie_manager::get_links(link_type_t /*link_type*/,
+ std::to_string(local_device_id)
+ ", no such device associated with this motherboard!");
}
- //zero_copy_xport_params default_buff_args;
- //xports.endianness = ENDIANNESS_LITTLE;
- //xports.lossless = true;
- //const uint32_t dma_channel_num = allocate_pcie_dma_chan(xports.send_sid, xport_type);
- //if (xport_type == uhd::usrp::device3_impl::CTRL) {
- //// Transport for control stream
- //if (not _ctrl_dma_xport) {
- //// One underlying DMA channel will handle
- //// all control traffic
- //_ctrl_dma_xport =
- //make_muxed_pcie_msg_xport(dma_channel_num, PCIE_MAX_MUXED_CTRL_XPORTS);
- //}
- //// Create a virtual control transport
- //xports.recv = _ctrl_dma_xport->make_stream(xports.recv_sid.get_dst());
- //} else if (xport_type == uhd::usrp::device3_impl::ASYNC_MSG) {
- //// Transport for async message stream
- //if (not _async_msg_dma_xport) {
- //// One underlying DMA channel will handle
- //// all async message traffic
- //_async_msg_dma_xport =
- //make_muxed_pcie_msg_xport(dma_channel_num, PCIE_MAX_MUXED_ASYNC_XPORTS);
- //}
- //// Create a virtual async message transport
- //xports.recv = _async_msg_dma_xport->make_stream(xports.recv_sid.get_dst());
- //} else if (xport_type == uhd::usrp::device3_impl::TX_DATA) {
- //default_buff_args.send_frame_size = args.cast<size_t>(
- //"send_frame_size", std::min(send_mtu, PCIE_TX_DATA_FRAME_SIZE));
- //default_buff_args.num_send_frames =
- //args.cast<size_t>("num_send_frames", PCIE_TX_DATA_NUM_FRAMES);
- //default_buff_args.send_buff_size = args.cast<size_t>("send_buff_size", 0);
- //default_buff_args.recv_frame_size = PCIE_MSG_FRAME_SIZE;
- //default_buff_args.num_recv_frames = PCIE_MSG_NUM_FRAMES;
- //xports.recv = nirio_zero_copy::make(
- //_rio_fpga_interface, dma_channel_num, default_buff_args);
- //} else if (xport_type == uhd::usrp::device3_impl::RX_DATA) {
- //default_buff_args.send_frame_size = PCIE_MSG_FRAME_SIZE;
- //default_buff_args.num_send_frames = PCIE_MSG_NUM_FRAMES;
- //default_buff_args.recv_frame_size = args.cast<size_t>(
- //"recv_frame_size", std::min(recv_mtu, PCIE_RX_DATA_FRAME_SIZE));
- //default_buff_args.num_recv_frames =
- //args.cast<size_t>("num_recv_frames", PCIE_RX_DATA_NUM_FRAMES);
- //default_buff_args.recv_buff_size = args.cast<size_t>("recv_buff_size", 0);
- //xports.recv = nirio_zero_copy::make(
- //_rio_fpga_interface, dma_channel_num, default_buff_args);
+ // zero_copy_xport_params default_buff_args;
+ // xports.endianness = ENDIANNESS_LITTLE;
+ // xports.lossless = true;
+ // const uint32_t dma_channel_num = allocate_pcie_dma_chan(xports.send_sid,
+ // xport_type); if (xport_type == uhd::transport::link_type_t::CTRL) {
+ //// Transport for control stream
+ // if (not _ctrl_dma_xport) {
+ //// One underlying DMA channel will handle
+ //// all control traffic
+ //_ctrl_dma_xport =
+ // make_muxed_pcie_msg_xport(dma_channel_num, PCIE_MAX_MUXED_CTRL_XPORTS);
+ //}
+ //// Create a virtual control transport
+ // xports.recv = _ctrl_dma_xport->make_stream(xports.recv_sid.get_dst());
+ //} else if (xport_type == uhd::transport::link_type_t::ASYNC_MSG) {
+ //// Transport for async message stream
+ // if (not _async_msg_dma_xport) {
+ //// One underlying DMA channel will handle
+ //// all async message traffic
+ //_async_msg_dma_xport =
+ // make_muxed_pcie_msg_xport(dma_channel_num, PCIE_MAX_MUXED_ASYNC_XPORTS);
+ //}
+ //// Create a virtual async message transport
+ // xports.recv = _async_msg_dma_xport->make_stream(xports.recv_sid.get_dst());
+ //} else if (xport_type == uhd::transport::link_type_t::TX_DATA) {
+ // default_buff_args.send_frame_size = args.cast<size_t>(
+ //"send_frame_size", std::min(send_mtu, PCIE_TX_DATA_FRAME_SIZE));
+ // default_buff_args.num_send_frames =
+ // args.cast<size_t>("num_send_frames", PCIE_TX_DATA_NUM_FRAMES);
+ // default_buff_args.send_buff_size = args.cast<size_t>("send_buff_size", 0);
+ // default_buff_args.recv_frame_size = PCIE_MSG_FRAME_SIZE;
+ // default_buff_args.num_recv_frames = PCIE_MSG_NUM_FRAMES;
+ // xports.recv = nirio_zero_copy::make(
+ //_rio_fpga_interface, dma_channel_num, default_buff_args);
+ //} else if (xport_type == uhd::transport::link_type_t::RX_DATA) {
+ // default_buff_args.send_frame_size = PCIE_MSG_FRAME_SIZE;
+ // default_buff_args.num_send_frames = PCIE_MSG_NUM_FRAMES;
+ // default_buff_args.recv_frame_size = args.cast<size_t>(
+ //"recv_frame_size", std::min(recv_mtu, PCIE_RX_DATA_FRAME_SIZE));
+ // default_buff_args.num_recv_frames =
+ // args.cast<size_t>("num_recv_frames", PCIE_RX_DATA_NUM_FRAMES);
+ // default_buff_args.recv_buff_size = args.cast<size_t>("recv_buff_size", 0);
+ // xports.recv = nirio_zero_copy::make(
+ //_rio_fpga_interface, dma_channel_num, default_buff_args);
//}
//xports.send = xports.recv;
diff --git a/host/lib/usrp/x300/x300_radio_ctrl_impl.cpp b/host/lib/usrp/x300/x300_radio_ctrl_impl.cpp
deleted file mode 100644
index c280f77c5..000000000
--- a/host/lib/usrp/x300/x300_radio_ctrl_impl.cpp
+++ /dev/null
@@ -1,1577 +0,0 @@
-//
-// Copyright 2015-2017 Ettus Research, A National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include "x300_radio_ctrl_impl.hpp"
-#include "x300_dboard_iface.hpp"
-#include <uhd/rfnoc/node_ctrl_base.hpp>
-#include <uhd/transport/chdr.hpp>
-#include <uhd/usrp/dboard_eeprom.hpp>
-#include <uhd/usrp/dboard_iface.hpp>
-#include <uhd/utils/log.hpp>
-#include <uhd/utils/math.hpp>
-#include <uhd/utils/safe_call.hpp>
-#include <uhdlib/rfnoc/wb_iface_adapter.hpp>
-#include <uhdlib/usrp/common/apply_corrections.hpp>
-#include <uhdlib/usrp/cores/gpio_atr_3000.hpp>
-#include <boost/algorithm/string.hpp>
-#include <boost/date_time/posix_time/posix_time_io.hpp>
-#include <boost/make_shared.hpp>
-#include <chrono>
-#include <thread>
-#include <bitset>
-
-using namespace uhd;
-using namespace uhd::usrp;
-using namespace uhd::rfnoc;
-using namespace uhd::usrp::x300;
-
-static const size_t IO_MASTER_RADIO = 0;
-
-namespace {
-
-gain_fcns_t make_gain_fcns_from_subtree(property_tree::sptr subtree)
-{
- gain_fcns_t gain_fcns;
- gain_fcns.get_range = [subtree]() {
- return subtree->access<meta_range_t>("range").get();
- };
- gain_fcns.get_value = [subtree]() { return subtree->access<double>("value").get(); };
- gain_fcns.set_value = [subtree](const double gain) {
- subtree->access<double>("value").set(gain);
- };
- return gain_fcns;
-}
-
-} // namespace
-
-/****************************************************************************
- * Structors
- ***************************************************************************/
-UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR(x300_radio_ctrl)
-, _ignore_cal_file(false)
-{
- UHD_RFNOC_BLOCK_TRACE() << "x300_radio_ctrl_impl::ctor() ";
-
- ////////////////////////////////////////////////////////////////////
- // Set up basic info
- ////////////////////////////////////////////////////////////////////
- _radio_type = (get_block_id().get_block_count() == 0) ? PRIMARY : SECONDARY;
- _radio_slot = (get_block_id().get_block_count() == 0) ? "A" : "B";
- _radio_clk_rate = _tree->access<double>("master_clock_rate").get();
-
- ////////////////////////////////////////////////////////////////////
- // Set up peripherals
- ////////////////////////////////////////////////////////////////////
- wb_iface::sptr ctrl = _get_ctrl(IO_MASTER_RADIO);
- _regs = boost::make_shared<radio_regmap_t>(_radio_type == PRIMARY ? 0 : 1);
- _regs->initialize(*ctrl, true);
-
- // Only Radio0 has the ADC/DAC reset bits. Those bits are reserved for Radio1
- if (_radio_type == PRIMARY) {
- _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::ADC_RESET, 1);
- _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::DAC_RESET_N, 0);
- _regs->misc_outs_reg.flush();
- _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::ADC_RESET, 0);
- _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::DAC_RESET_N, 1);
- _regs->misc_outs_reg.flush();
- }
- _regs->misc_outs_reg.write(radio_regmap_t::misc_outs_reg_t::DAC_ENABLED, 1);
-
- ////////////////////////////////////////////////////////////////
- // Setup peripherals
- ////////////////////////////////////////////////////////////////
- _spi = spi_core_3000::make(ctrl,
- regs::sr_addr(radio_ctrl_impl::regs::SPI),
- regs::rb_addr(radio_ctrl_impl::regs::RB_SPI));
- _adc = x300_adc_ctrl::make(_spi, DB_ADC_SEN);
- _dac = x300_dac_ctrl::make(_spi, DB_DAC_SEN, _radio_clk_rate);
-
- if (_radio_type == PRIMARY) {
- _fp_gpio = gpio_atr::gpio_atr_3000::make(
- ctrl, regs::sr_addr(regs::FP_GPIO), regs::rb_addr(regs::RB_FP_GPIO));
- for (const gpio_atr::gpio_attr_map_t::value_type attr : gpio_atr::gpio_attr_map) {
- switch (attr.first) {
- case usrp::gpio_atr::GPIO_SRC:
- _tree
- ->create<std::vector<std::string>>(
- fs_path("gpio") / "FP0" / attr.second)
- .set(std::vector<std::string>(
- 32, usrp::gpio_atr::default_attr_value_map.at(attr.first)))
- .add_coerced_subscriber([this](const std::vector<std::string>&) {
- throw uhd::runtime_error("This device does not support "
- "setting the GPIO_SRC attribute.");
- });
- break;
- case usrp::gpio_atr::GPIO_CTRL:
- case usrp::gpio_atr::GPIO_DDR:
- _tree
- ->create<std::vector<std::string>>(
- fs_path("gpio") / "FP0" / attr.second)
- .set(std::vector<std::string>(
- 32, usrp::gpio_atr::default_attr_value_map.at(attr.first)))
- .add_coerced_subscriber(
- [this, attr](const std::vector<std::string> str_val) {
- uint32_t val = 0;
- for (size_t i = 0; i < str_val.size(); i++) {
- val += usrp::gpio_atr::gpio_attr_value_pair
- .at(attr.second)
- .at(str_val[i])
- << i;
- }
- _fp_gpio->set_gpio_attr(attr.first, val);
- });
- break;
- case usrp::gpio_atr::GPIO_READBACK:
- _tree->create<uint32_t>(fs_path("gpio") / "FP0" / "READBACK")
- .set_publisher([this]() { return _fp_gpio->read_gpio(); });
- break;
- default:
- _tree->create<uint32_t>(fs_path("gpio") / "FP0" / attr.second)
- .set(0)
- .add_coerced_subscriber([this, attr](const uint32_t val) {
- _fp_gpio->set_gpio_attr(attr.first, val);
- });
- }
- }
- }
-
- ////////////////////////////////////////////////////////////////
- // create legacy codec control objects
- ////////////////////////////////////////////////////////////////
- _tree->create<int>(
- "rx_codecs" / _radio_slot / "gains"); // phony property so this dir exists
- _tree->create<int>(
- "tx_codecs" / _radio_slot / "gains"); // phony property so this dir exists
- _tree->create<std::string>("rx_codecs" / _radio_slot / "name").set("ads62p48");
- _tree->create<std::string>("tx_codecs" / _radio_slot / "name").set("ad9146");
-
- _tree->create<meta_range_t>("rx_codecs" / _radio_slot / "gains" / "digital" / "range")
- .set(meta_range_t(0, 6.0, 0.5));
- _tree->create<double>("rx_codecs" / _radio_slot / "gains" / "digital" / "value")
- .add_coerced_subscriber(boost::bind(&x300_adc_ctrl::set_gain, _adc, _1))
- .set(0);
-
- ////////////////////////////////////////////////////////////////
- // create front-end objects
- ////////////////////////////////////////////////////////////////
- for (size_t i = 0; i < _get_num_radios(); i++) {
- _leds[i] = gpio_atr::gpio_atr_3000::make_write_only(
- _get_ctrl(i), regs::sr_addr(regs::LEDS));
- _leds[i]->set_atr_mode(
- usrp::gpio_atr::MODE_ATR, usrp::gpio_atr::gpio_atr_3000::MASK_SET_ALL);
-
- _rx_fe_map[i].core = rx_frontend_core_3000::make(
- _get_ctrl(i), regs::sr_addr(x300_regs::RX_FE_BASE));
- _rx_fe_map[i].core->set_adc_rate(_radio_clk_rate);
- _rx_fe_map[i].core->set_dc_offset(rx_frontend_core_3000::DEFAULT_DC_OFFSET_VALUE);
- _rx_fe_map[i].core->set_dc_offset_auto(
- rx_frontend_core_3000::DEFAULT_DC_OFFSET_ENABLE);
- _rx_fe_map[i].core->populate_subtree(
- _tree->subtree(_root_path / "rx_fe_corrections" / i));
-
- _tx_fe_map[i].core = tx_frontend_core_200::make(
- _get_ctrl(i), regs::sr_addr(x300_regs::TX_FE_BASE));
- _tx_fe_map[i].core->set_dc_offset(tx_frontend_core_200::DEFAULT_DC_OFFSET_VALUE);
- _tx_fe_map[i].core->set_iq_balance(
- tx_frontend_core_200::DEFAULT_IQ_BALANCE_VALUE);
- _tx_fe_map[i].core->populate_subtree(
- _tree->subtree(_root_path / "tx_fe_corrections" / i));
-
- ////////////////////////////////////////////////////////////////
- // Bind the daughterboard command time to the motherboard level property
- ////////////////////////////////////////////////////////////////
-
- if (_tree->exists(fs_path("time") / "cmd")) {
- _tree->access<time_spec_t>(fs_path("time") / "cmd")
- .add_coerced_subscriber(
- boost::bind(&x300_radio_ctrl_impl::set_fe_cmd_time, this, _1, i));
- }
- }
-
- ////////////////////////////////////////////////////////////////
- // Update default SPP (overwrites the default value from the XML file)
- ////////////////////////////////////////////////////////////////
- const size_t max_bytes_header =
- uhd::transport::vrt::chdr::max_if_hdr_words64 * sizeof(uint64_t);
- const size_t default_spp =
- (_tree->access<size_t>("mtu/recv").get() - max_bytes_header)
- / (2 * sizeof(int16_t));
- _tree->access<int>(get_arg_path("spp") / "value").set(default_spp);
-}
-
-x300_radio_ctrl_impl::~x300_radio_ctrl_impl()
-{
- UHD_SAFE_CALL(
- // Tear down our part of the tree:
- _tree->remove(fs_path("rx_codecs" / _radio_slot));
- _tree->remove(fs_path("tx_codecs" / _radio_slot));
- _tree->remove(_root_path / "rx_fe_corrections");
- _tree->remove(_root_path / "tx_fe_corrections");
- if (_radio_type == PRIMARY) {
- for (const gpio_atr::gpio_attr_map_t::value_type attr :
- gpio_atr::gpio_attr_map) {
- _tree->remove(fs_path("gpio") / "FP0" / attr.second);
- }
- }
-
- // Reset peripherals
- if (_radio_type == PRIMARY) {
- _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::ADC_RESET, 1);
- _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::DAC_RESET_N, 0);
- } _regs->misc_outs_reg.write(radio_regmap_t::misc_outs_reg_t::DAC_ENABLED, 0);
- _regs->misc_outs_reg.flush();)
-}
-
-/****************************************************************************
- * API calls
- ***************************************************************************/
-double x300_radio_ctrl_impl::set_rate(double rate)
-{
- const double actual_rate = get_rate();
- if (not uhd::math::frequencies_are_equal(rate, actual_rate)) {
- UHD_LOGGER_WARNING("X300 RADIO")
- << "Requesting invalid sampling rate from device: " << rate / 1e6
- << " MHz. Actual rate is: " << actual_rate / 1e6 << " MHz.";
- }
- // On X3x0, tick rate can't actually be changed at runtime
- return actual_rate;
-}
-
-void x300_radio_ctrl_impl::set_fe_cmd_time(const time_spec_t& time, const size_t chan)
-{
- if (_tree->exists(fs_path("dboards" / _radio_slot / "rx_frontends"
- / _rx_fe_map.at(chan).db_fe_name / "time" / "cmd"))) {
- _tree
- ->access<time_spec_t>(
- fs_path("dboards" / _radio_slot / "rx_frontends"
- / _rx_fe_map.at(chan).db_fe_name / "time" / "cmd"))
- .set(time);
- }
-}
-
-void x300_radio_ctrl_impl::set_tx_antenna(const std::string& ant, const size_t chan)
-{
- _tree
- ->access<std::string>(
- fs_path("dboards" / _radio_slot / "tx_frontends"
- / _tx_fe_map.at(chan).db_fe_name / "antenna" / "value"))
- .set(ant);
-}
-
-std::string x300_radio_ctrl_impl::get_tx_antenna(const size_t chan)
-{
- return _tree
- ->access<std::string>(
- fs_path("dboards" / _radio_slot / "tx_frontends"
- / _tx_fe_map.at(chan).db_fe_name / "antenna" / "value"))
- .get();
-}
-
-void x300_radio_ctrl_impl::set_rx_antenna(const std::string& ant, const size_t chan)
-{
- _tree
- ->access<std::string>(
- fs_path("dboards" / _radio_slot / "rx_frontends"
- / _rx_fe_map.at(chan).db_fe_name / "antenna" / "value"))
- .set(ant);
-}
-
-std::string x300_radio_ctrl_impl::get_rx_antenna(const size_t chan)
-{
- return _tree
- ->access<std::string>(
- fs_path("dboards" / _radio_slot / "rx_frontends"
- / _rx_fe_map.at(chan).db_fe_name / "antenna" / "value"))
- .get();
-}
-
-double x300_radio_ctrl_impl::set_tx_frequency(const double freq, const size_t chan)
-{
- return _tree
- ->access<double>(fs_path("dboards" / _radio_slot / "tx_frontends"
- / _tx_fe_map.at(chan).db_fe_name / "freq" / "value"))
- .set(freq)
- .get();
-}
-
-double x300_radio_ctrl_impl::get_tx_frequency(const size_t chan)
-{
- return _tree
- ->access<double>(fs_path("dboards" / _radio_slot / "tx_frontends"
- / _tx_fe_map.at(chan).db_fe_name / "freq" / "value"))
- .get();
-}
-
-double x300_radio_ctrl_impl::set_rx_frequency(const double freq, const size_t chan)
-{
- return _tree
- ->access<double>(fs_path("dboards" / _radio_slot / "rx_frontends"
- / _rx_fe_map.at(chan).db_fe_name / "freq" / "value"))
- .set(freq)
- .get();
-}
-
-double x300_radio_ctrl_impl::get_rx_frequency(const size_t chan)
-{
- return _tree
- ->access<double>(fs_path("dboards" / _radio_slot / "rx_frontends"
- / _rx_fe_map.at(chan).db_fe_name / "freq" / "value"))
- .get();
-}
-
-double x300_radio_ctrl_impl::set_rx_bandwidth(const double bandwidth, const size_t chan)
-{
- return _tree
- ->access<double>(
- fs_path("dboards" / _radio_slot / "rx_frontends"
- / _rx_fe_map.at(chan).db_fe_name / "bandwidth" / "value"))
- .set(bandwidth)
- .get();
-}
-
-double x300_radio_ctrl_impl::get_rx_bandwidth(const size_t chan)
-{
- return _tree
- ->access<double>(
- fs_path("dboards" / _radio_slot / "rx_frontends"
- / _rx_fe_map.at(chan).db_fe_name / "bandwidth" / "value"))
- .get();
-}
-
-double x300_radio_ctrl_impl::set_tx_gain(const double gain, const size_t chan)
-{
- if (_tx_gain_groups.count(chan)) {
- auto& gg = _tx_gain_groups.at(chan);
- gg->set_value(gain);
- return radio_ctrl_impl::set_tx_gain(gg->get_value(), chan);
- }
- return radio_ctrl_impl::set_tx_gain(0.0, chan);
-}
-
-double x300_radio_ctrl_impl::set_rx_gain(const double gain, const size_t chan)
-{
- auto& gg = _rx_gain_groups.at(chan);
- gg->set_value(gain);
- return radio_ctrl_impl::set_rx_gain(gg->get_value(), chan);
-}
-
-double x300_radio_ctrl_impl::get_rx_gain(const size_t chan)
-{
- return _rx_gain_groups.at(chan)->get_value();
-}
-
-std::vector<std::string> x300_radio_ctrl_impl::get_rx_lo_names(const size_t chan)
-{
- fs_path rx_fe_fe_root = fs_path(
- "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name);
-
- std::vector<std::string> lo_names;
- if (_tree->exists(rx_fe_fe_root / "los")) {
- for (const std::string& name : _tree->list(rx_fe_fe_root / "los")) {
- lo_names.push_back(name);
- }
- }
- return lo_names;
-}
-
-std::vector<std::string> x300_radio_ctrl_impl::get_rx_lo_sources(
- const std::string& name, const size_t chan)
-{
- fs_path rx_fe_fe_root = fs_path(
- "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name);
-
- if (_tree->exists(rx_fe_fe_root / "los")) {
- if (name == ALL_LOS) {
- if (_tree->exists(rx_fe_fe_root / "los" / ALL_LOS)) {
- // Special value ALL_LOS support atomically sets the source for all LOs
- return _tree
- ->access<std::vector<std::string>>(
- rx_fe_fe_root / "los" / ALL_LOS / "source" / "options")
- .get();
- } else {
- return std::vector<std::string>();
- }
- } else {
- if (_tree->exists(rx_fe_fe_root / "los")) {
- return _tree
- ->access<std::vector<std::string>>(
- rx_fe_fe_root / "los" / name / "source" / "options")
- .get();
- } else {
- throw uhd::runtime_error("Could not find LO stage " + name);
- }
- }
- } else {
- // If the daughterboard doesn't expose it's LO(s) then it can only be internal
- return std::vector<std::string>(1, "internal");
- }
-}
-
-void x300_radio_ctrl_impl::set_rx_lo_source(
- const std::string& src, const std::string& name, const size_t chan)
-{
- fs_path rx_fe_fe_root = fs_path(
- "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name);
-
- if (_tree->exists(rx_fe_fe_root / "los")) {
- if (name == ALL_LOS) {
- if (_tree->exists(rx_fe_fe_root / "los" / ALL_LOS)) {
- // Special value ALL_LOS support atomically sets the source for all LOs
- _tree
- ->access<std::string>(
- rx_fe_fe_root / "los" / ALL_LOS / "source" / "value")
- .set(src);
- } else {
- for (const std::string& n : _tree->list(rx_fe_fe_root / "los")) {
- this->set_rx_lo_source(src, n, chan);
- }
- }
- } else {
- if (_tree->exists(rx_fe_fe_root / "los")) {
- _tree
- ->access<std::string>(
- rx_fe_fe_root / "los" / name / "source" / "value")
- .set(src);
- } else {
- throw uhd::runtime_error("Could not find LO stage " + name);
- }
- }
- } else {
- throw uhd::runtime_error(
- "This device does not support manual configuration of LOs");
- }
-}
-
-const std::string x300_radio_ctrl_impl::get_rx_lo_source(
- const std::string& name, const size_t chan)
-{
- fs_path rx_fe_fe_root = fs_path(
- "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name);
-
- if (_tree->exists(rx_fe_fe_root / "los")) {
- if (name == ALL_LOS) {
- // Special value ALL_LOS support atomically sets the source for all LOs
- return _tree
- ->access<std::string>(
- rx_fe_fe_root / "los" / ALL_LOS / "source" / "value")
- .get();
- } else {
- if (_tree->exists(rx_fe_fe_root / "los")) {
- return _tree
- ->access<std::string>(
- rx_fe_fe_root / "los" / name / "source" / "value")
- .get();
- } else {
- throw uhd::runtime_error("Could not find LO stage " + name);
- }
- }
- } else {
- // If the daughterboard doesn't expose it's LO(s) then it can only be internal
- return "internal";
- }
-}
-
-void x300_radio_ctrl_impl::set_rx_lo_export_enabled(
- bool enabled, const std::string& name, const size_t chan)
-{
- fs_path rx_fe_fe_root = fs_path(
- "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name);
-
- if (_tree->exists(rx_fe_fe_root / "los")) {
- if (name == ALL_LOS) {
- if (_tree->exists(rx_fe_fe_root / "los" / ALL_LOS)) {
- // Special value ALL_LOS support atomically sets the source for all LOs
- _tree->access<bool>(rx_fe_fe_root / "los" / ALL_LOS / "export")
- .set(enabled);
- } else {
- for (const std::string& n : _tree->list(rx_fe_fe_root / "los")) {
- this->set_rx_lo_export_enabled(enabled, n, chan);
- }
- }
- } else {
- if (_tree->exists(rx_fe_fe_root / "los")) {
- _tree->access<bool>(rx_fe_fe_root / "los" / name / "export").set(enabled);
- } else {
- throw uhd::runtime_error("Could not find LO stage " + name);
- }
- }
- } else {
- throw uhd::runtime_error(
- "This device does not support manual configuration of LOs");
- }
-}
-
-bool x300_radio_ctrl_impl::get_rx_lo_export_enabled(
- const std::string& name, const size_t chan)
-{
- fs_path rx_fe_fe_root = fs_path(
- "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name);
-
- if (_tree->exists(rx_fe_fe_root / "los")) {
- if (name == ALL_LOS) {
- // Special value ALL_LOS support atomically sets the source for all LOs
- return _tree->access<bool>(rx_fe_fe_root / "los" / ALL_LOS / "export").get();
- } else {
- if (_tree->exists(rx_fe_fe_root / "los")) {
- return _tree->access<bool>(rx_fe_fe_root / "los" / name / "export").get();
- } else {
- throw uhd::runtime_error("Could not find LO stage " + name);
- }
- }
- } else {
- // If the daughterboard doesn't expose it's LO(s), assume it cannot export
- return false;
- }
-}
-
-double x300_radio_ctrl_impl::set_rx_lo_freq(
- double freq, const std::string& name, const size_t chan)
-{
- fs_path rx_fe_fe_root = fs_path(
- "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name);
-
- if (_tree->exists(rx_fe_fe_root / "los")) {
- if (name == ALL_LOS) {
- throw uhd::runtime_error(
- "LO frequency must be set for each stage individually");
- } else {
- if (_tree->exists(rx_fe_fe_root / "los")) {
- _tree->access<double>(rx_fe_fe_root / "los" / name / "freq" / "value")
- .set(freq);
- return _tree
- ->access<double>(rx_fe_fe_root / "los" / name / "freq" / "value")
- .get();
- } else {
- throw uhd::runtime_error("Could not find LO stage " + name);
- }
- }
- } else {
- throw uhd::runtime_error(
- "This device does not support manual configuration of LOs");
- }
-}
-
-double x300_radio_ctrl_impl::get_rx_lo_freq(const std::string& name, const size_t chan)
-{
- fs_path rx_fe_fe_root = fs_path(
- "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name);
-
- if (_tree->exists(rx_fe_fe_root / "los")) {
- if (name == ALL_LOS) {
- throw uhd::runtime_error(
- "LO frequency must be retrieved for each stage individually");
- } else {
- if (_tree->exists(rx_fe_fe_root / "los")) {
- return _tree
- ->access<double>(rx_fe_fe_root / "los" / name / "freq" / "value")
- .get();
- } else {
- throw uhd::runtime_error("Could not find LO stage " + name);
- }
- }
- } else {
- // Return actual RF frequency if the daughterboard doesn't expose it's LO(s)
- return _tree->access<double>(rx_fe_fe_root / "freq" / " value").get();
- }
-}
-
-freq_range_t x300_radio_ctrl_impl::get_rx_lo_freq_range(
- const std::string& name, const size_t chan)
-{
- fs_path rx_fe_fe_root = fs_path(
- "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name);
-
- if (_tree->exists(rx_fe_fe_root / "los")) {
- if (name == ALL_LOS) {
- throw uhd::runtime_error(
- "LO frequency range must be retrieved for each stage individually");
- } else {
- if (_tree->exists(rx_fe_fe_root / "los")) {
- return _tree
- ->access<freq_range_t>(
- rx_fe_fe_root / "los" / name / "freq" / "range")
- .get();
- } else {
- throw uhd::runtime_error("Could not find LO stage " + name);
- }
- }
- } else {
- // Return the actual RF range if the daughterboard doesn't expose it's LO(s)
- return _tree->access<meta_range_t>(rx_fe_fe_root / "freq" / "range").get();
- }
-}
-
-template <typename map_type>
-static size_t _get_chan_from_map(std::map<size_t, map_type> map, const std::string& fe)
-{
- for (auto it = map.begin(); it != map.end(); ++it) {
- if (it->second.db_fe_name == fe) {
- return it->first;
- }
- }
- throw uhd::runtime_error(
- str(boost::format("Invalid daughterboard frontend name: %s") % fe));
-}
-
-size_t x300_radio_ctrl_impl::get_chan_from_dboard_fe(
- const std::string& fe, const uhd::direction_t direction)
-{
- switch (direction) {
- case uhd::TX_DIRECTION:
- return _get_chan_from_map(_tx_fe_map, fe);
- case uhd::RX_DIRECTION:
- return _get_chan_from_map(_rx_fe_map, fe);
- default:
- UHD_THROW_INVALID_CODE_PATH();
- }
-}
-
-std::string x300_radio_ctrl_impl::get_dboard_fe_from_chan(
- const size_t chan, const uhd::direction_t direction)
-{
- switch (direction) {
- case uhd::TX_DIRECTION:
- return _tx_fe_map.at(chan).db_fe_name;
- case uhd::RX_DIRECTION:
- return _rx_fe_map.at(chan).db_fe_name;
- default:
- UHD_THROW_INVALID_CODE_PATH();
- }
-}
-
-double x300_radio_ctrl_impl::get_output_samp_rate(size_t chan)
-{
- // TODO: chan should never be ANY_PORT, but due to our current graph search
- // method, this can actually happen:
- if (chan == ANY_PORT) {
- chan = 0;
- for (size_t i = 0; i < _get_num_radios(); i++) {
- if (_is_streamer_active(uhd::RX_DIRECTION, chan)) {
- chan = i;
- break;
- }
- }
- }
- return _rx_fe_map.at(chan).core->get_output_rate();
-}
-
-std::vector<std::string> x300_radio_ctrl_impl::get_gpio_banks() const
-{
- std::vector<std::string> banks{"RX", "TX"};
- // These pairs are the same, but RXA/TXA are from pre-rfnoc era and are kept for
- // backward compat:
- banks.push_back("RX" + _radio_slot);
- banks.push_back("TX" + _radio_slot);
- if (_fp_gpio) {
- banks.push_back("FP0");
- }
- return banks;
-}
-
-void x300_radio_ctrl_impl::set_gpio_attr(const std::string& bank,
- const std::string& attr,
- const uint32_t value,
- const uint32_t mask)
-{
- if (bank == "FP0" and _fp_gpio) {
- std::vector<std::string> attr_value;
- const auto attr_type = usrp::gpio_atr::gpio_attr_rev_map.at(attr);
- switch (attr_type) {
- case usrp::gpio_atr::GPIO_SRC:
- case usrp::gpio_atr::GPIO_CTRL:
- case usrp::gpio_atr::GPIO_DDR: {
- attr_value =
- _tree->access<std::vector<std::string>>(fs_path("gpio") / bank / attr)
- .get();
- std::bitset<32> bit_mask = std::bitset<32>(mask);
- std::bitset<32> new_value = std::bitset<32>(value);
- for (size_t i = 0; i < bit_mask.size(); i++) {
- if (bit_mask[i] == 1) {
- attr_value[i] =
- usrp::gpio_atr::attr_value_map.at(attr_type).at(new_value[i]);
- }
- }
- _tree->access<std::vector<std::string>>(fs_path("gpio") / bank / attr)
- .set(attr_value);
- return;
- } break;
- default: {
- const uint32_t curr_value =
- _tree->access<uint32_t>(fs_path("gpio") / bank / attr).get();
- uint32_t new_value = (curr_value & ~mask) | (value & mask);
- _tree->access<uint32_t>(fs_path("gpio") / bank / attr).set(new_value);
- } break;
- }
- }
- if (bank.size() > 2 and bank[1] == 'X') {
- const std::string name = bank.substr(2);
- const dboard_iface::unit_t unit = (bank[0] == 'R') ? dboard_iface::UNIT_RX
- : dboard_iface::UNIT_TX;
- dboard_iface::sptr iface =
- _tree->access<dboard_iface::sptr>(fs_path("dboards") / name / "iface").get();
- if (attr == "CTRL")
- iface->set_pin_ctrl(unit, uint16_t(value), uint16_t(mask));
- if (attr == "DDR")
- iface->set_gpio_ddr(unit, uint16_t(value), uint16_t(mask));
- if (attr == "OUT")
- iface->set_gpio_out(unit, uint16_t(value), uint16_t(mask));
- if (attr == "ATR_0X")
- iface->set_atr_reg(
- unit, gpio_atr::ATR_REG_IDLE, uint16_t(value), uint16_t(mask));
- if (attr == "ATR_RX")
- iface->set_atr_reg(
- unit, gpio_atr::ATR_REG_RX_ONLY, uint16_t(value), uint16_t(mask));
- if (attr == "ATR_TX")
- iface->set_atr_reg(
- unit, gpio_atr::ATR_REG_TX_ONLY, uint16_t(value), uint16_t(mask));
- if (attr == "ATR_XX")
- iface->set_atr_reg(
- unit, gpio_atr::ATR_REG_FULL_DUPLEX, uint16_t(value), uint16_t(mask));
- }
-}
-
-uint32_t x300_radio_ctrl_impl::get_gpio_attr(
- const std::string& bank, const std::string& attr)
-{
- if (bank == "FP0" and _fp_gpio) {
- const auto attr_type = usrp::gpio_atr::gpio_attr_rev_map.at(attr);
- switch(attr_type) {
- case usrp::gpio_atr::GPIO_SRC:
- case usrp::gpio_atr::GPIO_CTRL:
- case usrp::gpio_atr::GPIO_DDR: {
- auto str_val =
- _tree->access<std::vector<std::string>>(
- fs_path("gpio") / bank / attr).get();
- uint32_t val = 0;
- for (size_t i = 0; i < str_val.size(); i++) {
- val += usrp::gpio_atr::gpio_attr_value_pair.at(attr).at(str_val[i]) << i;
- }
- return val;
- }
- break;
- default: {
- return _tree->access<uint32_t>(fs_path("gpio") / bank / attr).get();
- }
- break;
- }
- }
- if (bank.size() > 2 and bank[1] == 'X') {
- const std::string name = bank.substr(2);
- const dboard_iface::unit_t unit = (bank[0] == 'R') ? dboard_iface::UNIT_RX
- : dboard_iface::UNIT_TX;
- dboard_iface::sptr iface =
- _tree->access<dboard_iface::sptr>(fs_path("dboards") / name / "iface").get();
- if (attr == "CTRL")
- return iface->get_pin_ctrl(unit);
- if (attr == "DDR")
- return iface->get_gpio_ddr(unit);
- if (attr == "OUT")
- return iface->get_gpio_out(unit);
- if (attr == "ATR_0X")
- return iface->get_atr_reg(unit, gpio_atr::ATR_REG_IDLE);
- if (attr == "ATR_RX")
- return iface->get_atr_reg(unit, gpio_atr::ATR_REG_RX_ONLY);
- if (attr == "ATR_TX")
- return iface->get_atr_reg(unit, gpio_atr::ATR_REG_TX_ONLY);
- if (attr == "ATR_XX")
- return iface->get_atr_reg(unit, gpio_atr::ATR_REG_FULL_DUPLEX);
- if (attr == "READBACK")
- return iface->read_gpio(unit);
- }
- return 0;
-}
-
-/****************************************************************************
- * Radio control and setup
- ***************************************************************************/
-void x300_radio_ctrl_impl::setup_radio(uhd::i2c_iface::sptr zpu_i2c,
- x300_clock_ctrl::sptr clock,
- bool ignore_cal_file,
- bool verbose)
-{
- _self_cal_adc_capture_delay(verbose);
- _ignore_cal_file = ignore_cal_file;
-
- ////////////////////////////////////////////////////////////////////
- // create RF frontend interfacing
- ////////////////////////////////////////////////////////////////////
- static const size_t BASE_ADDR = 0x50;
- static const size_t RX_EEPROM_ADDR = 0x5;
- static const size_t TX_EEPROM_ADDR = 0x4;
- static const size_t GDB_EEPROM_ADDR = 0x1;
- const static std::vector<size_t> EEPROM_ADDRS{
- RX_EEPROM_ADDR, TX_EEPROM_ADDR, GDB_EEPROM_ADDR};
- const static std::vector<std::string> EEPROM_PATHS{
- "rx_eeprom", "tx_eeprom", "gdb_eeprom"};
-
- const size_t DB_OFFSET = (_radio_slot == "A") ? 0x0 : 0x2;
- const fs_path db_path = ("dboards" / _radio_slot);
- for (size_t i = 0; i < EEPROM_ADDRS.size(); i++) {
- const size_t addr = EEPROM_ADDRS[i] + DB_OFFSET;
- // Load EEPROM
- _db_eeproms[addr].load(*zpu_i2c, BASE_ADDR | addr);
- // Add to tree
- _tree->create<dboard_eeprom_t>(db_path / EEPROM_PATHS[i])
- .set(_db_eeproms[addr])
- .add_coerced_subscriber(boost::bind(&x300_radio_ctrl_impl::_set_db_eeprom,
- this,
- zpu_i2c,
- (BASE_ADDR | addr),
- _1));
- }
-
- // create a new dboard interface
- x300_dboard_iface_config_t db_config;
- db_config.gpio = gpio_atr::db_gpio_atr_3000::make(_get_ctrl(IO_MASTER_RADIO),
- radio_ctrl_impl::regs::sr_addr(radio_ctrl_impl::regs::GPIO),
- radio_ctrl_impl::regs::rb_addr(radio_ctrl_impl::regs::RB_DB_GPIO));
- db_config.spi = _spi;
- db_config.rx_spi_slaveno = DB_RX_SEN;
- db_config.tx_spi_slaveno = DB_TX_SEN;
- db_config.i2c = zpu_i2c;
- db_config.clock = clock;
- db_config.which_rx_clk = (_radio_slot == "A") ? X300_CLOCK_WHICH_DB0_RX
- : X300_CLOCK_WHICH_DB1_RX;
- db_config.which_tx_clk = (_radio_slot == "A") ? X300_CLOCK_WHICH_DB0_TX
- : X300_CLOCK_WHICH_DB1_TX;
- db_config.dboard_slot = (_radio_slot == "A") ? 0 : 1;
- db_config.cmd_time_ctrl = _get_ctrl(IO_MASTER_RADIO);
-
- // create a new dboard manager
- boost::shared_ptr<x300_dboard_iface> db_iface =
- boost::make_shared<x300_dboard_iface>(db_config);
- _db_manager = dboard_manager::make(_db_eeproms[RX_EEPROM_ADDR + DB_OFFSET],
- _db_eeproms[TX_EEPROM_ADDR + DB_OFFSET],
- _db_eeproms[GDB_EEPROM_ADDR + DB_OFFSET],
- db_iface,
- _tree->subtree(db_path),
- true // defer daughterboard intitialization
- );
-
- size_t rx_chan = 0, tx_chan = 0;
- for (const std::string& fe : _db_manager->get_rx_frontends()) {
- if (rx_chan >= _get_num_radios()) {
- break;
- }
- _rx_fe_map[rx_chan].db_fe_name = fe;
- db_iface->add_rx_fe(fe, _rx_fe_map[rx_chan].core);
- const fs_path fe_path(db_path / "rx_frontends" / fe);
- const std::string conn = _tree->access<std::string>(fe_path / "connection").get();
- const double if_freq =
- (_tree->exists(fe_path / "if_freq/value"))
- ? _tree->access<double>(fe_path / "if_freq/value").get()
- : 0.0;
- _rx_fe_map[rx_chan].core->set_fe_connection(usrp::fe_connection_t(conn, if_freq));
- rx_chan++;
- }
- for (const std::string& fe : _db_manager->get_tx_frontends()) {
- if (tx_chan >= _get_num_radios()) {
- break;
- }
- _tx_fe_map[tx_chan].db_fe_name = fe;
- const fs_path fe_path(db_path / "tx_frontends" / fe);
- const std::string conn = _tree->access<std::string>(fe_path / "connection").get();
- _tx_fe_map[tx_chan].core->set_mux(conn);
- tx_chan++;
- }
- UHD_ASSERT_THROW(rx_chan or tx_chan);
-
- // Initialize the daughterboards now that frontend cores and connections exist
- _db_manager->initialize_dboards();
-
- // now that dboard is created -- register into rx antenna event
- if (not _rx_fe_map.empty()) {
- for (size_t i = 0; i < _get_num_radios(); i++) {
- if (_tree->exists(db_path / "rx_frontends" / _rx_fe_map[i].db_fe_name
- / "antenna" / "value")) {
- // We need a desired subscriber for antenna/value because the experts
- // don't coerce that property.
- _tree
- ->access<std::string>(db_path / "rx_frontends"
- / _rx_fe_map[i].db_fe_name / "antenna"
- / "value")
- .add_desired_subscriber(boost::bind(
- &x300_radio_ctrl_impl::_update_atr_leds, this, _1, i));
- _update_atr_leds(_tree
- ->access<std::string>(db_path / "rx_frontends"
- / _rx_fe_map[i].db_fe_name
- / "antenna" / "value")
- .get(),
- i);
- } else {
- _update_atr_leds("", i); // init anyway, even if never called
- }
- }
- }
-
- // bind frontend corrections to the dboard freq props
- const fs_path db_tx_fe_path = db_path / "tx_frontends";
- if (not _tx_fe_map.empty()) {
- for (size_t i = 0; i < _get_num_radios(); i++) {
- if (_tree->exists(
- db_tx_fe_path / _tx_fe_map[i].db_fe_name / "freq" / "value")) {
- _tree
- ->access<double>(
- db_tx_fe_path / _tx_fe_map[i].db_fe_name / "freq" / "value")
- .add_coerced_subscriber(
- boost::bind(&x300_radio_ctrl_impl::set_tx_fe_corrections,
- this,
- db_path,
- _root_path / "tx_fe_corrections" / _tx_fe_map[i].db_fe_name,
- _1));
- }
- }
- }
- const fs_path db_rx_fe_path = db_path / "rx_frontends";
- if (not _rx_fe_map.empty()) {
- for (size_t i = 0; i < _get_num_radios(); i++) {
- if (_tree->exists(
- db_rx_fe_path / _tx_fe_map[i].db_fe_name / "freq" / "value")) {
- _tree
- ->access<double>(
- db_rx_fe_path / _tx_fe_map[i].db_fe_name / "freq" / "value")
- .add_coerced_subscriber(
- boost::bind(&x300_radio_ctrl_impl::set_rx_fe_corrections,
- this,
- db_path,
- _root_path / "rx_fe_corrections" / _tx_fe_map[i].db_fe_name,
- _1));
- }
- }
- }
-
- ////////////////////////////////////////////////////////////////
- // Set tick rate
- ////////////////////////////////////////////////////////////////
- const double tick_rate = _tree->access<double>("tick_rate").get();
- radio_ctrl_impl::set_rate(tick_rate);
-
- ////////////////////////////////////////////////////////////////
- // Set gain groups
- // Note: The actual gain control comes from the daughterboard drivers, thus,
- // we need to call into the prop tree at the appropriate location in order
- // to modify the gains.
- ////////////////////////////////////////////////////////////////
- // TX
- for (size_t chan = 0; chan < _num_tx_channels; chan++) {
- fs_path rf_gains_path(db_tx_fe_path / _tx_fe_map.at(chan).db_fe_name / "gains");
- if (!_tree->exists(rf_gains_path)) {
- continue;
- }
-
- std::vector<std::string> gain_stages = _tree->list(rf_gains_path);
- if (gain_stages.empty()) {
- continue;
- }
-
- // DAC does not have a gain path
- auto gg = gain_group::make();
- for (const auto& name : gain_stages) {
- gg->register_fcns(name,
- make_gain_fcns_from_subtree(_tree->subtree(rf_gains_path / name)),
- 1 /* high prio */);
- }
- _tx_gain_groups[chan] = gg;
- }
- // RX
- for (size_t chan = 0; chan < _num_rx_channels; chan++) {
- fs_path rf_gains_path(db_rx_fe_path / _rx_fe_map.at(chan).db_fe_name / "gains");
- fs_path adc_gains_path("rx_codecs" / _radio_slot / "gains");
-
- auto gg = gain_group::make();
- // ADC also has a gain path
- for (const auto& name : _tree->list(adc_gains_path)) {
- gg->register_fcns("ADC-" + name,
- make_gain_fcns_from_subtree(_tree->subtree(adc_gains_path / name)),
- 0 /* low prio */);
- }
- if (_tree->exists(rf_gains_path)) {
- for (const auto& name : _tree->list(rf_gains_path)) {
- gg->register_fcns(name,
- make_gain_fcns_from_subtree(_tree->subtree(rf_gains_path / name)),
- 1 /* high prio */);
- }
- }
- _rx_gain_groups[chan] = gg;
- }
-}
-
-void x300_radio_ctrl_impl::set_rx_fe_corrections(
- const fs_path& db_path, const fs_path& rx_fe_corr_path, const double lo_freq)
-{
- if (not _ignore_cal_file) {
- apply_rx_fe_corrections(_tree, db_path, rx_fe_corr_path, lo_freq);
- }
-}
-
-void x300_radio_ctrl_impl::set_tx_fe_corrections(
- const fs_path& db_path, const fs_path& tx_fe_corr_path, const double lo_freq)
-{
- if (not _ignore_cal_file) {
- apply_tx_fe_corrections(_tree, db_path, tx_fe_corr_path, lo_freq);
- }
-}
-
-void x300_radio_ctrl_impl::reset_codec()
-{
- if (_radio_type == PRIMARY) { // ADC/DAC reset lines only exist in Radio0
- _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::ADC_RESET, 1);
- _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::DAC_RESET_N, 0);
- _regs->misc_outs_reg.flush();
- _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::ADC_RESET, 0);
- _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::DAC_RESET_N, 1);
- _regs->misc_outs_reg.flush();
- }
- UHD_ASSERT_THROW(bool(_adc));
- UHD_ASSERT_THROW(bool(_dac));
- _adc->reset();
- _dac->reset();
-}
-
-void x300_radio_ctrl_impl::self_test_adc(uint32_t ramp_time_ms)
-{
- // Bypass all front-end corrections
- for (size_t i = 0; i < _get_num_radios(); i++) {
- _rx_fe_map[i].core->bypass_all(true);
- }
-
- // Test basic patterns
- _adc->set_test_word("ones", "ones");
- _check_adc(0xfffcfffc);
- _adc->set_test_word("zeros", "zeros");
- _check_adc(0x00000000);
- _adc->set_test_word("ones", "zeros");
- _check_adc(0xfffc0000);
- _adc->set_test_word("zeros", "ones");
- _check_adc(0x0000fffc);
- for (size_t k = 0; k < 14; k++) {
- _adc->set_test_word("zeros", "custom", 1 << k);
- _check_adc(1 << (k + 2));
- }
- for (size_t k = 0; k < 14; k++) {
- _adc->set_test_word("custom", "zeros", 1 << k);
- _check_adc(1 << (k + 18));
- }
-
- // Turn on ramp pattern test
- _adc->set_test_word("ramp", "ramp");
- _regs->misc_outs_reg.write(radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 0);
- // Sleep added for SPI transactions to finish and ramp to start before checker is
- // enabled.
- std::this_thread::sleep_for(std::chrono::microseconds(1000));
- _regs->misc_outs_reg.write(radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 1);
-
- std::this_thread::sleep_for(std::chrono::milliseconds(ramp_time_ms));
- _regs->misc_ins_reg.refresh();
-
- std::string i_status, q_status;
- if (_regs->misc_ins_reg.get(radio_regmap_t::misc_ins_reg_t::ADC_CHECKER1_I_LOCKED))
- if (_regs->misc_ins_reg.get(radio_regmap_t::misc_ins_reg_t::ADC_CHECKER1_I_ERROR))
- i_status = "Bit Errors!";
- else
- i_status = "Good";
- else
- i_status = "Not Locked!";
-
- if (_regs->misc_ins_reg.get(radio_regmap_t::misc_ins_reg_t::ADC_CHECKER1_Q_LOCKED))
- if (_regs->misc_ins_reg.get(radio_regmap_t::misc_ins_reg_t::ADC_CHECKER1_Q_ERROR))
- q_status = "Bit Errors!";
- else
- q_status = "Good";
- else
- q_status = "Not Locked!";
-
- // Return to normal mode
- _adc->set_test_word("normal", "normal");
-
- if ((i_status != "Good") or (q_status != "Good")) {
- throw uhd::runtime_error(
- (boost::format(
- "ADC self-test failed for %s. Ramp checker status: {ADC_A=%s, ADC_B=%s}")
- % unique_id() % i_status % q_status)
- .str());
- }
-
- // Restore front-end corrections
- for (size_t i = 0; i < _get_num_radios(); i++) {
- _rx_fe_map[i].core->bypass_all(false);
- }
-}
-
-void x300_radio_ctrl_impl::extended_adc_test(
- const std::vector<x300_radio_ctrl_impl::sptr>& radios, double duration_s)
-{
- static const size_t SECS_PER_ITER = 5;
- UHD_LOGGER_INFO("X300 RADIO")
- << boost::format(
- "Running Extended ADC Self-Test (Duration=%.0fs, %ds/iteration)...")
- % duration_s % SECS_PER_ITER;
-
- size_t num_iters = static_cast<size_t>(ceil(duration_s / SECS_PER_ITER));
- size_t num_failures = 0;
- for (size_t iter = 0; iter < num_iters; iter++) {
- // Run self-test
- UHD_LOGGER_INFO("X300 RADIO")
- << boost::format("Extended ADC Self-Test Iteration %06d... ") % (iter + 1);
- try {
- for (size_t i = 0; i < radios.size(); i++) {
- radios[i]->self_test_adc((SECS_PER_ITER * 1000) / radios.size());
- }
- UHD_LOGGER_INFO("X300 RADIO")
- << boost::format("Extended ADC Self-Test Iteration %06d passed ")
- % (iter + 1);
- } catch (std::exception& e) {
- num_failures++;
- UHD_LOGGER_ERROR("X300 RADIO") << e.what();
- }
- }
- if (num_failures == 0) {
- UHD_LOGGER_INFO("X300 RADIO") << "Extended ADC Self-Test PASSED";
- } else {
- throw uhd::runtime_error(
- (boost::format("Extended ADC Self-Test FAILED!!! (%d/%d failures)\n")
- % num_failures % num_iters)
- .str());
- }
-}
-
-void x300_radio_ctrl_impl::synchronize_dacs(
- const std::vector<x300_radio_ctrl_impl::sptr>& radios)
-{
- if (radios.size() < 2)
- return; // Nothing to synchronize
-
- //**PRECONDITION**
- // This function assumes that all the VITA times in "radios" are synchronized
- // to a common reference. Currently, this function is called in get_tx_stream
- // which also has the same precondition.
-
- // Get a rough estimate of the cumulative command latency
- boost::posix_time::ptime t_start = boost::posix_time::microsec_clock::local_time();
- for (size_t i = 0; i < radios.size(); i++) {
- radios[i]->user_reg_read64(
- regs::RB_TIME_NOW); // Discard value. We are just timing the call
- }
- boost::posix_time::time_duration t_elapsed =
- boost::posix_time::microsec_clock::local_time() - t_start;
-
- // Add 100% of headroom + uncertainty to the command time
- uint64_t t_sync_us =
- (t_elapsed.total_microseconds() * 2) + 16000 /*Scheduler latency*/;
-
- std::string err_str;
- // Try to sync 3 times before giving up
- for (size_t attempt = 0; attempt < 3; attempt++) {
- try {
- // Reinitialize and resync all DACs
- for (size_t i = 0; i < radios.size(); i++) {
- radios[i]->_dac->sync();
- }
-
- // Set tick rate and make sure FRAMEP/N is 0
- for (size_t i = 0; i < radios.size(); i++) {
- radios[i]->set_command_tick_rate(
- radios[i]->_radio_clk_rate, IO_MASTER_RADIO);
- radios[i]->_regs->misc_outs_reg.write(
- radio_regmap_t::misc_outs_reg_t::DAC_SYNC, 0);
- }
-
- // Pick radios[0] as the time reference.
- uhd::time_spec_t sync_time = radios[0]->_time64->get_time_now()
- + uhd::time_spec_t(((double)t_sync_us) / 1e6);
-
- // Send the sync command
- for (size_t i = 0; i < radios.size(); i++) {
- radios[i]->set_command_time(sync_time, IO_MASTER_RADIO);
- // Arm FRAMEP/N sync pulse by asserting a rising edge
- radios[i]->_regs->misc_outs_reg.write(
- radio_regmap_t::misc_outs_reg_t::DAC_SYNC, 1);
- }
-
- // Reset FRAMEP/N to 0 after 2 clock cycles
- for (size_t i = 0; i < radios.size(); i++) {
- radios[i]->set_command_time(
- sync_time + (2.0 / radios[i]->_radio_clk_rate), IO_MASTER_RADIO);
- radios[i]->_regs->misc_outs_reg.write(
- radio_regmap_t::misc_outs_reg_t::DAC_SYNC, 0);
- radios[i]->set_command_time(uhd::time_spec_t(0.0), IO_MASTER_RADIO);
- }
-
- // Wait and check status
- std::this_thread::sleep_for(std::chrono::microseconds(t_sync_us));
- for (size_t i = 0; i < radios.size(); i++) {
- radios[i]->_dac->verify_sync();
- }
-
- return;
- } catch (const uhd::runtime_error& e) {
- err_str = e.what();
- UHD_LOGGER_TRACE("X300 RADIO") << "Retrying DAC synchronization: " << err_str;
- }
- }
- throw uhd::runtime_error(err_str);
-}
-
-double x300_radio_ctrl_impl::self_cal_adc_xfer_delay(
- const std::vector<x300_radio_ctrl_impl::sptr>& radios,
- x300_clock_ctrl::sptr clock,
- boost::function<void(double)> wait_for_clk_locked,
- bool apply_delay)
-{
- UHD_LOGGER_INFO("X300 RADIO") << "Running ADC transfer delay self-cal: ";
-
- // Effective resolution of the self-cal.
- static const size_t NUM_DELAY_STEPS = 100;
-
- double master_clk_period = (1.0e9 / clock->get_master_clock_rate()); // in ns
- double delay_start = 0.0;
- double delay_range = 2 * master_clk_period;
- double delay_incr = delay_range / NUM_DELAY_STEPS;
-
- double cached_clk_delay = clock->get_clock_delay(X300_CLOCK_WHICH_ADC0);
- double fpga_clk_delay = clock->get_clock_delay(X300_CLOCK_WHICH_FPGA);
-
- // Iterate through several values of delays and measure ADC data integrity
- std::vector<std::pair<double, bool>> results;
- for (size_t i = 0; i < NUM_DELAY_STEPS; i++) {
- // Delay the ADC clock (will set both Ch0 and Ch1 delays)
- double delay =
- clock->set_clock_delay(X300_CLOCK_WHICH_ADC0, delay_incr * i + delay_start);
- wait_for_clk_locked(0.1);
-
- uint32_t err_code = 0;
- for (size_t r = 0; r < radios.size(); r++) {
- // Test each channel (I and Q) individually so as to not accidentally trigger
- // on the data from the other channel if there is a swap
-
- // -- Test I Channel --
- // Put ADC in ramp test mode. Tie the other channel to all ones.
- radios[r]->_adc->set_test_word("ramp", "ones");
- // Turn on the pattern checker in the FPGA. It will lock when it sees a zero
- // and count deviations from the expected value
- radios[r]->_regs->misc_outs_reg.write(
- radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 0);
- radios[r]->_regs->misc_outs_reg.write(
- radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 1);
- // 50ms @ 200MHz = 10 million samples
- std::this_thread::sleep_for(std::chrono::milliseconds(50));
- if (radios[r]->_regs->misc_ins_reg.read(
- radio_regmap_t::misc_ins_reg_t::ADC_CHECKER1_I_LOCKED)) {
- err_code += radios[r]->_regs->misc_ins_reg.get(
- radio_regmap_t::misc_ins_reg_t::ADC_CHECKER1_I_ERROR);
- } else {
- err_code += 100; // Increment error code by 100 to indicate no lock
- }
-
- // -- Test Q Channel --
- // Put ADC in ramp test mode. Tie the other channel to all ones.
- radios[r]->_adc->set_test_word("ones", "ramp");
- // Turn on the pattern checker in the FPGA. It will lock when it sees a zero
- // and count deviations from the expected value
- radios[r]->_regs->misc_outs_reg.write(
- radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 0);
- radios[r]->_regs->misc_outs_reg.write(
- radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 1);
- // 50ms @ 200MHz = 10 million samples
- std::this_thread::sleep_for(std::chrono::milliseconds(50));
- if (radios[r]->_regs->misc_ins_reg.read(
- radio_regmap_t::misc_ins_reg_t::ADC_CHECKER1_Q_LOCKED)) {
- err_code += radios[r]->_regs->misc_ins_reg.get(
- radio_regmap_t::misc_ins_reg_t::ADC_CHECKER1_Q_ERROR);
- } else {
- err_code += 100; // Increment error code by 100 to indicate no lock
- }
- }
- // UHD_LOGGER_INFO("X300 RADIO") << (boost::format("XferDelay=%fns, Error=%d") %
- // delay % err_code);
- results.push_back(std::pair<double, bool>(delay, err_code == 0));
- }
-
- // Calculate the valid window
- int win_start_idx = -1, win_stop_idx = -1, cur_start_idx = -1, cur_stop_idx = -1;
- for (size_t i = 0; i < results.size(); i++) {
- std::pair<double, bool>& item = results[i];
- if (item.second) { // If data is stable
- if (cur_start_idx == -1) { // This is the first window
- cur_start_idx = i;
- cur_stop_idx = i;
- } else { // We are extending the window
- cur_stop_idx = i;
- }
- } else {
- if (cur_start_idx == -1) { // We haven't yet seen valid data
- // Do nothing
- } else if (win_start_idx == -1) { // We passed the first valid window
- win_start_idx = cur_start_idx;
- win_stop_idx = cur_stop_idx;
- } else { // Update cached window if current window is larger
- double cur_win_len =
- results[cur_stop_idx].first - results[cur_start_idx].first;
- double cached_win_len =
- results[win_stop_idx].first - results[win_start_idx].first;
- if (cur_win_len > cached_win_len) {
- win_start_idx = cur_start_idx;
- win_stop_idx = cur_stop_idx;
- }
- }
- // Reset current window
- cur_start_idx = -1;
- cur_stop_idx = -1;
- }
- }
- if (win_start_idx == -1) {
- throw uhd::runtime_error(
- "self_cal_adc_xfer_delay: Self calibration failed. Convergence error.");
- }
-
- double win_center =
- (results[win_stop_idx].first + results[win_start_idx].first) / 2.0;
- double win_length = results[win_stop_idx].first - results[win_start_idx].first;
- if (win_length < master_clk_period / 4) {
- throw uhd::runtime_error(
- "self_cal_adc_xfer_delay: Self calibration failed. Valid window too narrow.");
- }
-
- // Cycle slip the relative delay by a clock cycle to prevent sample misalignment
- // fpga_clk_delay > 0 and 0 < win_center < 2*(1/MCR) so one cycle slip is all we need
- bool cycle_slip = (win_center - fpga_clk_delay >= master_clk_period);
- if (cycle_slip) {
- win_center -= master_clk_period;
- }
-
- if (apply_delay) {
- // Apply delay
- win_center = clock->set_clock_delay(
- X300_CLOCK_WHICH_ADC0, win_center); // Sets ADC0 and ADC1
- wait_for_clk_locked(0.1);
- // Validate
- for (size_t r = 0; r < radios.size(); r++) {
- radios[r]->self_test_adc(2000);
- }
- } else {
- // Restore delay
- clock->set_clock_delay(
- X300_CLOCK_WHICH_ADC0, cached_clk_delay); // Sets ADC0 and ADC1
- }
-
- // Teardown
- for (size_t r = 0; r < radios.size(); r++) {
- radios[r]->_adc->set_test_word("normal", "normal");
- radios[r]->_regs->misc_outs_reg.write(
- radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 0);
- }
- UHD_LOGGER_INFO("X300 RADIO")
- << (boost::format(
- "ADC transfer delay self-cal done (FPGA->ADC=%.3fns%s, Window=%.3fns)")
- % (win_center - fpga_clk_delay) % (cycle_slip ? " +cyc" : "")
- % win_length);
-
- return win_center;
-}
-/****************************************************************************
- * Helpers
- ***************************************************************************/
-void x300_radio_ctrl_impl::_update_atr_leds(const std::string& rx_ant, const size_t chan)
-{
- // The "RX1" port is used by TwinRX and the "TX/RX" port is used by all
- // other full-duplex dboards. We need to handle both here.
- const bool is_txrx = (rx_ant == "TX/RX" or rx_ant == "RX1");
- const int TXRX_RX = (1 << 0);
- const int TXRX_TX = (1 << 1);
- const int RX2_RX = (1 << 2);
- _leds.at(chan)->set_atr_reg(gpio_atr::ATR_REG_IDLE, 0);
- _leds.at(chan)->set_atr_reg(gpio_atr::ATR_REG_RX_ONLY, is_txrx ? TXRX_RX : RX2_RX);
- _leds.at(chan)->set_atr_reg(gpio_atr::ATR_REG_TX_ONLY, TXRX_TX);
- _leds.at(chan)->set_atr_reg(gpio_atr::ATR_REG_FULL_DUPLEX, RX2_RX | TXRX_TX);
-}
-
-void x300_radio_ctrl_impl::_self_cal_adc_capture_delay(bool print_status)
-{
- if (print_status)
- UHD_LOGGER_INFO("X300 RADIO") << "Running ADC capture delay self-cal...";
-
- static const uint32_t NUM_DELAY_STEPS = 32; // The IDELAYE2 element has 32 steps
- static const uint32_t NUM_RETRIES =
- 2; // Retry self-cal if it fails in warmup situations
- static const int32_t MIN_WINDOW_LEN = 4;
-
- int32_t win_start = -1, win_stop = -1;
- uint32_t iter = 0;
- while (iter++ < NUM_RETRIES) {
- for (uint32_t dly_tap = 0; dly_tap < NUM_DELAY_STEPS; dly_tap++) {
- // Apply delay
- _regs->misc_outs_reg.write(
- radio_regmap_t::misc_outs_reg_t::ADC_DATA_DLY_VAL, dly_tap);
- _regs->misc_outs_reg.write(
- radio_regmap_t::misc_outs_reg_t::ADC_DATA_DLY_STB, 1);
- _regs->misc_outs_reg.write(
- radio_regmap_t::misc_outs_reg_t::ADC_DATA_DLY_STB, 0);
-
- uint32_t err_code = 0;
-
- // -- Test I Channel --
- // Put ADC in ramp test mode. Tie the other channel to all ones.
- _adc->set_test_word("ramp", "ones");
- // Turn on the pattern checker in the FPGA. It will lock when it sees a zero
- // and count deviations from the expected value
- _regs->misc_outs_reg.write(
- radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 0);
- _regs->misc_outs_reg.write(
- radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 1);
- // 5ms @ 200MHz = 1 million samples
- std::this_thread::sleep_for(std::chrono::milliseconds(5));
- if (_regs->misc_ins_reg.read(
- radio_regmap_t::misc_ins_reg_t::ADC_CHECKER0_I_LOCKED)) {
- err_code += _regs->misc_ins_reg.get(
- radio_regmap_t::misc_ins_reg_t::ADC_CHECKER0_I_ERROR);
- } else {
- err_code += 100; // Increment error code by 100 to indicate no lock
- }
-
- // -- Test Q Channel --
- // Put ADC in ramp test mode. Tie the other channel to all ones.
- _adc->set_test_word("ones", "ramp");
- // Turn on the pattern checker in the FPGA. It will lock when it sees a zero
- // and count deviations from the expected value
- _regs->misc_outs_reg.write(
- radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 0);
- _regs->misc_outs_reg.write(
- radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 1);
- // 5ms @ 200MHz = 1 million samples
- std::this_thread::sleep_for(std::chrono::milliseconds(5));
- if (_regs->misc_ins_reg.read(
- radio_regmap_t::misc_ins_reg_t::ADC_CHECKER0_Q_LOCKED)) {
- err_code += _regs->misc_ins_reg.get(
- radio_regmap_t::misc_ins_reg_t::ADC_CHECKER0_Q_ERROR);
- } else {
- err_code += 100; // Increment error code by 100 to indicate no lock
- }
-
- if (err_code == 0) {
- if (win_start == -1) { // This is the first window
- win_start = dly_tap;
- win_stop = dly_tap;
- } else { // We are extending the window
- win_stop = dly_tap;
- }
- } else {
- if (win_start != -1) { // A valid window turned invalid
- if (win_stop - win_start >= MIN_WINDOW_LEN) {
- break; // Valid window found
- } else {
- win_start = -1; // Reset window
- }
- }
- }
- // UHD_LOGGER_INFO("X300 RADIO") << (boost::format("CapTap=%d, Error=%d") %
- // dly_tap % err_code);
- }
-
- // Retry the self-cal if it fails
- if ((win_start == -1 || (win_stop - win_start) < MIN_WINDOW_LEN)
- && iter < NUM_RETRIES /*not last iteration*/) {
- win_start = -1;
- win_stop = -1;
- std::this_thread::sleep_for(std::chrono::milliseconds(2000));
- } else {
- break;
- }
- }
- _adc->set_test_word("normal", "normal");
- _regs->misc_outs_reg.write(radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 0);
-
- if (win_start == -1) {
- throw uhd::runtime_error(
- "self_cal_adc_capture_delay: Self calibration failed. Convergence error.");
- }
-
- if (win_stop - win_start < MIN_WINDOW_LEN) {
- throw uhd::runtime_error("self_cal_adc_capture_delay: Self calibration failed. "
- "Valid window too narrow.");
- }
-
- uint32_t ideal_tap = (win_stop + win_start) / 2;
- _regs->misc_outs_reg.write(
- radio_regmap_t::misc_outs_reg_t::ADC_DATA_DLY_VAL, ideal_tap);
- _regs->misc_outs_reg.write(radio_regmap_t::misc_outs_reg_t::ADC_DATA_DLY_STB, 1);
- _regs->misc_outs_reg.write(radio_regmap_t::misc_outs_reg_t::ADC_DATA_DLY_STB, 0);
-
- if (print_status) {
- double tap_delay = (1.0e12 / _radio_clk_rate) / (2 * 32); // in ps
- UHD_LOGGER_INFO("X300 RADIO")
- << boost::format("ADC capture delay self-cal done (Tap=%d, Window=%d, "
- "TapDelay=%.3fps, Iter=%d)")
- % ideal_tap % (win_stop - win_start) % tap_delay % iter;
- }
-}
-
-void x300_radio_ctrl_impl::_check_adc(const uint32_t val)
-{
- // Wait for previous control transaction to flush
- user_reg_read64(regs::RB_TEST);
- // Wait for ADC test pattern to propagate
- std::this_thread::sleep_for(std::chrono::microseconds(5));
- // Read value of RX readback register and verify
- uint32_t adc_rb = static_cast<uint32_t>(user_reg_read64(regs::RB_TEST) >> 32);
- adc_rb ^= 0xfffc0000; // adapt for I inversion in FPGA
- if (val != adc_rb) {
- throw uhd::runtime_error(
- (boost::format("ADC self-test failed for %s. (Exp=0x%x, Got=0x%x)")
- % unique_id() % val % adc_rb)
- .str());
- }
-}
-
-void x300_radio_ctrl_impl::_set_db_eeprom(
- i2c_iface::sptr i2c, const size_t addr, const uhd::usrp::dboard_eeprom_t& db_eeprom)
-{
- db_eeprom.store(*i2c, addr);
- _db_eeproms[addr] = db_eeprom;
-}
-
-void x300_radio_ctrl_impl::_set_command_time(const time_spec_t& spec, const size_t port)
-{
- set_fe_cmd_time(spec, port);
-}
-/****************************************************************************
- * Helpers
- ***************************************************************************/
-bool x300_radio_ctrl_impl::check_radio_config()
-{
- UHD_RFNOC_BLOCK_TRACE() << "x300_radio_ctrl_impl::check_radio_config() ";
- const fs_path rx_fe_path = fs_path("dboards" / _radio_slot / "rx_frontends");
- for (size_t chan = 0; chan < _num_rx_channels; chan++) {
- if (_tree->exists(rx_fe_path / _rx_fe_map.at(chan).db_fe_name / "enabled")) {
- const bool chan_active = _is_streamer_active(uhd::RX_DIRECTION, chan);
- if (chan_active) {
- _tree
- ->access<bool>(
- rx_fe_path / _rx_fe_map.at(chan).db_fe_name / "enabled")
- .set(chan_active);
- }
- }
- }
-
- const fs_path tx_fe_path = fs_path("dboards" / _radio_slot / "tx_frontends");
- for (size_t chan = 0; chan < _num_tx_channels; chan++) {
- if (_tree->exists(tx_fe_path / _tx_fe_map.at(chan).db_fe_name / "enabled")) {
- const bool chan_active = _is_streamer_active(uhd::TX_DIRECTION, chan);
- if (chan_active) {
- _tree
- ->access<bool>(
- tx_fe_path / _tx_fe_map.at(chan).db_fe_name / "enabled")
- .set(chan_active);
- }
- }
- }
-
- return true;
-}
-
-/****************************************************************************
- * Register block
- ***************************************************************************/
-UHD_RFNOC_BLOCK_REGISTER(x300_radio_ctrl, "X300Radio");
diff --git a/host/lib/usrp/x300/x300_radio_ctrl_impl.hpp b/host/lib/usrp/x300/x300_radio_ctrl_impl.hpp
deleted file mode 100644
index 63aac876d..000000000
--- a/host/lib/usrp/x300/x300_radio_ctrl_impl.hpp
+++ /dev/null
@@ -1,246 +0,0 @@
-//
-// Copyright 2015-2016 Ettus Research
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#ifndef INCLUDED_LIBUHD_RFNOC_X300_RADIO_CTRL_IMPL_HPP
-#define INCLUDED_LIBUHD_RFNOC_X300_RADIO_CTRL_IMPL_HPP
-
-#include "x300_adc_ctrl.hpp"
-#include "x300_clock_ctrl.hpp"
-#include "x300_dac_ctrl.hpp"
-#include "x300_regs.hpp"
-#include <uhd/usrp/dboard_eeprom.hpp>
-#include <uhd/usrp/dboard_manager.hpp>
-#include <uhd/usrp/gpio_defs.hpp>
-#include <uhd/utils/gain_group.hpp>
-#include <uhdlib/rfnoc/radio_ctrl_impl.hpp>
-#include <uhdlib/usrp/cores/rx_frontend_core_3000.hpp>
-#include <uhdlib/usrp/cores/spi_core_3000.hpp>
-#include <uhdlib/usrp/cores/tx_frontend_core_200.hpp>
-#include <unordered_map>
-
-namespace uhd { namespace rfnoc {
-
-/*! \brief Provide access to an X300 radio.
- */
-class x300_radio_ctrl_impl : public radio_ctrl_impl
-{
-public:
- typedef boost::shared_ptr<x300_radio_ctrl_impl> sptr;
-
- /************************************************************************
- * Structors
- ***********************************************************************/
- UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR_DECL(x300_radio_ctrl)
- virtual ~x300_radio_ctrl_impl();
-
- /************************************************************************
- * API calls
- ***********************************************************************/
- double set_rate(double rate);
-
- void set_tx_antenna(const std::string& ant, const size_t chan);
- void set_rx_antenna(const std::string& ant, const size_t chan);
- std::string get_tx_antenna(const size_t chan);
- std::string get_rx_antenna(const size_t chan);
-
- double set_tx_frequency(const double freq, const size_t chan);
- double set_rx_frequency(const double freq, const size_t chan);
- double set_rx_bandwidth(const double bandwidth, const size_t chan);
- double get_tx_frequency(const size_t chan);
- double get_rx_frequency(const size_t chan);
- double get_rx_bandwidth(const size_t chan);
-
- double set_tx_gain(const double gain, const size_t chan);
- double set_rx_gain(const double gain, const size_t chan);
- double get_rx_gain(const size_t chan);
-
- std::vector<std::string> get_rx_lo_names(const size_t chan);
- std::vector<std::string> get_rx_lo_sources(
- const std::string& name, const size_t chan);
- freq_range_t get_rx_lo_freq_range(const std::string& name, const size_t chan);
-
- void set_rx_lo_source(
- const std::string& src, const std::string& name, const size_t chan);
- const std::string get_rx_lo_source(const std::string& name, const size_t chan);
-
- void set_rx_lo_export_enabled(
- bool enabled, const std::string& name, const size_t chan);
- bool get_rx_lo_export_enabled(const std::string& name, const size_t chan);
-
- double set_rx_lo_freq(double freq, const std::string& name, const size_t chan);
- double get_rx_lo_freq(const std::string& name, const size_t chan);
-
- size_t get_chan_from_dboard_fe(const std::string& fe, const direction_t dir);
- std::string get_dboard_fe_from_chan(const size_t chan, const direction_t dir);
-
- std::vector<std::string> get_gpio_banks() const;
- void set_gpio_attr(const std::string& bank,
- const std::string& attr,
- const uint32_t value,
- const uint32_t mask);
- uint32_t get_gpio_attr(const std::string& bank, const std::string& attr);
-
- double get_output_samp_rate(size_t port);
-
- /************************************************************************
- * Hardware setup and control
- ***********************************************************************/
- /*! Set up the radio. No API calls may be made before this one.
- */
- void setup_radio(uhd::i2c_iface::sptr zpu_i2c,
- x300_clock_ctrl::sptr clock,
- bool ignore_cal_file,
- bool verbose);
-
- void reset_codec();
-
- void self_test_adc(uint32_t ramp_time_ms = 100);
-
- static void extended_adc_test(
- const std::vector<x300_radio_ctrl_impl::sptr>&, double duration_s);
-
- static void synchronize_dacs(const std::vector<x300_radio_ctrl_impl::sptr>& radios);
-
- static double self_cal_adc_xfer_delay(
- const std::vector<x300_radio_ctrl_impl::sptr>& radios,
- x300_clock_ctrl::sptr clock,
- boost::function<void(double)> wait_for_clk_locked,
- bool apply_delay);
-
-protected:
- virtual bool check_radio_config();
-
-private:
- class radio_regmap_t : public uhd::soft_regmap_t
- {
- public:
- typedef boost::shared_ptr<radio_regmap_t> sptr;
- class misc_outs_reg_t : public uhd::soft_reg32_wo_t
- {
- public:
- UHD_DEFINE_SOFT_REG_FIELD(DAC_ENABLED, /*width*/ 1, /*shift*/ 0); //[0]
- UHD_DEFINE_SOFT_REG_FIELD(DAC_RESET_N, /*width*/ 1, /*shift*/ 1); //[1]
- UHD_DEFINE_SOFT_REG_FIELD(ADC_RESET, /*width*/ 1, /*shift*/ 2); //[2]
- UHD_DEFINE_SOFT_REG_FIELD(ADC_DATA_DLY_STB, /*width*/ 1, /*shift*/ 3); //[3]
- UHD_DEFINE_SOFT_REG_FIELD(ADC_DATA_DLY_VAL, /*width*/ 5, /*shift*/ 4); //[8:4]
- UHD_DEFINE_SOFT_REG_FIELD(
- ADC_CHECKER_ENABLED, /*width*/ 1, /*shift*/ 9); //[9]
- UHD_DEFINE_SOFT_REG_FIELD(DAC_SYNC, /*width*/ 1, /*shift*/ 10); //[10]
-
- misc_outs_reg_t() : uhd::soft_reg32_wo_t(regs::sr_addr(regs::MISC_OUTS))
- {
- // Initial values
- set(DAC_ENABLED, 0);
- set(DAC_RESET_N, 0);
- set(ADC_RESET, 0);
- set(ADC_DATA_DLY_STB, 0);
- set(ADC_DATA_DLY_VAL, 16);
- set(ADC_CHECKER_ENABLED, 0);
- set(DAC_SYNC, 0);
- }
- } misc_outs_reg;
-
- class misc_ins_reg_t : public uhd::soft_reg64_ro_t
- {
- public:
- UHD_DEFINE_SOFT_REG_FIELD(
- ADC_CHECKER0_Q_LOCKED, /*width*/ 1, /*shift*/ 32); //[0]
- UHD_DEFINE_SOFT_REG_FIELD(
- ADC_CHECKER0_I_LOCKED, /*width*/ 1, /*shift*/ 33); //[1]
- UHD_DEFINE_SOFT_REG_FIELD(
- ADC_CHECKER1_Q_LOCKED, /*width*/ 1, /*shift*/ 34); //[2]
- UHD_DEFINE_SOFT_REG_FIELD(
- ADC_CHECKER1_I_LOCKED, /*width*/ 1, /*shift*/ 35); //[3]
- UHD_DEFINE_SOFT_REG_FIELD(
- ADC_CHECKER0_Q_ERROR, /*width*/ 1, /*shift*/ 36); //[4]
- UHD_DEFINE_SOFT_REG_FIELD(
- ADC_CHECKER0_I_ERROR, /*width*/ 1, /*shift*/ 37); //[5]
- UHD_DEFINE_SOFT_REG_FIELD(
- ADC_CHECKER1_Q_ERROR, /*width*/ 1, /*shift*/ 38); //[6]
- UHD_DEFINE_SOFT_REG_FIELD(
- ADC_CHECKER1_I_ERROR, /*width*/ 1, /*shift*/ 39); //[7]
-
- misc_ins_reg_t() : uhd::soft_reg64_ro_t(regs::rb_addr(regs::RB_MISC_IO)) {}
- } misc_ins_reg;
-
- radio_regmap_t(int radio_num)
- : soft_regmap_t("radio" + std::to_string(radio_num) + "_regmap")
- {
- add_to_map(misc_outs_reg, "misc_outs_reg", PRIVATE);
- add_to_map(misc_ins_reg, "misc_ins_reg", PRIVATE);
- }
- };
-
- struct x300_regs
- {
- static const uint32_t TX_FE_BASE = 224;
- static const uint32_t RX_FE_BASE = 232;
- };
-
- void _update_atr_leds(const std::string& rx_ant, const size_t chan);
-
- void _self_cal_adc_capture_delay(bool print_status);
-
- void _check_adc(const uint32_t val);
-
- void _set_db_eeprom(
- uhd::i2c_iface::sptr i2c, const size_t, const uhd::usrp::dboard_eeprom_t&);
-
- void set_rx_fe_corrections(const uhd::fs_path& db_path,
- const uhd::fs_path& rx_fe_corr_path,
- const double lo_freq);
- void set_tx_fe_corrections(const uhd::fs_path& db_path,
- const uhd::fs_path& tx_fe_corr_path,
- const double lo_freq);
-
- void _set_command_time(const uhd::time_spec_t& spec, const size_t port);
- void set_fe_cmd_time(const time_spec_t& time, const size_t chan);
-
-private: // members
- enum radio_connection_t { PRIMARY, SECONDARY };
-
- radio_connection_t _radio_type;
- std::string _radio_slot;
- //! Radio clock rate is the rate at which the ADC and DAC are running at.
- // Not necessarily this block's sampling rate (tick rate).
- double _radio_clk_rate;
-
- radio_regmap_t::sptr _regs;
- std::map<size_t, usrp::gpio_atr::gpio_atr_3000::sptr> _leds;
- spi_core_3000::sptr _spi;
- x300_adc_ctrl::sptr _adc;
- x300_dac_ctrl::sptr _dac;
- usrp::gpio_atr::gpio_atr_3000::sptr _fp_gpio;
-
- std::map<size_t, usrp::dboard_eeprom_t> _db_eeproms;
- usrp::dboard_manager::sptr _db_manager;
-
- struct rx_fe_perif
- {
- std::string name;
- std::string db_fe_name;
- rx_frontend_core_3000::sptr core;
- };
- struct tx_fe_perif
- {
- std::string name;
- std::string db_fe_name;
- tx_frontend_core_200::sptr core;
- };
-
- std::map<size_t, rx_fe_perif> _rx_fe_map;
- std::map<size_t, tx_fe_perif> _tx_fe_map;
-
- bool _ignore_cal_file;
-
- std::unordered_map<size_t, uhd::gain_group::sptr> _tx_gain_groups;
- std::unordered_map<size_t, uhd::gain_group::sptr> _rx_gain_groups;
-}; /* class radio_ctrl_impl */
-
-}} /* namespace uhd::rfnoc */
-
-#endif /* INCLUDED_LIBUHD_RFNOC_X300_RADIO_CTRL_IMPL_HPP */