aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/dboard/magnesium
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp/dboard/magnesium')
-rw-r--r--host/lib/usrp/dboard/magnesium/CMakeLists.txt8
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_bands.cpp11
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_constants.hpp23
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_gain_table.cpp8
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_gain_table.hpp6
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_radio_control.cpp1151
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_radio_control.hpp (renamed from host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.hpp)136
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_radio_control_cpld.cpp (renamed from host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_cpld.cpp)34
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_radio_control_gain.cpp (renamed from host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_gain.cpp)68
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_radio_control_init.cpp446
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.cpp847
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_init.cpp713
12 files changed, 1780 insertions, 1671 deletions
diff --git a/host/lib/usrp/dboard/magnesium/CMakeLists.txt b/host/lib/usrp/dboard/magnesium/CMakeLists.txt
index 1029bfacd..df5fe765a 100644
--- a/host/lib/usrp/dboard/magnesium/CMakeLists.txt
+++ b/host/lib/usrp/dboard/magnesium/CMakeLists.txt
@@ -8,10 +8,10 @@
# set to true.
list(APPEND MAGNESIUM_SOURCES
- ${CMAKE_CURRENT_SOURCE_DIR}/magnesium_radio_ctrl_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/magnesium_radio_ctrl_init.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/magnesium_radio_ctrl_cpld.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/magnesium_radio_ctrl_gain.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/magnesium_radio_control.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/magnesium_radio_control_init.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/magnesium_radio_control_cpld.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/magnesium_radio_control_gain.cpp
${CMAKE_CURRENT_SOURCE_DIR}/magnesium_ad9371_iface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/magnesium_bands.cpp
${CMAKE_CURRENT_SOURCE_DIR}/magnesium_cpld_ctrl.cpp
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_bands.cpp b/host/lib/usrp/dboard/magnesium/magnesium_bands.cpp
index 13cc52d49..ef72aee95 100644
--- a/host/lib/usrp/dboard/magnesium/magnesium_bands.cpp
+++ b/host/lib/usrp/dboard/magnesium/magnesium_bands.cpp
@@ -7,7 +7,7 @@
// The band plan
#include "magnesium_constants.hpp"
-#include "magnesium_radio_ctrl_impl.hpp"
+#include "magnesium_radio_control.hpp"
#include <uhd/utils/math.hpp>
/*
@@ -93,11 +93,10 @@ namespace {
} // namespace
-
-magnesium_radio_ctrl_impl::rx_band magnesium_radio_ctrl_impl::_map_freq_to_rx_band(
+magnesium_radio_control_impl::rx_band magnesium_radio_control_impl::_map_freq_to_rx_band(
const band_map_t band_map, const double freq)
{
- magnesium_radio_ctrl_impl::rx_band band;
+ magnesium_radio_control_impl::rx_band band;
if (fp_compare_epsilon<double>(freq) < MAGNESIUM_MIN_FREQ) {
band = rx_band::INVALID_BAND;
@@ -124,10 +123,10 @@ magnesium_radio_ctrl_impl::rx_band magnesium_radio_ctrl_impl::_map_freq_to_rx_ba
return band;
}
-magnesium_radio_ctrl_impl::tx_band magnesium_radio_ctrl_impl::_map_freq_to_tx_band(
+magnesium_radio_control_impl::tx_band magnesium_radio_control_impl::_map_freq_to_tx_band(
const band_map_t band_map, const double freq)
{
- magnesium_radio_ctrl_impl::tx_band band;
+ magnesium_radio_control_impl::tx_band band;
if (fp_compare_epsilon<double>(freq) < MAGNESIUM_MIN_FREQ) {
band = tx_band::INVALID_BAND;
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_constants.hpp b/host/lib/usrp/dboard/magnesium/magnesium_constants.hpp
index 9b3bdf800..7d98bca91 100644
--- a/host/lib/usrp/dboard/magnesium/magnesium_constants.hpp
+++ b/host/lib/usrp/dboard/magnesium/magnesium_constants.hpp
@@ -69,6 +69,13 @@ static constexpr char MAGNESIUM_GAIN2[] = "dsa";
//! Amplifier gain
static constexpr char MAGNESIUM_AMP[] = "amp";
+static constexpr char MAGNESIUM_FE_NAME[] = "Magnesium";
+
+static constexpr char MAGNESIUM_DEFAULT_RX_ANTENNA[] = "RX2";
+static constexpr char MAGNESIUM_DEFAULT_TX_ANTENNA[] = "TX/RX";
+
+static constexpr char MAGNESIUM_FPGPIO_BANK[] = "FP0";
+
// Note: MAGNESIUM_NUM_CHANS is independent of the number of chans per
// RFNoC block. TODO: When we go to one radio per dboard, this comment can
// be deleted.
@@ -79,4 +86,20 @@ static constexpr double MAGNESIUM_TX_IF_FREQ = 1.95e9;
//! Max time we allow for a call to set_freq() to take
static constexpr size_t MAGNESIUM_TUNE_TIMEOUT = 15000; // milliseconds
+//! Magnesium gain profile options
+static const std::vector<std::string> MAGNESIUM_GP_OPTIONS = {"manual",
+ "default",
+ "default_rf_filter_bypass_always_on",
+ "default_rf_filter_bypass_always_off"};
+
+namespace n310_regs {
+
+constexpr uint32_t DB_GPIO_BASE = 0x80000; // FIXME
+constexpr uint32_t DB_GPIO_RB = 0x80000; // FIXME
+constexpr uint32_t DB_GPIO_OFFSET = 0x100; // FIXME
+constexpr uint32_t FP_GPIO = 0x80000; // FIXME
+constexpr uint32_t RB_FP_GPIO = 0x80000; // FIXME
+
+}
+
#endif /* INCLUDED_LIBUHD_MAGNESIUM_CONSTANTS_HPP */
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_gain_table.cpp b/host/lib/usrp/dboard/magnesium/magnesium_gain_table.cpp
index 67b20f5fa..3e513218a 100644
--- a/host/lib/usrp/dboard/magnesium/magnesium_gain_table.cpp
+++ b/host/lib/usrp/dboard/magnesium/magnesium_gain_table.cpp
@@ -15,8 +15,8 @@ using namespace uhd::rfnoc;
using namespace magnesium;
namespace {
-typedef magnesium_radio_ctrl_impl::rx_band rx_band;
-typedef magnesium_radio_ctrl_impl::tx_band tx_band;
+typedef magnesium_radio_control_impl::rx_band rx_band;
+typedef magnesium_radio_control_impl::tx_band tx_band;
const size_t TX_LOWBAND = 0;
const size_t TX_HIGHBAND = 1;
@@ -454,7 +454,7 @@ gain_tuple_t fine_tune_ad9371_att(const gain_tuple_t gain_tuple, const double ga
gain_tuple_t magnesium::get_rx_gain_tuple(
- const double gain_index, const magnesium_radio_ctrl_impl::rx_band band)
+ const double gain_index, const magnesium_radio_control_impl::rx_band band)
{
UHD_ASSERT_THROW(gain_index <= ALL_RX_MAX_GAIN and gain_index >= ALL_RX_MIN_GAIN);
auto& gain_table = rx_gain_tables.at(map_rx_band(band));
@@ -463,7 +463,7 @@ gain_tuple_t magnesium::get_rx_gain_tuple(
}
gain_tuple_t magnesium::get_tx_gain_tuple(
- const double gain_index, const magnesium_radio_ctrl_impl::tx_band band)
+ const double gain_index, const magnesium_radio_control_impl::tx_band band)
{
UHD_ASSERT_THROW(gain_index <= ALL_TX_MAX_GAIN and gain_index >= ALL_TX_MIN_GAIN);
auto& gain_table = tx_gain_tables.at(map_tx_band(band));
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_gain_table.hpp b/host/lib/usrp/dboard/magnesium/magnesium_gain_table.hpp
index 8769b44ac..6ba91a248 100644
--- a/host/lib/usrp/dboard/magnesium/magnesium_gain_table.hpp
+++ b/host/lib/usrp/dboard/magnesium/magnesium_gain_table.hpp
@@ -7,7 +7,7 @@
#ifndef INCLUDED_LIBUHD_MAGNESIUM_GAIN_TABLE_HPP
#define INCLUDED_LIBUHD_MAGNESIUM_GAIN_TABLE_HPP
-#include "magnesium_radio_ctrl_impl.hpp"
+#include "magnesium_radio_control.hpp"
#include <uhd/types/direction.hpp>
namespace magnesium {
@@ -31,12 +31,12 @@ struct gain_tuple_t
/*! Given a gain index, return a tuple of gain-related settings (Rx)
*/
gain_tuple_t get_rx_gain_tuple(
- const double gain_index, const uhd::rfnoc::magnesium_radio_ctrl_impl::rx_band band_);
+ const double gain_index, const uhd::rfnoc::magnesium_radio_control_impl::rx_band band_);
/*! Given a gain index, return a tuple of gain-related settings (Tx)
*/
gain_tuple_t get_tx_gain_tuple(
- const double gain_index, const uhd::rfnoc::magnesium_radio_ctrl_impl::tx_band band_);
+ const double gain_index, const uhd::rfnoc::magnesium_radio_control_impl::tx_band band_);
} /* namespace magnesium */
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_control.cpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_control.cpp
new file mode 100644
index 000000000..dc78cee7d
--- /dev/null
+++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_control.cpp
@@ -0,0 +1,1151 @@
+//
+// Copyright 2017 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#include "magnesium_radio_control.hpp"
+#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>
+#include <uhd/utils/log.hpp>
+#include <uhd/utils/math.hpp>
+#include <uhd/rfnoc/registry.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/format.hpp>
+#include <boost/make_shared.hpp>
+#include <cmath>
+#include <cstdlib>
+#include <sstream>
+
+using namespace uhd;
+using namespace uhd::usrp;
+using namespace uhd::rfnoc;
+using namespace uhd::math::fp_compare;
+
+namespace {
+
+/**************************************************************************
+ * ADF4351 Controls
+ *************************************************************************/
+/*!
+ * \param lo_iface Reference to the LO object
+ * \param freq Frequency (in Hz) of the tone to be generated from the LO
+ * \param ref_clock_freq Frequency (in Hz) of the reference clock at the
+ * PLL input of the LO
+ * \param int_n_mode Integer-N mode on or off
+ */
+double _lo_set_frequency(adf435x_iface::sptr lo_iface,
+ const double freq,
+ const double ref_clock_freq,
+ const bool int_n_mode)
+{
+ UHD_LOG_TRACE("MG/ADF4351",
+ "Attempting to tune low band LO to " << freq << " Hz with ref clock freq "
+ << ref_clock_freq);
+ lo_iface->set_feedback_select(adf435x_iface::FB_SEL_DIVIDED);
+ lo_iface->set_reference_freq(ref_clock_freq);
+ lo_iface->set_prescaler(adf435x_iface::PRESCALER_4_5);
+ const double actual_freq = lo_iface->set_frequency(freq, int_n_mode);
+ lo_iface->set_output_power(
+ adf435x_iface::RF_OUTPUT_A, adf435x_iface::OUTPUT_POWER_2DBM);
+ lo_iface->set_output_power(
+ adf435x_iface::RF_OUTPUT_B, adf435x_iface::OUTPUT_POWER_2DBM);
+ lo_iface->set_charge_pump_current(adf435x_iface::CHARGE_PUMP_CURRENT_0_31MA);
+ return actual_freq;
+}
+
+/*! Configure and enable LO
+ *
+ * Will tune it to requested frequency and enable outputs.
+ *
+ * \param lo_iface Reference to the LO object
+ * \param lo_freq Frequency (in Hz) of the tone to be generated from the LO
+ * \param ref_clock_freq Frequency (in Hz) of the reference clock at the
+ * PLL input of the LO
+ * \param int_n_mode Integer-N mode on or off
+ * \returns the actual frequency the LO is running at
+ */
+double _lo_enable(adf435x_iface::sptr lo_iface,
+ const double lo_freq,
+ const double ref_clock_freq,
+ const bool int_n_mode)
+{
+ const double actual_lo_freq =
+ _lo_set_frequency(lo_iface, lo_freq, ref_clock_freq, int_n_mode);
+ lo_iface->set_output_enable(adf435x_iface::RF_OUTPUT_A, true);
+ lo_iface->set_output_enable(adf435x_iface::RF_OUTPUT_B, true);
+ lo_iface->commit();
+ return actual_lo_freq;
+}
+
+/*! Disable LO
+ */
+void _lo_disable(adf435x_iface::sptr lo_iface)
+{
+ lo_iface->set_output_enable(adf435x_iface::RF_OUTPUT_A, false);
+ lo_iface->set_output_enable(adf435x_iface::RF_OUTPUT_B, false);
+ lo_iface->commit();
+}
+} // namespace
+
+
+/******************************************************************************
+ * Structors
+ *****************************************************************************/
+magnesium_radio_control_impl::magnesium_radio_control_impl(make_args_ptr make_args)
+ : radio_control_impl(std::move(make_args))
+{
+ RFNOC_LOG_TRACE("Entering magnesium_radio_control_impl ctor...");
+ UHD_ASSERT_THROW(get_block_id().get_block_count() < 2);
+ const char radio_slot_name[2] = {'A', 'B'};
+ _radio_slot = radio_slot_name[get_block_id().get_block_count()];
+ RFNOC_LOG_TRACE("Radio slot: " << _radio_slot);
+ _rpc_prefix = (_radio_slot == "A") ? "db_0_" : "db_1_";
+ UHD_ASSERT_THROW(get_num_input_ports() == MAGNESIUM_NUM_CHANS);
+ UHD_ASSERT_THROW(get_num_output_ports() == MAGNESIUM_NUM_CHANS);
+ UHD_ASSERT_THROW(get_mb_controller());
+ _n310_mb_control = std::dynamic_pointer_cast<mpmd_mb_controller>(get_mb_controller());
+ UHD_ASSERT_THROW(_n310_mb_control);
+ _n3xx_timekeeper = std::dynamic_pointer_cast<mpmd_mb_controller::mpmd_timekeeper>(
+ _n310_mb_control->get_timekeeper(0));
+ UHD_ASSERT_THROW(_n3xx_timekeeper);
+ _rpcc = _n310_mb_control->get_rpc_client();
+ UHD_ASSERT_THROW(_rpcc);
+
+ _init_defaults();
+ _init_mpm();
+ _init_peripherals();
+ _init_prop_tree();
+}
+
+magnesium_radio_control_impl::~magnesium_radio_control_impl()
+{
+ RFNOC_LOG_TRACE("magnesium_radio_control_impl::dtor() ");
+}
+
+
+/******************************************************************************
+ * API Calls
+ *****************************************************************************/
+double magnesium_radio_control_impl::set_rate(double requested_rate)
+{
+ meta_range_t rates;
+ for (const double rate : MAGNESIUM_RADIO_RATES) {
+ rates.push_back(range_t(rate));
+ }
+
+ const double rate = rates.clip(requested_rate);
+ if (!math::frequencies_are_equal(requested_rate, rate)) {
+ RFNOC_LOG_WARNING("Coercing requested sample rate from "
+ << (requested_rate / 1e6) << " to " << (rate / 1e6));
+ }
+
+ const double current_rate = get_tick_rate();
+ if (math::frequencies_are_equal(current_rate, rate)) {
+ RFNOC_LOG_DEBUG("Rate is already at " << rate << " MHz. Skipping set_rate()");
+ return current_rate;
+ }
+
+ std::lock_guard<std::mutex> l(_set_lock);
+ // Now commit to device. First, disable LOs.
+ _lo_disable(_tx_lo);
+ _lo_disable(_rx_lo);
+ _master_clock_rate = _ad9371->set_master_clock_rate(rate);
+ _n3xx_timekeeper->update_tick_rate(_master_clock_rate);
+ radio_control_impl::set_rate(_master_clock_rate);
+ // Frequency settings apply to both channels, no loop needed. Will also
+ // re-enable the lowband LOs if they were used.
+ set_rx_frequency(get_rx_frequency(0), 0);
+ set_tx_frequency(get_tx_frequency(0), 0);
+ // Gain and bandwidth need to be looped:
+ for (size_t radio_idx = 0; radio_idx < MAGNESIUM_NUM_CHANS; radio_idx++) {
+ set_rx_gain(radio_control_impl::get_rx_gain(radio_idx), radio_idx);
+ set_tx_gain(radio_control_impl::get_rx_gain(radio_idx), radio_idx);
+ set_rx_bandwidth(get_rx_bandwidth(radio_idx), radio_idx);
+ set_tx_bandwidth(get_tx_bandwidth(radio_idx), radio_idx);
+ }
+ set_tick_rate(_master_clock_rate);
+ return _master_clock_rate;
+}
+
+void magnesium_radio_control_impl::set_tx_antenna(const std::string& ant, const size_t chan)
+{
+ if (ant != get_tx_antenna(chan)) {
+ throw uhd::value_error(
+ str(boost::format("[%s] Requesting invalid TX antenna value: %s")
+ % get_unique_id() % ant));
+ }
+ // We can't actually set the TX antenna, so let's stop here.
+}
+
+void magnesium_radio_control_impl::set_rx_antenna(const std::string& ant, const size_t chan)
+{
+ UHD_ASSERT_THROW(chan <= MAGNESIUM_NUM_CHANS);
+ if (std::find(MAGNESIUM_RX_ANTENNAS.begin(), MAGNESIUM_RX_ANTENNAS.end(), ant)
+ == MAGNESIUM_RX_ANTENNAS.end()) {
+ throw uhd::value_error(
+ str(boost::format("[%s] Requesting invalid RX antenna value: %s")
+ % get_unique_id() % ant));
+ }
+ RFNOC_LOG_TRACE("Setting RX antenna to " << ant << " for chan " << chan);
+ magnesium_cpld_ctrl::chan_sel_t chan_sel = chan == 0 ? magnesium_cpld_ctrl::CHAN1
+ : magnesium_cpld_ctrl::CHAN2;
+ _update_atr_switches(chan_sel, RX_DIRECTION, ant);
+
+ radio_control_impl::set_rx_antenna(ant, chan);
+}
+
+double magnesium_radio_control_impl::set_tx_frequency(const double req_freq, const size_t chan)
+{
+ const double freq = MAGNESIUM_FREQ_RANGE.clip(req_freq);
+ RFNOC_LOG_TRACE("set_tx_frequency(f=" << freq << ", chan=" << chan << ")");
+ _desired_rf_freq[TX_DIRECTION] = freq;
+ std::lock_guard<std::mutex> l(_set_lock);
+ // We need to set the switches on both channels, because they share an LO.
+ // This way, if we tune channel 0 it will not put channel 1 into a bad
+ // state.
+ _update_tx_freq_switches(freq, _tx_bypass_amp, magnesium_cpld_ctrl::BOTH);
+ const std::string ad9371_source = this->get_tx_lo_source(MAGNESIUM_LO1, chan);
+ const std::string adf4351_source = this->get_tx_lo_source(MAGNESIUM_LO2, chan);
+ UHD_ASSERT_THROW(adf4351_source == "internal");
+ double coerced_if_freq = freq;
+
+ if (_map_freq_to_tx_band(_tx_band_map, freq) == tx_band::LOWBAND) {
+ _is_low_band[TX_DIRECTION] = true;
+ const double desired_low_freq = MAGNESIUM_TX_IF_FREQ - freq;
+ coerced_if_freq =
+ this->_set_tx_lo_freq(adf4351_source, MAGNESIUM_LO2, desired_low_freq, chan)
+ + freq;
+ RFNOC_LOG_TRACE("coerced_if_freq = " << coerced_if_freq);
+ } else {
+ _is_low_band[TX_DIRECTION] = false;
+ _lo_disable(_tx_lo);
+ }
+ // external LO required to tune at 2xdesired_frequency.
+ const double desired_if_freq = (ad9371_source == "internal") ? coerced_if_freq
+ : 2 * coerced_if_freq;
+
+ this->_set_tx_lo_freq(ad9371_source, MAGNESIUM_LO1, desired_if_freq, chan);
+ this->_update_freq(chan, TX_DIRECTION);
+ this->_update_gain(chan, TX_DIRECTION);
+ return radio_control_impl::get_tx_frequency(chan);
+}
+
+void magnesium_radio_control_impl::_update_gain(const size_t chan, const uhd::direction_t dir)
+{
+ const std::string fe = (dir == TX_DIRECTION) ? "tx_frontends" : "rx_frontends";
+ const double freq = (dir == TX_DIRECTION) ? this->get_tx_frequency(chan)
+ : this->get_rx_frequency(chan);
+ this->_set_all_gain(this->_get_all_gain(chan, dir), freq, chan, dir);
+}
+
+void magnesium_radio_control_impl::_update_freq(const size_t chan, const uhd::direction_t dir)
+{
+ const std::string ad9371_source = dir == TX_DIRECTION
+ ? this->get_tx_lo_source(MAGNESIUM_LO1, chan)
+ : this->get_rx_lo_source(MAGNESIUM_LO1, chan);
+
+ const double ad9371_freq = ad9371_source == "external" ? _ad9371_freq[dir] / 2
+ : _ad9371_freq[dir];
+ const double rf_freq = _is_low_band[dir] ? ad9371_freq - _adf4351_freq[dir]
+ : ad9371_freq;
+
+ RFNOC_LOG_TRACE("RF freq = " << rf_freq);
+ UHD_ASSERT_THROW(fp_compare_epsilon<double>(rf_freq) >= 0);
+ UHD_ASSERT_THROW(fp_compare_epsilon<double>(std::abs(rf_freq - _desired_rf_freq[dir]))
+ <= _master_clock_rate / 2);
+ if (dir == RX_DIRECTION) {
+ radio_control_impl::set_rx_frequency(rf_freq, chan);
+ } else if (dir == TX_DIRECTION) {
+ radio_control_impl::set_tx_frequency(rf_freq, chan);
+ } else {
+ UHD_THROW_INVALID_CODE_PATH();
+ }
+}
+
+double magnesium_radio_control_impl::set_rx_frequency(const double req_freq, const size_t chan)
+{
+ const double freq = MAGNESIUM_FREQ_RANGE.clip(req_freq);
+ RFNOC_LOG_TRACE("set_rx_frequency(f=" << freq << ", chan=" << chan << ")");
+ _desired_rf_freq[RX_DIRECTION] = freq;
+ std::lock_guard<std::mutex> l(_set_lock);
+ // We need to set the switches on both channels, because they share an LO.
+ // This way, if we tune channel 0 it will not put channel 1 into a bad
+ // state.
+ _update_rx_freq_switches(freq, _rx_bypass_lnas, magnesium_cpld_ctrl::BOTH);
+ const std::string ad9371_source = this->get_rx_lo_source(MAGNESIUM_LO1, chan);
+ const std::string adf4351_source = this->get_rx_lo_source(MAGNESIUM_LO2, chan);
+ UHD_ASSERT_THROW(adf4351_source == "internal");
+ double coerced_if_freq = freq;
+
+ if (_map_freq_to_rx_band(_rx_band_map, freq) == rx_band::LOWBAND) {
+ _is_low_band[RX_DIRECTION] = true;
+ const double desired_low_freq = MAGNESIUM_RX_IF_FREQ - freq;
+ coerced_if_freq =
+ this->_set_rx_lo_freq(adf4351_source, MAGNESIUM_LO2, desired_low_freq, chan)
+ + freq;
+ RFNOC_LOG_TRACE("coerced_if_freq = " << coerced_if_freq);
+ } else {
+ _is_low_band[RX_DIRECTION] = false;
+ _lo_disable(_rx_lo);
+ }
+ // external LO required to tune at 2xdesired_frequency.
+ const double desired_if_freq = ad9371_source == "internal" ? coerced_if_freq
+ : 2 * coerced_if_freq;
+
+ this->_set_rx_lo_freq(ad9371_source, MAGNESIUM_LO1, desired_if_freq, chan);
+
+ this->_update_freq(chan, RX_DIRECTION);
+ this->_update_gain(chan, RX_DIRECTION);
+
+ return radio_control_impl::get_rx_frequency(chan);
+}
+
+double magnesium_radio_control_impl::set_rx_bandwidth(
+ const double bandwidth, const size_t chan)
+{
+ std::lock_guard<std::mutex> l(_set_lock);
+ _ad9371->set_bandwidth(bandwidth, chan, RX_DIRECTION);
+ // FIXME: setting analog bandwidth on AD9371 take no effect.
+ // Remove this warning when ADI can confirm that it works.
+ RFNOC_LOG_WARNING("set_rx_bandwidth take no effect on AD9371. "
+ "Default analog bandwidth is 100MHz");
+ return AD9371_RX_MAX_BANDWIDTH;
+}
+
+double magnesium_radio_control_impl::set_tx_bandwidth(
+ const double bandwidth, const size_t chan)
+{
+ std::lock_guard<std::mutex> l(_set_lock);
+ _ad9371->set_bandwidth(bandwidth, chan, TX_DIRECTION);
+ // FIXME: setting analog bandwidth on AD9371 take no effect.
+ // Remove this warning when ADI can confirm that it works.
+ RFNOC_LOG_WARNING("set_tx_bandwidth take no effect on AD9371. "
+ "Default analog bandwidth is 100MHz");
+ return AD9371_TX_MAX_BANDWIDTH;
+}
+
+void magnesium_radio_control_impl::set_tx_gain_profile(
+ const std::string& profile, const size_t)
+{
+ if (std::find(
+ MAGNESIUM_GP_OPTIONS.begin(), MAGNESIUM_GP_OPTIONS.end(), profile)
+ == MAGNESIUM_GP_OPTIONS.end()) {
+ RFNOC_LOG_ERROR("Invalid TX gain profile: " << profile);
+ throw uhd::key_error("Invalid TX gain profile!");
+ }
+ _gain_profile[TX_DIRECTION] = profile;
+}
+
+void magnesium_radio_control_impl::set_rx_gain_profile(
+ const std::string& profile, const size_t)
+{
+ if (std::find(
+ MAGNESIUM_GP_OPTIONS.begin(), MAGNESIUM_GP_OPTIONS.end(), profile)
+ == MAGNESIUM_GP_OPTIONS.end()) {
+ RFNOC_LOG_ERROR("Invalid RX gain profile: " << profile);
+ throw uhd::key_error("Invalid RX gain profile!");
+ }
+ _gain_profile[RX_DIRECTION] = profile;
+}
+
+double magnesium_radio_control_impl::set_tx_gain(const double gain, const size_t chan)
+{
+ std::lock_guard<std::mutex> l(_set_lock);
+ RFNOC_LOG_TRACE("set_tx_gain(gain=" << gain << ", chan=" << chan << ")");
+ const double coerced_gain =
+ _set_all_gain(gain, this->get_tx_frequency(chan), chan, TX_DIRECTION);
+ radio_control_impl::set_tx_gain(coerced_gain, chan);
+ return coerced_gain;
+}
+
+double magnesium_radio_control_impl::_set_tx_gain(
+ const std::string& name, const double gain, const size_t chan)
+{
+ std::lock_guard<std::mutex> l(_set_lock);
+ RFNOC_LOG_TRACE(
+ "_set_tx_gain(name=" << name << ", gain=" << gain << ", chan=" << chan << ")");
+ RFNOC_LOG_TRACE(
+ "_set_tx_gain(name=" << name << ", gain=" << gain << ", chan=" << chan << ")");
+ double clip_gain = 0;
+ if (name == MAGNESIUM_GAIN1) {
+ clip_gain = uhd::clip(gain, AD9371_MIN_TX_GAIN, AD9371_MAX_TX_GAIN);
+ _ad9371_att[TX_DIRECTION] = clip_gain;
+ } else if (name == MAGNESIUM_GAIN2) {
+ clip_gain = uhd::clip(gain, DSA_MIN_GAIN, DSA_MAX_GAIN);
+ _dsa_att[TX_DIRECTION] = clip_gain;
+ } else if (name == MAGNESIUM_AMP) {
+ clip_gain = gain > 0.0 ? AMP_MAX_GAIN : AMP_MIN_GAIN;
+ _amp_bypass[TX_DIRECTION] = clip_gain == 0.0;
+ } else {
+ throw uhd::value_error("Could not find gain element " + name);
+ }
+ RFNOC_LOG_TRACE("_set_tx_gain calling update gain");
+ this->_set_all_gain(this->_get_all_gain(chan, TX_DIRECTION),
+ this->get_tx_frequency(chan),
+ chan,
+ TX_DIRECTION);
+ return clip_gain;
+}
+
+double magnesium_radio_control_impl::_get_tx_gain(
+ const std::string& name, const size_t /*chan*/
+)
+{
+ std::lock_guard<std::mutex> l(_set_lock);
+ if (name == MAGNESIUM_GAIN1) {
+ return _ad9371_att[TX_DIRECTION];
+ } else if (name == MAGNESIUM_GAIN2) {
+ return _dsa_att[TX_DIRECTION];
+ } else if (name == MAGNESIUM_AMP) {
+ return _amp_bypass[TX_DIRECTION] ? AMP_MIN_GAIN : AMP_MAX_GAIN;
+ } else {
+ throw uhd::value_error("Could not find gain element " + name);
+ }
+}
+
+double magnesium_radio_control_impl::set_rx_gain(const double gain, const size_t chan)
+{
+ std::lock_guard<std::mutex> l(_set_lock);
+ RFNOC_LOG_TRACE("set_rx_gain(gain=" << gain << ", chan=" << chan << ")");
+ const double coerced_gain =
+ _set_all_gain(gain, this->get_rx_frequency(chan), chan, RX_DIRECTION);
+ radio_control_impl::set_rx_gain(coerced_gain, chan);
+ return coerced_gain;
+}
+
+double magnesium_radio_control_impl::_set_rx_gain(
+ const std::string& name, const double gain, const size_t chan)
+{
+ std::lock_guard<std::mutex> l(_set_lock);
+ RFNOC_LOG_TRACE(
+ "_set_rx_gain(name=" << name << ", gain=" << gain << ", chan=" << chan << ")");
+ double clip_gain = 0;
+ if (name == MAGNESIUM_GAIN1) {
+ clip_gain = uhd::clip(gain, AD9371_MIN_RX_GAIN, AD9371_MAX_RX_GAIN);
+ _ad9371_att[RX_DIRECTION] = clip_gain;
+ } else if (name == MAGNESIUM_GAIN2) {
+ clip_gain = uhd::clip(gain, DSA_MIN_GAIN, DSA_MAX_GAIN);
+ _dsa_att[RX_DIRECTION] = clip_gain;
+ } else if (name == MAGNESIUM_AMP) {
+ clip_gain = gain > 0.0 ? AMP_MAX_GAIN : AMP_MIN_GAIN;
+ _amp_bypass[RX_DIRECTION] = clip_gain == 0.0;
+ } else {
+ throw uhd::value_error("Could not find gain element " + name);
+ }
+ RFNOC_LOG_TRACE("_set_rx_gain calling update gain");
+ this->_set_all_gain(this->_get_all_gain(chan, RX_DIRECTION),
+ this->get_rx_frequency(chan),
+ chan,
+ RX_DIRECTION);
+ return clip_gain; // not really any coerced here (only clip) for individual gain
+}
+
+double magnesium_radio_control_impl::_get_rx_gain(
+ const std::string& name, const size_t /*chan*/
+)
+{
+ std::lock_guard<std::mutex> l(_set_lock);
+
+ if (name == MAGNESIUM_GAIN1) {
+ return _ad9371_att[RX_DIRECTION];
+ } else if (name == MAGNESIUM_GAIN2) {
+ return _dsa_att[RX_DIRECTION];
+ } else if (name == MAGNESIUM_AMP) {
+ return _amp_bypass[RX_DIRECTION] ? AMP_MIN_GAIN : AMP_MAX_GAIN;
+ } else {
+ throw uhd::value_error("Could not find gain element " + name);
+ }
+}
+
+double magnesium_radio_control_impl::set_tx_gain(
+ const double gain, const std::string& name, const size_t chan)
+{
+ if (get_tx_gain_profile(chan) == "manual") {
+ if (name == "all" || name == ALL_GAINS) {
+ RFNOC_LOG_ERROR("Setting overall gain is not supported in manual gain mode!");
+ throw uhd::key_error(
+ "Setting overall gain is not supported in manual gain mode!");
+ }
+ if (name != MAGNESIUM_GAIN1 && name != MAGNESIUM_GAIN2 && name != MAGNESIUM_AMP) {
+ RFNOC_LOG_ERROR("Invalid TX gain name: " << name);
+ throw uhd::key_error("Invalid TX gain name!");
+ }
+ const double coerced_gain = get_tx_gain_range(name, chan).clip(gain, true);
+ if (name == MAGNESIUM_GAIN1) {
+ _ad9371_att[TX_DIRECTION] = AD9371_MAX_TX_GAIN - coerced_gain;
+ } else if (name == MAGNESIUM_GAIN2) {
+ _dsa_set_att(AD9371_MAX_TX_GAIN - coerced_gain, chan, TX_DIRECTION);
+ } else if (name == MAGNESIUM_AMP) {
+ _amp_bypass[TX_DIRECTION] = (coerced_gain == AMP_MIN_GAIN);
+ } else {
+ throw uhd::value_error("Could not find gain element " + name);
+ }
+ _set_all_gain(coerced_gain /* this value doesn't actuall matter */,
+ get_tx_frequency(chan),
+ chan,
+ TX_DIRECTION);
+ return coerced_gain;
+ }
+
+ if (name == "all" || name == ALL_GAINS) {
+ return set_tx_gain(gain, chan);
+ }
+ RFNOC_LOG_ERROR("Setting individual TX gains is only supported in manual gain mode!");
+ throw uhd::key_error(
+ "Setting individual TX gains is only supported in manual gain mode!");
+}
+
+double magnesium_radio_control_impl::set_rx_gain(
+ const double gain, const std::string& name, const size_t chan)
+{
+ if (get_rx_gain_profile(chan) == "manual") {
+ if (name == "all" || name == ALL_GAINS) {
+ RFNOC_LOG_ERROR("Setting overall gain is not supported in manual gain mode!");
+ throw uhd::key_error(
+ "Setting overall gain is not supported in manual gain mode!");
+ }
+ if (name != MAGNESIUM_GAIN1 && name != MAGNESIUM_GAIN2 && name != MAGNESIUM_AMP) {
+ RFNOC_LOG_ERROR("Invalid RX gain name: " << name);
+ throw uhd::key_error("Invalid RX gain name!");
+ }
+ const double coerced_gain = get_rx_gain_range(name, chan).clip(gain, true);
+ if (name == MAGNESIUM_GAIN1) {
+ _ad9371_att[RX_DIRECTION] = AD9371_MAX_RX_GAIN - coerced_gain;
+ } else if (name == MAGNESIUM_GAIN2) {
+ _dsa_set_att(AD9371_MAX_RX_GAIN - coerced_gain, chan, RX_DIRECTION);
+ } else if (name == MAGNESIUM_AMP) {
+ _amp_bypass[RX_DIRECTION] = (coerced_gain == AMP_MIN_GAIN);
+ } else {
+ throw uhd::value_error("Could not find gain element " + name);
+ }
+ _set_all_gain(coerced_gain /* this value doesn't actuall matter */,
+ get_rx_frequency(chan),
+ chan,
+ RX_DIRECTION);
+ return coerced_gain;
+ }
+
+ if (name == "all" || name == ALL_GAINS) {
+ return set_rx_gain(gain, chan);
+ }
+ RFNOC_LOG_ERROR("Setting individual RX gains is only supported in manual gain mode!");
+ throw uhd::key_error(
+ "Setting individual RX gains is only supported in manual gain mode!");
+}
+
+std::vector<std::string> magnesium_radio_control_impl::get_tx_antennas(const size_t) const
+{
+ return {"TX/RX"};
+}
+
+std::vector<std::string> magnesium_radio_control_impl::get_rx_antennas(const size_t) const
+{
+ return MAGNESIUM_RX_ANTENNAS;
+}
+
+uhd::freq_range_t magnesium_radio_control_impl::get_tx_frequency_range(const size_t) const
+{
+ return meta_range_t(MAGNESIUM_MIN_FREQ, MAGNESIUM_MAX_FREQ, 1.0);
+}
+
+uhd::freq_range_t magnesium_radio_control_impl::get_rx_frequency_range(const size_t) const
+{
+ return meta_range_t(MAGNESIUM_MIN_FREQ, MAGNESIUM_MAX_FREQ, 1.0);
+}
+
+std::vector<std::string> magnesium_radio_control_impl::get_tx_gain_names(const size_t) const
+{
+ return {MAGNESIUM_GAIN1, MAGNESIUM_GAIN2, MAGNESIUM_AMP};
+}
+
+std::vector<std::string> magnesium_radio_control_impl::get_rx_gain_names(const size_t) const
+{
+ return {MAGNESIUM_GAIN1, MAGNESIUM_GAIN2, MAGNESIUM_AMP};
+}
+
+double magnesium_radio_control_impl::get_tx_gain(
+ const std::string& name, const size_t chan)
+{
+ if (name == MAGNESIUM_GAIN1 || name == MAGNESIUM_GAIN2 || name == MAGNESIUM_AMP) {
+ return _get_tx_gain(name, chan);
+ }
+ if (name == "all" || name == ALL_GAINS) {
+ return radio_control_impl::get_tx_gain(chan);
+ }
+ RFNOC_LOG_ERROR("Invalid TX gain name: " << name);
+ throw uhd::key_error("Invalid TX gain name!");
+}
+
+double magnesium_radio_control_impl::get_rx_gain(
+ const std::string& name, const size_t chan)
+{
+ if (name == MAGNESIUM_GAIN1 || name == MAGNESIUM_GAIN2 || name == MAGNESIUM_AMP) {
+ return _get_rx_gain(name, chan);
+ }
+ if (name == "all" || name == ALL_GAINS) {
+ return radio_control_impl::get_rx_gain(chan);
+ }
+ RFNOC_LOG_ERROR("Invalid RX gain name: " << name);
+ throw uhd::key_error("Invalid RX gain name!");
+}
+
+uhd::gain_range_t magnesium_radio_control_impl::get_tx_gain_range(const size_t chan) const
+{
+ if (get_tx_gain_profile(chan) == "manual") {
+ return meta_range_t(0.0, 0.0, 0.0);
+ }
+ return meta_range_t(ALL_TX_MIN_GAIN, ALL_TX_MAX_GAIN, ALL_TX_GAIN_STEP);
+}
+
+uhd::gain_range_t magnesium_radio_control_impl::get_tx_gain_range(
+ const std::string& name, const size_t chan) const
+{
+ if (get_tx_gain_profile(chan) == "manual") {
+ if (name == "all" || name == ALL_GAINS) {
+ return meta_range_t(0.0, 0.0, 0.0);
+ }
+ if (name == MAGNESIUM_GAIN1) {
+ return meta_range_t(
+ AD9371_MIN_TX_GAIN, AD9371_MAX_TX_GAIN, AD9371_TX_GAIN_STEP);
+ }
+ if (name == MAGNESIUM_GAIN2) {
+ return meta_range_t(DSA_MIN_GAIN, DSA_MAX_GAIN, DSA_GAIN_STEP);
+ }
+ if (name == MAGNESIUM_AMP) {
+ return meta_range_t(AMP_MIN_GAIN, AMP_MAX_GAIN, AMP_GAIN_STEP);
+ }
+ RFNOC_LOG_ERROR("Invalid TX gain name: " << name);
+ throw uhd::key_error("Invalid TX gain name!");
+ }
+ if (name == "all" || name == ALL_GAINS) {
+ return get_tx_gain_range(chan);
+ }
+ if (name == MAGNESIUM_GAIN1 || name == MAGNESIUM_GAIN2 || name == MAGNESIUM_AMP) {
+ return meta_range_t(0.0, 0.0, 0.0);
+ }
+ RFNOC_LOG_ERROR("Invalid TX gain name: " << name);
+ throw uhd::key_error("Invalid TX gain name!");
+}
+
+uhd::gain_range_t magnesium_radio_control_impl::get_rx_gain_range(const size_t chan) const
+{
+ if (get_rx_gain_profile(chan) == "manual") {
+ return meta_range_t(0.0, 0.0, 0.0);
+ }
+ return meta_range_t(ALL_RX_MIN_GAIN, ALL_RX_MAX_GAIN, ALL_RX_GAIN_STEP);
+}
+
+uhd::gain_range_t magnesium_radio_control_impl::get_rx_gain_range(
+ const std::string& name, const size_t chan) const
+{
+ if (get_rx_gain_profile(chan) == "manual") {
+ if (name == "all" || name == ALL_GAINS) {
+ return meta_range_t(0.0, 0.0, 0.0);
+ }
+ if (name == MAGNESIUM_GAIN1) {
+ return meta_range_t(
+ AD9371_MIN_RX_GAIN, AD9371_MAX_RX_GAIN, AD9371_RX_GAIN_STEP);
+ }
+ if (name == MAGNESIUM_GAIN2) {
+ return meta_range_t(DSA_MIN_GAIN, DSA_MAX_GAIN, DSA_GAIN_STEP);
+ }
+ if (name == MAGNESIUM_AMP) {
+ return meta_range_t(AMP_MIN_GAIN, AMP_MAX_GAIN, AMP_GAIN_STEP);
+ }
+ RFNOC_LOG_ERROR("Invalid RX gain name: " << name);
+ throw uhd::key_error("Invalid RX gain name!");
+ }
+ if (name == "all" || name == ALL_GAINS) {
+ return get_rx_gain_range(chan);
+ }
+ if (name == MAGNESIUM_GAIN1 || name == MAGNESIUM_GAIN2 || name == MAGNESIUM_AMP) {
+ return meta_range_t(0.0, 0.0, 0.0);
+ }
+ RFNOC_LOG_ERROR("Invalid RX gain name: " << name);
+ throw uhd::key_error("Invalid RX gain name!");
+}
+
+std::vector<std::string> magnesium_radio_control_impl::get_tx_gain_profile_names(
+ const size_t) const
+{
+ return MAGNESIUM_GP_OPTIONS;
+}
+
+std::vector<std::string> magnesium_radio_control_impl::get_rx_gain_profile_names(const size_t ) const
+{
+ return MAGNESIUM_GP_OPTIONS;
+}
+
+std::string magnesium_radio_control_impl::get_tx_gain_profile(const size_t) const
+{
+ return _gain_profile.at(TX_DIRECTION);
+}
+
+std::string magnesium_radio_control_impl::get_rx_gain_profile(const size_t) const
+{
+ return _gain_profile.at(RX_DIRECTION);
+}
+
+meta_range_t magnesium_radio_control_impl::get_tx_bandwidth_range(size_t) const
+{
+ return meta_range_t(AD9371_TX_MIN_BANDWIDTH, AD9371_TX_MAX_BANDWIDTH);
+}
+
+meta_range_t magnesium_radio_control_impl::get_rx_bandwidth_range(size_t) const
+{
+ return meta_range_t(AD9371_TX_MIN_BANDWIDTH, AD9371_TX_MAX_BANDWIDTH);
+}
+
+
+/******************************************************************************
+ * LO Controls
+ *****************************************************************************/
+std::vector<std::string> magnesium_radio_control_impl::get_rx_lo_names(
+ const size_t /*chan*/
+ ) const
+{
+ return std::vector<std::string>{MAGNESIUM_LO1, MAGNESIUM_LO2};
+}
+
+std::vector<std::string> magnesium_radio_control_impl::get_rx_lo_sources(
+ const std::string& name, const size_t /*chan*/
+ ) const
+{
+ if (name == MAGNESIUM_LO2) {
+ return std::vector<std::string>{"internal"};
+ } else if (name == MAGNESIUM_LO1) {
+ return std::vector<std::string>{"internal", "external"};
+ } else {
+ throw uhd::value_error("Could not find LO stage " + name);
+ }
+}
+
+freq_range_t magnesium_radio_control_impl::get_rx_lo_freq_range(
+ const std::string& name, const size_t /*chan*/
+) const
+{
+ if (name == MAGNESIUM_LO1) {
+ return freq_range_t{ADF4351_MIN_FREQ, ADF4351_MAX_FREQ};
+ } else if (name == MAGNESIUM_LO2) {
+ return freq_range_t{AD9371_MIN_FREQ, AD9371_MAX_FREQ};
+ } else {
+ throw uhd::value_error("Could not find LO stage " + name);
+ }
+}
+
+void magnesium_radio_control_impl::set_rx_lo_source(
+ const std::string& src, const std::string& name, const size_t /*chan*/
+)
+{
+ // TODO: checking what options are there
+ std::lock_guard<std::mutex> l(_set_lock);
+ RFNOC_LOG_TRACE("Setting RX LO " << name << " to " << src);
+
+ if (name == MAGNESIUM_LO1) {
+ _ad9371->set_lo_source(src, RX_DIRECTION);
+ } else {
+ RFNOC_LOG_ERROR(
+ "RX LO " << name << " does not support setting source to " << src);
+ }
+}
+
+const std::string magnesium_radio_control_impl::get_rx_lo_source(
+ const std::string& name, const size_t /*chan*/
+) const
+{
+ if (name == MAGNESIUM_LO1) {
+ // TODO: should we use this from cache?
+ return _ad9371->get_lo_source(RX_DIRECTION);
+ }
+ return "internal";
+}
+
+double magnesium_radio_control_impl::_set_rx_lo_freq(const std::string source,
+ const std::string name,
+ const double freq,
+ const size_t chan)
+{
+ double coerced_lo_freq = freq;
+ if (source != "internal") {
+ RFNOC_LOG_WARNING(
+ "LO source is not internal. This set frequency will be ignored");
+ if (name == MAGNESIUM_LO1) {
+ // handle ad9371 external LO case
+ coerced_lo_freq = freq;
+ _ad9371_freq[RX_DIRECTION] = coerced_lo_freq;
+ }
+ } else {
+ if (name == MAGNESIUM_LO1) {
+ coerced_lo_freq = _ad9371->set_frequency(freq, chan, RX_DIRECTION);
+ _ad9371_freq[RX_DIRECTION] = coerced_lo_freq;
+ } else if (name == MAGNESIUM_LO2) {
+ // TODO: no hardcode the init_n_mode
+ coerced_lo_freq = _lo_enable(_rx_lo, freq, _master_clock_rate, false);
+ _adf4351_freq[RX_DIRECTION] = coerced_lo_freq;
+ } else {
+ RFNOC_LOG_WARNING("There's no LO with this name of "
+ << name
+ << " in the system. This set rx lo freq will be ignored");
+ };
+ }
+ return coerced_lo_freq;
+}
+
+double magnesium_radio_control_impl::set_rx_lo_freq(
+ double freq, const std::string& name, const size_t chan)
+{
+ RFNOC_LOG_TRACE("set_rx_lo_freq(freq=" << freq << ", name=" << name << ")");
+ std::lock_guard<std::mutex> l(_set_lock);
+ std::string source = this->get_rx_lo_source(name, chan);
+ const double coerced_lo_freq = this->_set_rx_lo_freq(source, name, freq, chan);
+ this->_update_freq(chan, RX_DIRECTION);
+ this->_update_gain(chan, RX_DIRECTION);
+ return coerced_lo_freq;
+}
+
+double magnesium_radio_control_impl::get_rx_lo_freq(
+ const std::string& name, const size_t chan)
+{
+ RFNOC_LOG_TRACE("get_rx_lo_freq(name=" << name << ")");
+ std::string source = this->get_rx_lo_source(name, chan);
+ if (name == MAGNESIUM_LO1) {
+ return _ad9371_freq.at(RX_DIRECTION);
+ } else if (name == "adf4531") {
+ return _adf4351_freq.at(RX_DIRECTION);
+ } else {
+ RFNOC_LOG_ERROR("get_rx_lo_freq(): No such LO: " << name);
+ }
+ UHD_THROW_INVALID_CODE_PATH();
+}
+
+// TX LO
+std::vector<std::string> magnesium_radio_control_impl::get_tx_lo_names(
+ const size_t /*chan*/
+) const
+{
+ return std::vector<std::string>{MAGNESIUM_LO1, MAGNESIUM_LO2};
+}
+
+std::vector<std::string> magnesium_radio_control_impl::get_tx_lo_sources(
+ const std::string& name, const size_t /*chan*/
+) const
+{
+ if (name == MAGNESIUM_LO2) {
+ return std::vector<std::string>{"internal"};
+ } else if (name == MAGNESIUM_LO1) {
+ return std::vector<std::string>{"internal", "external"};
+ } else {
+ throw uhd::value_error("Could not find LO stage " + name);
+ }
+}
+
+freq_range_t magnesium_radio_control_impl::get_tx_lo_freq_range(
+ const std::string& name, const size_t /*chan*/
+)
+{
+ if (name == MAGNESIUM_LO2) {
+ return freq_range_t{ADF4351_MIN_FREQ, ADF4351_MAX_FREQ};
+ } else if (name == MAGNESIUM_LO1) {
+ return freq_range_t{AD9371_MIN_FREQ, AD9371_MAX_FREQ};
+ } else {
+ throw uhd::value_error("Could not find LO stage " + name);
+ }
+}
+
+void magnesium_radio_control_impl::set_tx_lo_source(
+ const std::string& src, const std::string& name, const size_t /*chan*/
+)
+{
+ // TODO: checking what options are there
+ std::lock_guard<std::mutex> l(_set_lock);
+ RFNOC_LOG_TRACE("set_tx_lo_source(name=" << name << ", src=" << src << ")");
+ if (name == MAGNESIUM_LO1) {
+ _ad9371->set_lo_source(src, TX_DIRECTION);
+ } else {
+ RFNOC_LOG_ERROR(
+ "TX LO " << name << " does not support setting source to " << src);
+ }
+}
+
+const std::string magnesium_radio_control_impl::get_tx_lo_source(
+ const std::string& name, const size_t /*chan*/
+)
+{
+ if (name == MAGNESIUM_LO1) {
+ // TODO: should we use this from cache?
+ return _ad9371->get_lo_source(TX_DIRECTION);
+ }
+ return "internal";
+}
+
+double magnesium_radio_control_impl::_set_tx_lo_freq(const std::string source,
+ const std::string name,
+ const double freq,
+ const size_t chan)
+{
+ double coerced_lo_freq = freq;
+ if (source != "internal") {
+ RFNOC_LOG_WARNING(
+ "LO source is not internal. This set frequency will be ignored");
+ if (name == MAGNESIUM_LO1) {
+ // handle ad9371 external LO case
+ coerced_lo_freq = freq;
+ _ad9371_freq[TX_DIRECTION] = coerced_lo_freq;
+ }
+ } else {
+ if (name == MAGNESIUM_LO1) {
+ coerced_lo_freq = _ad9371->set_frequency(freq, chan, TX_DIRECTION);
+ _ad9371_freq[TX_DIRECTION] = coerced_lo_freq;
+ } else if (name == MAGNESIUM_LO2) {
+ // TODO: no hardcode the int_n_mode
+ const bool int_n_mode = false;
+ coerced_lo_freq = _lo_enable(_tx_lo, freq, _master_clock_rate, int_n_mode);
+ _adf4351_freq[TX_DIRECTION] = coerced_lo_freq;
+ } else {
+ RFNOC_LOG_WARNING("There's no LO with this name of "
+ << name
+ << " in the system. This set tx lo freq will be ignored");
+ };
+ }
+ return coerced_lo_freq;
+}
+
+double magnesium_radio_control_impl::set_tx_lo_freq(
+ double freq, const std::string& name, const size_t chan)
+{
+ RFNOC_LOG_TRACE("set_tx_lo_freq(freq=" << freq << ", name=" << name << ")");
+ std::string source = this->get_tx_lo_source(name, chan);
+ const double return_freq = this->_set_tx_lo_freq(source, name, freq, chan);
+ this->_update_freq(chan, TX_DIRECTION);
+ this->_update_gain(chan, TX_DIRECTION);
+ return return_freq;
+}
+
+double magnesium_radio_control_impl::get_tx_lo_freq(const std::string& name, const size_t chan)
+{
+ RFNOC_LOG_TRACE("get_tx_lo_freq(name=" << name << ")");
+ std::string source = this->get_tx_lo_source(name, chan);
+ if (name == MAGNESIUM_LO1) {
+ return _ad9371_freq[TX_DIRECTION];
+ } else if (name == MAGNESIUM_LO2) {
+ return _adf4351_freq[TX_DIRECTION];
+ } else {
+ RFNOC_LOG_ERROR("get_tx_lo_freq(): No such LO: " << name);
+ };
+
+ UHD_THROW_INVALID_CODE_PATH();
+}
+
+void magnesium_radio_control_impl::_remap_band_limits(
+ const std::string band_map, const uhd::direction_t dir)
+{
+ const size_t dflt_band_size = (dir == RX_DIRECTION) ? _rx_band_map.size()
+ : _tx_band_map.size();
+
+ std::vector<std::string> band_map_split;
+ double band_lim;
+
+ RFNOC_LOG_DEBUG("Using user specified frequency band limits");
+ boost::split(band_map_split, band_map, boost::is_any_of(";"));
+ if (band_map_split.size() != dflt_band_size) {
+ throw uhd::runtime_error((
+ boost::format(
+ "size %s of given frequency band map doesn't match the required size: %s")
+ % band_map_split.size() % dflt_band_size)
+ .str());
+ }
+ RFNOC_LOG_DEBUG("newly used band limits: ");
+ for (size_t i = 0; i < band_map_split.size(); i++) {
+ try {
+ band_lim = std::stod(band_map_split.at(i));
+ } catch (...) {
+ throw uhd::value_error(
+ (boost::format("error while converting given frequency string %s "
+ "to a double value")
+ % band_map_split.at(i))
+ .str());
+ }
+ RFNOC_LOG_DEBUG("band " << i << " limit: " << band_lim << "Hz");
+ if (dir == RX_DIRECTION)
+ _rx_band_map.at(i) = band_lim;
+ else
+ _tx_band_map.at(i) = band_lim;
+ }
+}
+
+
+bool magnesium_radio_control_impl::get_lo_lock_status(const direction_t dir)
+{
+ if (not(bool(_rpcc))) {
+ RFNOC_LOG_WARNING("Reported no LO lock due to lack of RPC connection.");
+ return false;
+ }
+
+ const std::string trx = (dir == RX_DIRECTION) ? "rx" : "tx";
+ const size_t chan = 0; // They're the same after all
+ const double freq = (dir == RX_DIRECTION) ? get_rx_frequency(chan)
+ : get_tx_frequency(chan);
+
+ bool lo_lock =
+ _rpcc->request_with_token<bool>(_rpc_prefix + "get_ad9371_lo_lock", trx);
+ RFNOC_LOG_TRACE("AD9371 " << trx << " LO reports lock: " << (lo_lock ? "Yes" : "No"));
+ if (lo_lock and _map_freq_to_rx_band(_rx_band_map, freq) == rx_band::LOWBAND) {
+ lo_lock =
+ lo_lock
+ && _rpcc->request_with_token<bool>(_rpc_prefix + "get_lowband_lo_lock", trx);
+ RFNOC_LOG_TRACE(
+ "ADF4351 " << trx << " LO reports lock: " << (lo_lock ? "Yes" : "No"));
+ }
+
+ return lo_lock;
+}
+
+/**************************************************************************
+ * GPIO Controls
+ *************************************************************************/
+std::vector<std::string> magnesium_radio_control_impl::get_gpio_banks() const
+{
+ return {MAGNESIUM_FPGPIO_BANK};
+}
+
+void magnesium_radio_control_impl::set_gpio_attr(
+ const std::string& bank, const std::string& attr, const uint32_t value)
+{
+ if (bank != MAGNESIUM_FPGPIO_BANK) {
+ RFNOC_LOG_ERROR("Invalid GPIO bank: " << bank);
+ throw uhd::key_error("Invalid GPIO bank!");
+ }
+ if (!gpio_atr::gpio_attr_rev_map.count(attr)) {
+ RFNOC_LOG_ERROR("Invalid GPIO attr: " << attr);
+ throw uhd::key_error("Invalid GPIO attr!");
+ }
+
+ const gpio_atr::gpio_attr_t gpio_attr = gpio_atr::gpio_attr_rev_map.at(attr);
+
+ if (gpio_attr == gpio_atr::GPIO_READBACK) {
+ RFNOC_LOG_WARNING("Cannot set READBACK attr.");
+ return;
+ }
+
+ _fp_gpio->set_gpio_attr(gpio_attr, value);
+}
+
+uint32_t magnesium_radio_control_impl::get_gpio_attr(
+ const std::string& bank, const std::string& attr)
+{
+ if (bank != MAGNESIUM_FPGPIO_BANK) {
+ RFNOC_LOG_ERROR("Invalid GPIO bank: " << bank);
+ throw uhd::key_error("Invalid GPIO bank!");
+ }
+
+ return _fp_gpio->get_attr_reg(usrp::gpio_atr::gpio_attr_rev_map.at(attr));
+}
+
+/******************************************************************************
+ * EEPROM API
+ *****************************************************************************/
+void magnesium_radio_control_impl::set_db_eeprom(const eeprom_map_t& db_eeprom)
+{
+ const size_t db_idx = get_block_id().get_block_count();
+ _rpcc->notify_with_token("set_db_eeprom", db_idx, db_eeprom);
+}
+
+eeprom_map_t magnesium_radio_control_impl::get_db_eeprom()
+{
+ const size_t db_idx = get_block_id().get_block_count();
+ return this->_rpcc->request_with_token<eeprom_map_t>("get_db_eeprom", db_idx);
+}
+
+/**************************************************************************
+ * Sensor API
+ *************************************************************************/
+std::vector<std::string> magnesium_radio_control_impl::get_rx_sensor_names(size_t)
+{
+ auto sensor_names = _rpcc->request_with_token<std::vector<std::string>>(
+ this->_rpc_prefix + "get_sensors", "RX");
+ sensor_names.push_back("lo_locked");
+ return sensor_names;
+}
+
+sensor_value_t magnesium_radio_control_impl::get_rx_sensor(const std::string& name, size_t chan)
+{
+ if (name == "lo_locked") {
+ return sensor_value_t(
+ "all_los", this->get_lo_lock_status(RX_DIRECTION), "locked", "unlocked");
+ }
+ return sensor_value_t(_rpcc->request_with_token<sensor_value_t::sensor_map_t>(
+ _rpc_prefix + "get_sensor", "RX", name, chan));
+}
+
+std::vector<std::string> magnesium_radio_control_impl::get_tx_sensor_names(size_t)
+{
+ auto sensor_names = _rpcc->request_with_token<std::vector<std::string>>(
+ this->_rpc_prefix + "get_sensors", "TX");
+ sensor_names.push_back("lo_locked");
+ return sensor_names;
+}
+
+sensor_value_t magnesium_radio_control_impl::get_tx_sensor(const std::string& name, size_t chan)
+{
+ if (name == "lo_locked") {
+ return sensor_value_t(
+ "all_los", this->get_lo_lock_status(TX_DIRECTION), "locked", "unlocked");
+ }
+ return sensor_value_t(_rpcc->request_with_token<sensor_value_t::sensor_map_t>(
+ _rpc_prefix + "get_sensor", "TX", name, chan));
+}
+
+/**************************************************************************
+ * node_t API Calls
+ *************************************************************************/
+void magnesium_radio_control_impl::set_command_time(uhd::time_spec_t time, const size_t chan)
+{
+ node_t::set_command_time(time, chan);
+ _wb_ifaces.at(chan)->set_time(time);
+}
+
+/**************************************************************************
+ * Radio Identification API Calls
+ *************************************************************************/
+size_t magnesium_radio_control_impl::get_chan_from_dboard_fe(
+ const std::string& fe, const uhd::direction_t) const
+{
+ if (fe == "0") {
+ return 0;
+ }
+ if (fe == "1") {
+ return 1;
+ }
+ throw uhd::key_error(std::string("[N300] Invalid frontend: ") + fe);
+}
+
+std::string magnesium_radio_control_impl::get_dboard_fe_from_chan(
+ const size_t chan, const uhd::direction_t) const
+{
+ if (chan == 0) {
+ return "0";
+ }
+ if (chan == 1) {
+ return "1";
+ }
+ throw uhd::lookup_error(
+ std::string("[N300] Invalid channel: ") + std::to_string(chan));
+}
+
+std::string magnesium_radio_control_impl::get_fe_name(
+ const size_t, const uhd::direction_t) const
+{
+ return MAGNESIUM_FE_NAME;
+}
+
+// Register the block
+UHD_RFNOC_BLOCK_REGISTER_FOR_DEVICE_DIRECT(
+ magnesium_radio_control, RADIO_BLOCK, N300, "Radio", true, "radio_clk", "bus_clk");
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.hpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_control.hpp
index 165e3c996..d7c721c3b 100644
--- a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.hpp
+++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_control.hpp
@@ -14,12 +14,14 @@
#include "magnesium_ad9371_iface.hpp"
#include "magnesium_cpld_ctrl.hpp"
#include "magnesium_cpld_regs.hpp"
+#include <iostream>
#include <uhd/types/serial.hpp>
#include <uhd/usrp/dboard_manager.hpp>
#include <uhd/usrp/gpio_defs.hpp>
-#include <uhdlib/rfnoc/radio_ctrl_impl.hpp>
-#include <uhdlib/rfnoc/rpc_block_ctrl.hpp>
+#include <uhd/types/eeprom.hpp>
+#include <uhdlib/rfnoc/radio_control_impl.hpp>
#include <uhdlib/usrp/common/adf435x.hpp>
+#include <uhdlib/usrp/common/mpmd_mb_controller.hpp>
#include <uhdlib/usrp/cores/gpio_atr_3000.hpp>
#include <mutex>
@@ -29,13 +31,9 @@ namespace uhd { namespace rfnoc {
*
* This daughterboard is used on the USRP N310 and N300.
*/
-
-
-class magnesium_radio_ctrl_impl : public radio_ctrl_impl, public rpc_block_ctrl
+class magnesium_radio_control_impl : public radio_control_impl
{
public:
- typedef boost::shared_ptr<magnesium_radio_ctrl_impl> sptr;
-
//! Frequency bands for RX. Bands are a function of the analog filter banks
enum class rx_band {
INVALID_BAND,
@@ -68,66 +66,109 @@ public:
/************************************************************************
* Structors
***********************************************************************/
- UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR_DECL(magnesium_radio_ctrl)
- virtual ~magnesium_radio_ctrl_impl();
+ magnesium_radio_control_impl(make_args_ptr make_args);
+ virtual ~magnesium_radio_control_impl();
/************************************************************************
- * API calls
+ * RF API calls
***********************************************************************/
// Note: We use the cached values in radio_ctrl_impl, so most getters are
// not reimplemented here
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);
-
+ // Setters
+ void set_tx_antenna(const std::string &ant, const size_t chan);
+ void set_rx_antenna(const std::string &ant, 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 get_rx_frequency(const size_t chan);
- double get_tx_frequency(const size_t chan);
+ double set_tx_gain(const double gain, const size_t chan);
+ double set_tx_gain(const double gain, const std::string& name, const size_t chan);
+ double set_rx_gain(const double gain, const size_t chan);
+ double set_rx_gain(const double gain, const std::string& name, const size_t chan);
double set_tx_bandwidth(const double bandwidth, const size_t chan);
double set_rx_bandwidth(const double bandwidth, const size_t chan);
+ void set_tx_gain_profile(const std::string& profile, const size_t chan);
+ void set_rx_gain_profile(const std::string& profile, const size_t chan);
+
+ // Getters
+ std::vector<std::string> get_tx_antennas(const size_t chan) const;
+ std::vector<std::string> get_rx_antennas(const size_t chan) const;
+ uhd::freq_range_t get_tx_frequency_range(const size_t chan) const;
+ uhd::freq_range_t get_rx_frequency_range(const size_t chan) const;
+ std::vector<std::string> get_tx_gain_names(const size_t) const;
+ std::vector<std::string> get_rx_gain_names(const size_t) const;
+ double get_tx_gain(const std::string&, size_t);
+ double get_rx_gain(const std::string&, size_t);
+ uhd::gain_range_t get_tx_gain_range(const size_t) const;
+ uhd::gain_range_t get_tx_gain_range(const std::string&, const size_t) const;
+ uhd::gain_range_t get_rx_gain_range(const size_t) const;
+ uhd::gain_range_t get_rx_gain_range(const std::string&, const size_t) const;
+ std::vector<std::string> get_tx_gain_profile_names(const size_t chan) const;
+ std::vector<std::string> get_rx_gain_profile_names(const size_t chan) const;
+ std::string get_tx_gain_profile(const size_t chan) const;
+ std::string get_rx_gain_profile(const size_t chan) const;
+ uhd::meta_range_t get_tx_bandwidth_range(size_t chan) const;
+ uhd::meta_range_t get_rx_bandwidth_range(size_t chan) const;
- // RX LO
- std::vector<std::string> get_rx_lo_names(const size_t chan);
+ /**************************************************************************
+ * LO Controls
+ *************************************************************************/
+ std::vector<std::string> get_rx_lo_names(const size_t chan) const;
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);
-
+ const std::string& name, const size_t chan) const;
+ freq_range_t get_rx_lo_freq_range(const std::string& name, const size_t chan) const;
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);
-
+ const std::string get_rx_lo_source(const std::string& name, const size_t chan) const;
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);
-
- // TX LO
- std::vector<std::string> get_tx_lo_names(const size_t chan);
+ std::vector<std::string> get_tx_lo_names(const size_t chan) const;
std::vector<std::string> get_tx_lo_sources(
- const std::string& name, const size_t chan);
+ const std::string& name, const size_t chan) const;
freq_range_t get_tx_lo_freq_range(const std::string& name, const size_t chan);
-
void set_tx_lo_source(
const std::string& src, const std::string& name, const size_t chan);
const std::string get_tx_lo_source(const std::string& name, const size_t chan);
-
- double set_tx_lo_freq(double freq, const std::string& name, const size_t chan);
+ double set_tx_lo_freq(const double freq, const std::string& name, const size_t chan);
double get_tx_lo_freq(const std::string& name, const size_t chan);
- // gain
- double set_tx_gain(const double gain, const size_t chan);
- double set_rx_gain(const double gain, const size_t chan);
- void set_tx_gain_source(
- const std::string& src, const std::string& name, const size_t chan);
- std::string get_tx_gain_source(const std::string& name, const size_t chan);
- void set_rx_gain_source(
- const std::string& src, const std::string& name, const size_t chan);
- std::string get_rx_gain_source(const std::string& name, const size_t chan);
+ /**************************************************************************
+ * GPIO Controls
+ *************************************************************************/
+ std::vector<std::string> get_gpio_banks() const;
+ void set_gpio_attr(
+ const std::string& bank, const std::string& attr, const uint32_t value);
+ uint32_t get_gpio_attr(const std::string& bank, const std::string& attr);
+
+ /**************************************************************************
+ * EEPROM API
+ *************************************************************************/
+ void set_db_eeprom(const uhd::eeprom_map_t& db_eeprom);
+ uhd::eeprom_map_t get_db_eeprom();
+
+ /**************************************************************************
+ * Sensor API
+ *************************************************************************/
+ std::vector<std::string> get_rx_sensor_names(size_t chan);
+ uhd::sensor_value_t get_rx_sensor(const std::string& name, size_t chan);
+ std::vector<std::string> get_tx_sensor_names(size_t chan);
+ uhd::sensor_value_t get_tx_sensor(const std::string& name, 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);
+ /**************************************************************************
+ * Radio Identification API Calls
+ *************************************************************************/
+ std::string get_slot_name() const { return _radio_slot; }
+ size_t get_chan_from_dboard_fe(
+ const std::string& fe, const uhd::direction_t direction) const;
+ std::string get_dboard_fe_from_chan(
+ const size_t chan, const uhd::direction_t direction) const;
+ std::string get_fe_name(
+ const size_t chan, const uhd::direction_t direction) const;
- void set_rpc_client(uhd::rpc_client::sptr rpcc, const uhd::device_addr_t& block_args);
+ /**************************************************************************
+ * node_t API Calls
+ *************************************************************************/
+ void set_command_time(uhd::time_spec_t time, const size_t chan);
private:
/**************************************************************************
@@ -157,6 +198,10 @@ private:
//! Initialize property tree
void _init_prop_tree();
+ //! Init RPC interaction
+ void _init_mpm();
+
+ //! Set up sensor property nodes
void _init_mpm_sensors(const direction_t dir, const size_t chan_idx);
//! Map a frequency in Hz to an rx_band value. Will return
@@ -240,12 +285,21 @@ private:
//! Additional block args; gets set during set_rpc_client()
uhd::device_addr_t _block_args;
+ //! Reference to the MB controller
+ mpmd_mb_controller::sptr _n310_mb_control;
+
+ //! Reference to the MB timekeeper
+ uhd::rfnoc::mpmd_mb_controller::mpmd_timekeeper::sptr _n3xx_timekeeper;
+
//! Reference to the RPC client
uhd::rpc_client::sptr _rpcc;
//! Reference to the SPI core
uhd::spi_iface::sptr _spi;
+ //! Reference to wb_iface compat adapters (one per channel)
+ std::vector<uhd::timed_wb_iface::sptr> _wb_ifaces;
+
//! Reference to the TX LO
adf435x_iface::sptr _tx_lo;
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_cpld.cpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_control_cpld.cpp
index 679816af8..41f99cd68 100644
--- a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_cpld.cpp
+++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_control_cpld.cpp
@@ -6,14 +6,14 @@
#include "magnesium_constants.hpp"
#include "magnesium_cpld_ctrl.hpp"
-#include "magnesium_radio_ctrl_impl.hpp"
+#include "magnesium_radio_control.hpp"
#include <uhd/utils/log.hpp>
using namespace uhd;
using namespace uhd::usrp;
using namespace uhd::rfnoc;
-void magnesium_radio_ctrl_impl::_identify_with_leds(const int identify_duration)
+void magnesium_radio_control_impl::_identify_with_leds(const int identify_duration)
{
auto end_time =
std::chrono::steady_clock::now() + std::chrono::seconds(identify_duration);
@@ -36,7 +36,7 @@ void magnesium_radio_ctrl_impl::_identify_with_leds(const int identify_duration)
_cpld->reset();
}
-void magnesium_radio_ctrl_impl::_update_atr_switches(
+void magnesium_radio_control_impl::_update_atr_switches(
const magnesium_cpld_ctrl::chan_sel_t chan,
const direction_t dir,
const std::string& ant)
@@ -51,8 +51,7 @@ void magnesium_radio_ctrl_impl::_update_atr_switches(
// RX SW1. In all other cases, a TX state toggle (on to idle or vice
// versa) won't trigger a change of the TRX switch.
auto sw_trx = _sw_trx[chan];
- UHD_LOG_TRACE(
- unique_id(), "Updating all RX-ATR related switches for antenna==" << ant);
+ RFNOC_LOG_TRACE("Updating all RX-ATR related switches for antenna==" << ant);
if (ant == "TX/RX") {
rx_sw1 = magnesium_cpld_ctrl::RX_SW1_TRXSWITCHOUTPUT;
sw_trx = magnesium_cpld_ctrl::SW_TRX_RXCHANNELPATH;
@@ -96,7 +95,7 @@ void magnesium_radio_ctrl_impl::_update_atr_switches(
);
}
if (dir == TX_DIRECTION or dir == DX_DIRECTION) {
- UHD_LOG_TRACE(unique_id(), "Updating all TX-ATR related switches...");
+ RFNOC_LOG_TRACE("Updating all TX-ATR related switches...");
_cpld->set_tx_atr_bits(chan,
magnesium_cpld_ctrl::ON,
true, /* LED on */
@@ -117,11 +116,11 @@ void magnesium_radio_ctrl_impl::_update_atr_switches(
};
}
-void magnesium_radio_ctrl_impl::_update_rx_freq_switches(const double freq,
+void magnesium_radio_control_impl::_update_rx_freq_switches(const double freq,
const bool bypass_lnas,
const magnesium_cpld_ctrl::chan_sel_t chan_sel)
{
- UHD_LOG_TRACE(unique_id(),
+ RFNOC_LOG_TRACE(
"Update all RX freq related switches. f=" << freq
<< " Hz, "
"bypass LNAS: "
@@ -142,7 +141,7 @@ void magnesium_radio_ctrl_impl::_update_rx_freq_switches(const double freq,
not bypass_lnas
and (band == rx_band::BAND4 or band == rx_band::BAND5 or band == rx_band::BAND6);
const bool rx_lna2_enable = not bypass_lnas and not rx_lna1_enable;
- UHD_LOG_TRACE(unique_id(),
+ RFNOC_LOG_TRACE(
" Enabling LNA1: " << (rx_lna1_enable ? "Yes" : "No")
<< " Enabling LNA2: " << (rx_lna2_enable ? "Yes" : "No"));
// All the defaults are OK when using the bypass path.
@@ -199,7 +198,7 @@ void magnesium_radio_ctrl_impl::_update_rx_freq_switches(const double freq,
rx_sw6 = magnesium_cpld_ctrl::RX_SW6_UPPERFILTERBANKFROMSWITCH4;
break;
case rx_band::INVALID_BAND:
- UHD_LOG_ERROR(unique_id(), "Cannot map RX frequency to band: " << freq);
+ RFNOC_LOG_ERROR("Cannot map RX frequency to band: " << freq);
break;
default:
UHD_THROW_INVALID_CODE_PATH();
@@ -222,16 +221,15 @@ void magnesium_radio_ctrl_impl::_update_rx_freq_switches(const double freq,
enable_lowband_mixer);
}
-void magnesium_radio_ctrl_impl::_update_tx_freq_switches(const double freq,
+void magnesium_radio_control_impl::_update_tx_freq_switches(const double freq,
const bool bypass_amp,
const magnesium_cpld_ctrl::chan_sel_t chan_sel)
{
- UHD_LOG_TRACE(unique_id(),
- "Update all TX freq related switches. f=" << freq
- << " Hz, "
- "bypass amp: "
- << (bypass_amp ? "Yes" : "No")
- << ", chan=" << chan_sel);
+ RFNOC_LOG_TRACE("Update all TX freq related switches. f="
+ << freq
+ << " Hz, "
+ "bypass amp: "
+ << (bypass_amp ? "Yes" : "No") << ", chan=" << chan_sel);
auto tx_sw1 = magnesium_cpld_ctrl::TX_SW1_SHUTDOWNTXSW1;
auto tx_sw2 = magnesium_cpld_ctrl::TX_SW2_TOTXFILTERLP6400MHZ;
auto tx_sw3 = magnesium_cpld_ctrl::TX_SW3_BYPASSPATHTOTRXSW;
@@ -279,7 +277,7 @@ void magnesium_radio_ctrl_impl::_update_tx_freq_switches(const double freq,
tx_sw3 = magnesium_cpld_ctrl::TX_SW3_TOTXFILTERBANKS;
break;
case tx_band::INVALID_BAND:
- UHD_LOG_ERROR(unique_id(), "Cannot map TX frequency to band: " << freq);
+ RFNOC_LOG_ERROR("Cannot map TX frequency to band: " << freq);
break;
default:
UHD_THROW_INVALID_CODE_PATH();
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_gain.cpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_control_gain.cpp
index b66bd2efd..f515b2e33 100644
--- a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_gain.cpp
+++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_control_gain.cpp
@@ -6,63 +6,62 @@
#include "magnesium_constants.hpp"
#include "magnesium_gain_table.hpp"
-#include "magnesium_radio_ctrl_impl.hpp"
-#include <uhd/exception.hpp>
+#include "magnesium_radio_control.hpp"
#include <uhd/utils/log.hpp>
+#include <uhd/exception.hpp>
using namespace uhd;
using namespace uhd::usrp;
using namespace uhd::rfnoc;
using namespace magnesium;
-double magnesium_radio_ctrl_impl::_set_all_gain(
+double magnesium_radio_control_impl::_set_all_gain(
const double gain, const double freq, const size_t chan, const direction_t dir)
{
- UHD_LOG_TRACE(unique_id(),
- __func__ << "(gain=" << gain
- << "dB, "
- "freq="
- << freq
- << " Hz, "
- "chan="
- << chan
- << ", "
- "dir="
- << dir << ")");
+ RFNOC_LOG_TRACE(__func__ << "(gain=" << gain
+ << "dB, "
+ "freq="
+ << freq
+ << " Hz, "
+ "chan="
+ << chan
+ << ", "
+ "dir="
+ << dir);
const size_t ad9371_chan = chan;
auto chan_sel = static_cast<magnesium_cpld_ctrl::chan_sel_t>(chan);
gain_tuple_t gain_tuple;
std::string gp = _gain_profile[dir];
- UHD_LOG_TRACE(unique_id(), "Gain profile: " << gp);
+ RFNOC_LOG_TRACE("Gain profile: " << gp);
if (gp == "manual") {
- UHD_LOG_TRACE(unique_id(), "Manual gain mode. Getting gain from property tree.");
+ RFNOC_LOG_TRACE("Manual gain mode. Getting gain from property tree.");
gain_tuple = {DSA_MAX_GAIN - _dsa_att[dir],
((dir == RX_DIRECTION) ? AD9371_MAX_RX_GAIN : AD9371_MAX_TX_GAIN)
- _ad9371_att[dir],
_amp_bypass[dir]};
} else if (gp.find("default") != gp.npos) {
- UHD_LOG_TRACE(unique_id(), "Getting gain from gain table.");
+ RFNOC_LOG_TRACE("Getting gain from gain table.");
gain_tuple =
(dir == RX_DIRECTION)
? get_rx_gain_tuple(gain, _map_freq_to_rx_band(_rx_band_map, freq))
: get_tx_gain_tuple(gain, _map_freq_to_tx_band(_tx_band_map, freq));
if (gp == "default_rf_filter_bypass_always_on") {
- UHD_LOG_TRACE(unique_id(), "Enable filter bypass for all gains");
+ RFNOC_LOG_TRACE("Enable filter bypass for all gains");
gain_tuple.bypass = true;
} else if (gp == "default_rf_filter_bypass_always_off") {
- UHD_LOG_TRACE(unique_id(), "Disable filter bypass for all gains");
+ RFNOC_LOG_TRACE("Disable filter bypass for all gains");
gain_tuple.bypass = false;
}
} else {
- UHD_LOG_ERROR(unique_id(), "Unsupported gain mode: " << gp);
+ RFNOC_LOG_ERROR("Unsupported gain mode: " << gp);
throw uhd::value_error(
- str(boost::format("[%s] Unsupported gain mode: %s") % unique_id() % gp));
+ str(boost::format("[%s] Unsupported gain mode: %s") % get_unique_id() % gp));
}
const double ad9371_gain =
((dir == RX_DIRECTION) ? AD9371_MAX_RX_GAIN : AD9371_MAX_TX_GAIN)
- gain_tuple.ad9371_att;
- UHD_LOG_TRACE(unique_id(),
+ RFNOC_LOG_TRACE(
"AD9371 attenuation==" << gain_tuple.ad9371_att
<< " dB, "
"AD9371 gain=="
@@ -86,10 +85,10 @@ double magnesium_radio_ctrl_impl::_set_all_gain(
return gain;
}
-double magnesium_radio_ctrl_impl::_get_all_gain(
+double magnesium_radio_control_impl::_get_all_gain(
const size_t /* chan */, const direction_t dir)
{
- UHD_LOG_TRACE(unique_id(), "Getting all gain ");
+ RFNOC_LOG_TRACE("_get_all_gain()");
if (dir == RX_DIRECTION) {
return _all_rx_gain;
}
@@ -99,11 +98,12 @@ double magnesium_radio_ctrl_impl::_get_all_gain(
/******************************************************************************
* DSA Controls
*****************************************************************************/
-double magnesium_radio_ctrl_impl::_dsa_set_att(
+double magnesium_radio_control_impl::_dsa_set_att(
const double att, const size_t chan, const direction_t dir)
{
- UHD_LOG_TRACE(unique_id(),
- __func__ << "(att=" << att << "dB, chan=" << chan << ", dir=" << dir << ")")
+ RFNOC_LOG_TRACE(
+ __func__ << "(att="
+ << "att dB, chan=" << chan << ", dir=" << dir << ")")
const uint32_t dsa_val = 2 * att;
_set_dsa_val(chan, dir, dsa_val);
@@ -116,7 +116,7 @@ double magnesium_radio_ctrl_impl::_dsa_set_att(
return att;
}
-double magnesium_radio_ctrl_impl::_dsa_get_att(
+double magnesium_radio_control_impl::_dsa_get_att(
const size_t /*chan*/, const direction_t dir)
{
if (dir == RX_DIRECTION) {
@@ -125,21 +125,19 @@ double magnesium_radio_ctrl_impl::_dsa_get_att(
return _dsa_tx_att;
}
-void magnesium_radio_ctrl_impl::_set_dsa_val(
+void magnesium_radio_control_impl::_set_dsa_val(
const size_t chan, const direction_t dir, const uint32_t dsa_val)
{
// The DSA register holds 12 bits. The lower 6 bits are for RX, the upper
// 6 bits are for TX.
if (dir == RX_DIRECTION or dir == DX_DIRECTION) {
- UHD_LOG_TRACE(unique_id(),
- __func__ << "(chan=" << chan << ", dir=RX"
- << ", dsa_val=" << dsa_val << ")")
+ RFNOC_LOG_TRACE(__func__ << "(chan=" << chan << ", dir=RX"
+ << ", dsa_val=" << dsa_val << ")")
_gpio[chan]->set_gpio_out(dsa_val, 0x003F);
}
if (dir == TX_DIRECTION or dir == DX_DIRECTION) {
- UHD_LOG_TRACE(unique_id(),
- __func__ << "(chan=" << chan << ", dir=TX"
- << ", dsa_val=" << dsa_val << ")")
+ RFNOC_LOG_TRACE(__func__ << "(chan=" << chan << ", dir=TX"
+ << ", dsa_val=" << dsa_val << ")")
_gpio[chan]->set_gpio_out(dsa_val << 6, 0x0FC0);
}
}
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_control_init.cpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_control_init.cpp
new file mode 100644
index 000000000..db2ec9494
--- /dev/null
+++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_control_init.cpp
@@ -0,0 +1,446 @@
+//
+// Copyright 2017 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#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>
+#include <uhdlib/usrp/cores/spi_core_3000.hpp>
+#include <uhdlib/rfnoc/reg_iface_adapter.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/case_conv.hpp>
+#include <boost/algorithm/string/split.hpp>
+#include <boost/make_shared.hpp>
+#include <string>
+#include <vector>
+
+using namespace uhd;
+using namespace uhd::rfnoc;
+
+namespace {
+
+enum slave_select_t { SEN_CPLD = 1, SEN_TX_LO = 2, SEN_RX_LO = 4, SEN_PHASE_DAC = 8 };
+
+constexpr double MAGNESIUM_DEFAULT_FREQ = 2.5e9; // Hz
+constexpr double MAGNESIUM_DEFAULT_BANDWIDTH = 100e6; // Hz
+
+} // namespace
+
+void magnesium_radio_control_impl::_init_defaults()
+{
+ RFNOC_LOG_TRACE("_init_defaults()");
+ for (size_t chan = 0; chan < get_num_output_ports(); chan++) {
+ radio_control_impl::set_rx_frequency(MAGNESIUM_DEFAULT_FREQ, chan);
+ radio_control_impl::set_rx_gain(0, chan);
+ radio_control_impl::set_rx_antenna(MAGNESIUM_DEFAULT_RX_ANTENNA, chan);
+ radio_control_impl::set_rx_bandwidth(MAGNESIUM_DEFAULT_BANDWIDTH, chan);
+ }
+
+ for (size_t chan = 0; chan < get_num_input_ports(); chan++) {
+ radio_control_impl::set_tx_frequency(MAGNESIUM_DEFAULT_FREQ, chan);
+ radio_control_impl::set_tx_gain(0, chan);
+ radio_control_impl::set_tx_antenna(MAGNESIUM_DEFAULT_TX_ANTENNA, chan);
+ radio_control_impl::set_tx_bandwidth(MAGNESIUM_DEFAULT_BANDWIDTH, chan);
+ }
+
+ const auto block_args = get_block_args();
+ if (block_args.has_key("tx_gain_profile")) {
+ RFNOC_LOG_INFO("Using user specified TX gain profile: " << block_args.get(
+ "tx_gain_profile"));
+ _gain_profile[TX_DIRECTION] = block_args.get("tx_gain_profile");
+ }
+
+ if (block_args.has_key("rx_gain_profile")) {
+ RFNOC_LOG_INFO("Using user specified RX gain profile: " << block_args.get(
+ "rx_gain_profile"));
+ _gain_profile[RX_DIRECTION] = block_args.get("rx_gain_profile");
+ }
+
+ if (block_args.has_key("rx_band_map")) {
+ RFNOC_LOG_INFO("Using user specified RX band limits");
+ _remap_band_limits(block_args.get("rx_band_map"), RX_DIRECTION);
+ }
+
+ if (block_args.has_key("tx_band_map")) {
+ RFNOC_LOG_INFO("Using user specified TX band limits");
+ _remap_band_limits(block_args.get("tx_band_map"), TX_DIRECTION);
+ }
+}
+
+void magnesium_radio_control_impl::_init_peripherals()
+{
+ RFNOC_LOG_TRACE("Initializing peripherals...");
+ RFNOC_LOG_TRACE("Initializing SPI core...");
+ _spi = spi_core_3000::make(
+ [this](uint32_t addr, uint32_t data){ regs().poke32(addr, data, get_command_time(0)); },
+ [this](uint32_t addr){ return regs().peek32(addr, get_command_time(0)); },
+ regmap::REG_SPI_W,
+ 8,
+ regmap::REG_SPI_R);
+ RFNOC_LOG_TRACE("Initializing CPLD...");
+ RFNOC_LOG_TRACE("Creating new CPLD object...");
+ spi_config_t spi_config;
+ spi_config.use_custom_divider = true;
+ spi_config.divider = 125;
+ spi_config.mosi_edge = spi_config_t::EDGE_RISE;
+ spi_config.miso_edge = spi_config_t::EDGE_FALL;
+ RFNOC_LOG_TRACE("Making CPLD object...");
+ _cpld = std::make_shared<magnesium_cpld_ctrl>(
+ [this, spi_config](const uint32_t transaction) { // Write functor
+ this->_spi->write_spi(SEN_CPLD, spi_config, transaction, 24);
+ },
+ [this, spi_config](const uint32_t transaction) { // Read functor
+ return this->_spi->read_spi(SEN_CPLD, spi_config, transaction, 24);
+ });
+ _update_atr_switches(
+ magnesium_cpld_ctrl::BOTH, DX_DIRECTION, radio_control_impl::get_rx_antenna(0));
+ RFNOC_LOG_TRACE("Initializing TX LO...");
+ _tx_lo = adf435x_iface::make_adf4351([this](
+ const std::vector<uint32_t> transactions) {
+ for (const uint32_t transaction : transactions) {
+ this->_spi->write_spi(SEN_TX_LO, spi_config_t::EDGE_RISE, transaction, 32);
+ }
+ });
+ RFNOC_LOG_TRACE("Initializing RX LO...");
+ _rx_lo = adf435x_iface::make_adf4351([this](
+ const std::vector<uint32_t> transactions) {
+ for (const uint32_t transaction : transactions) {
+ this->_spi->write_spi(SEN_RX_LO, spi_config_t::EDGE_RISE, transaction, 32);
+ }
+ });
+
+ _gpio.clear(); // Following the as-if rule, this can get optimized out
+ for (size_t radio_idx = 0; radio_idx < get_num_input_ports(); radio_idx++) {
+ _wb_ifaces.push_back(RFNOC_MAKE_WB_IFACE(0, radio_idx));
+ RFNOC_LOG_TRACE("Initializing GPIOs for channel " << radio_idx);
+ _gpio.emplace_back(usrp::gpio_atr::gpio_atr_3000::make(
+ _wb_ifaces.back(),
+ n310_regs::DB_GPIO_BASE + radio_idx * n310_regs::DB_GPIO_OFFSET,
+ n310_regs::DB_GPIO_RB + radio_idx * n310_regs::DB_GPIO_OFFSET));
+ // DSA and AD9371 gain bits do *not* toggle on ATR modes. If we ever
+ // connect anything else to this core, we might need to set_atr_mode()
+ // to MODE_ATR on those bits. For now, all bits simply do what they're
+ // told, and don't toggle on RX/TX state changes.
+ _gpio.back()->set_atr_mode(usrp::gpio_atr::MODE_GPIO, // Disable ATR mode
+ usrp::gpio_atr::gpio_atr_3000::MASK_SET_ALL);
+ _gpio.back()->set_gpio_ddr(usrp::gpio_atr::DDR_OUTPUT, // Make all GPIOs outputs
+ usrp::gpio_atr::gpio_atr_3000::MASK_SET_ALL);
+ }
+ RFNOC_LOG_TRACE("Initializing front-panel GPIO control...")
+ _fp_gpio = usrp::gpio_atr::gpio_atr_3000::make(_wb_ifaces.front(),
+ n310_regs::FP_GPIO, n310_regs::RB_FP_GPIO);
+}
+
+void magnesium_radio_control_impl::_init_frontend_subtree(
+ uhd::property_tree::sptr subtree, const size_t chan_idx)
+{
+ const fs_path tx_fe_path = fs_path("tx_frontends") / chan_idx;
+ const fs_path rx_fe_path = fs_path("rx_frontends") / chan_idx;
+ RFNOC_LOG_TRACE("Adding non-RFNoC block properties for channel "
+ << chan_idx << " to prop tree path " << tx_fe_path << " and "
+ << rx_fe_path);
+ // TX Standard attributes
+ subtree->create<std::string>(tx_fe_path / "name").set(get_fe_name(chan_idx, TX_DIRECTION));
+ subtree->create<std::string>(tx_fe_path / "connection").set("IQ");
+ // RX Standard attributes
+ subtree->create<std::string>(rx_fe_path / "name").set(get_fe_name(chan_idx, RX_DIRECTION));
+ subtree->create<std::string>(rx_fe_path / "connection").set("IQ");
+ // TX Antenna
+ subtree->create<std::string>(tx_fe_path / "antenna" / "value")
+ .add_coerced_subscriber([this, chan_idx](const std::string& ant) {
+ this->set_tx_antenna(ant, chan_idx);
+ })
+ .set_publisher([this, chan_idx]() { return this->get_tx_antenna(chan_idx); });
+ subtree->create<std::vector<std::string>>(tx_fe_path / "antenna" / "options")
+ .set_publisher([this](){ return get_tx_antennas(0); })
+ .add_coerced_subscriber([](const std::vector<std::string>&) {
+ throw uhd::runtime_error("Attempting to update antenna options!");
+ });
+ // RX Antenna
+ subtree->create<std::string>(rx_fe_path / "antenna" / "value")
+ .add_coerced_subscriber([this, chan_idx](const std::string& ant) {
+ this->set_rx_antenna(ant, chan_idx);
+ })
+ .set_publisher([this, chan_idx]() { return this->get_rx_antenna(chan_idx); });
+ subtree->create<std::vector<std::string>>(rx_fe_path / "antenna" / "options")
+ .set_publisher([this](){ return get_rx_antennas(0); })
+ .add_coerced_subscriber([](const std::vector<std::string>&) {
+ throw uhd::runtime_error("Attempting to update antenna options!");
+ });
+ // TX frequency
+ subtree->create<double>(tx_fe_path / "freq" / "value")
+ .set_coercer([this, chan_idx](const double freq) {
+ return this->set_tx_frequency(freq, chan_idx);
+ })
+ .set_publisher([this, chan_idx]() { return this->get_tx_frequency(chan_idx); });
+ subtree->create<meta_range_t>(tx_fe_path / "freq" / "range")
+ .set_publisher([this, chan_idx](){ return get_tx_frequency_range(chan_idx); })
+ .add_coerced_subscriber([](const meta_range_t&) {
+ throw uhd::runtime_error("Attempting to update freq range!");
+ });
+ // RX frequency
+ subtree->create<double>(rx_fe_path / "freq" / "value")
+ .set_coercer([this, chan_idx](const double freq) {
+ return this->set_rx_frequency(freq, chan_idx);
+ })
+ .set_publisher([this, chan_idx]() { return this->get_rx_frequency(chan_idx); });
+ subtree->create<meta_range_t>(rx_fe_path / "freq" / "range")
+ .set_publisher([this, chan_idx](){ return get_rx_frequency_range(chan_idx); })
+ .add_coerced_subscriber([](const meta_range_t&) {
+ throw uhd::runtime_error("Attempting to update freq range!");
+ });
+ // TX bandwidth
+ subtree->create<double>(tx_fe_path / "bandwidth" / "value")
+ .set(AD9371_TX_MAX_BANDWIDTH)
+ .set_coercer([this, chan_idx](const double bw) {
+ return this->set_tx_bandwidth(bw, chan_idx);
+ })
+ .set_publisher([this, chan_idx]() { return this->get_tx_bandwidth(chan_idx); });
+ subtree->create<meta_range_t>(tx_fe_path / "bandwidth" / "range")
+ .set_publisher([this, chan_idx](){ return get_tx_bandwidth_range(chan_idx); })
+ .add_coerced_subscriber([](const meta_range_t&) {
+ throw uhd::runtime_error("Attempting to update bandwidth range!");
+ });
+ // RX bandwidth
+ subtree->create<double>(rx_fe_path / "bandwidth" / "value")
+ .set(AD9371_RX_MAX_BANDWIDTH)
+ .set_coercer([this, chan_idx](const double bw) {
+ return this->set_rx_bandwidth(bw, chan_idx);
+ })
+ .set_publisher([this, chan_idx]() { return this->get_rx_bandwidth(chan_idx); });
+ subtree->create<meta_range_t>(rx_fe_path / "bandwidth" / "range")
+ .set_publisher([this, chan_idx](){ return get_rx_bandwidth_range(chan_idx); })
+ .add_coerced_subscriber([](const meta_range_t&) {
+ throw uhd::runtime_error("Attempting to update bandwidth range!");
+ });
+
+ // TX gains
+ std::vector<std::string> tx_gain_names = get_tx_gain_names(chan_idx);
+ tx_gain_names.push_back("all");
+ for (const auto gain_name : tx_gain_names) {
+ subtree->create<double>(tx_fe_path / "gains" / gain_name / "value")
+ .set_coercer([this, chan_idx, gain_name](const double gain) {
+ return this->set_tx_gain(gain, gain_name, chan_idx);
+ })
+ .set_publisher(
+ [this, chan_idx, gain_name]() { return get_tx_gain(gain_name, chan_idx); });
+ subtree->create<meta_range_t>(tx_fe_path / "gains" / gain_name / "range")
+ .add_coerced_subscriber([](const meta_range_t&) {
+ throw uhd::runtime_error("Attempting to update gain range!");
+ })
+ .set_publisher([this, gain_name, chan_idx]() { return get_tx_gain_range(gain_name, chan_idx); });
+ }
+ subtree->create<std::vector<std::string>>(tx_fe_path / "gains/all/profile/options")
+ .set_publisher(
+ [this, chan_idx]() { return get_tx_gain_profile_names(chan_idx); });
+ subtree->create<std::string>(tx_fe_path / "gains/all/profile/value")
+ .set_coercer([this, chan_idx](const std::string& profile) {
+ set_tx_gain_profile(profile, chan_idx);
+ return profile;
+ })
+ .set_publisher([this, chan_idx]() { return get_tx_gain_profile(chan_idx); });
+
+ // RX gains
+ std::vector<std::string> rx_gain_names = get_rx_gain_names(chan_idx);
+ rx_gain_names.push_back("all");
+ for (const auto gain_name : rx_gain_names) {
+ subtree->create<double>(rx_fe_path / "gains" / gain_name / "value")
+ .set_coercer([this, chan_idx, gain_name](const double gain) {
+ return this->set_rx_gain(gain, gain_name, chan_idx);
+ })
+ .set_publisher(
+ [this, chan_idx, gain_name]() { return get_rx_gain(gain_name, chan_idx); });
+ subtree->create<meta_range_t>(rx_fe_path / "gains" / gain_name / "range")
+ .add_coerced_subscriber([](const meta_range_t&) {
+ throw uhd::runtime_error("Attempting to update gain range!");
+ })
+ .set_publisher([this, gain_name, chan_idx]() { return get_rx_gain_range(gain_name, chan_idx); });
+ }
+ subtree->create<std::vector<std::string>>(rx_fe_path / "gains/all/profile/options")
+ .set_publisher(
+ [this, chan_idx]() { return get_rx_gain_profile_names(chan_idx); });
+ subtree->create<std::string>(rx_fe_path / "gains/all/profile/value")
+ .set_coercer([this, chan_idx](const std::string& profile) {
+ set_rx_gain_profile(profile, chan_idx);
+ return profile;
+ })
+ .set_publisher([this, chan_idx]() { return get_rx_gain_profile(chan_idx); });
+
+ // LO Specific
+ // RX LO
+ subtree->create<meta_range_t>(rx_fe_path / "los" / MAGNESIUM_LO1 / "freq/range")
+ .set_publisher([this, chan_idx]() {
+ return this->get_rx_lo_freq_range(MAGNESIUM_LO1, chan_idx);
+ });
+ subtree
+ ->create<std::vector<std::string>>(
+ rx_fe_path / "los" / MAGNESIUM_LO1 / "source/options")
+ .set_publisher([this, chan_idx]() {
+ return this->get_rx_lo_sources(MAGNESIUM_LO1, chan_idx);
+ });
+ subtree->create<std::string>(rx_fe_path / "los" / MAGNESIUM_LO1 / "source/value")
+ .add_coerced_subscriber([this, chan_idx](std::string src) {
+ this->set_rx_lo_source(src, MAGNESIUM_LO1, chan_idx);
+ })
+ .set_publisher([this, chan_idx]() {
+ return this->get_rx_lo_source(MAGNESIUM_LO1, chan_idx);
+ });
+ subtree->create<double>(rx_fe_path / "los" / MAGNESIUM_LO1 / "freq/value")
+ .set_publisher(
+ [this, chan_idx]() { return this->get_rx_lo_freq(MAGNESIUM_LO1, chan_idx); })
+ .set_coercer([this, chan_idx](const double freq) {
+ return this->set_rx_lo_freq(freq, MAGNESIUM_LO1, chan_idx);
+ });
+ subtree->create<meta_range_t>(rx_fe_path / "los" / MAGNESIUM_LO2 / "freq/range")
+ .set_publisher([this, chan_idx]() {
+ return this->get_rx_lo_freq_range(MAGNESIUM_LO2, chan_idx);
+ });
+ subtree
+ ->create<std::vector<std::string>>(
+ rx_fe_path / "los" / MAGNESIUM_LO2 / "source/options")
+ .set_publisher([this, chan_idx]() {
+ return this->get_rx_lo_sources(MAGNESIUM_LO2, chan_idx);
+ });
+
+ subtree->create<std::string>(rx_fe_path / "los" / MAGNESIUM_LO2 / "source/value")
+ .add_coerced_subscriber([this, chan_idx](std::string src) {
+ this->set_rx_lo_source(src, MAGNESIUM_LO2, chan_idx);
+ })
+ .set_publisher([this, chan_idx]() {
+ return this->get_rx_lo_source(MAGNESIUM_LO2, chan_idx);
+ });
+ subtree->create<double>(rx_fe_path / "los" / MAGNESIUM_LO2 / "freq/value")
+ .set_publisher(
+ [this, chan_idx]() { return this->get_rx_lo_freq(MAGNESIUM_LO2, chan_idx); })
+ .set_coercer([this, chan_idx](double freq) {
+ return this->set_rx_lo_freq(freq, MAGNESIUM_LO2, chan_idx);
+ });
+ // TX LO
+ subtree->create<meta_range_t>(tx_fe_path / "los" / MAGNESIUM_LO1 / "freq/range")
+ .set_publisher([this, chan_idx]() {
+ return this->get_rx_lo_freq_range(MAGNESIUM_LO1, chan_idx);
+ });
+ subtree
+ ->create<std::vector<std::string>>(
+ tx_fe_path / "los" / MAGNESIUM_LO1 / "source/options")
+ .set_publisher([this, chan_idx]() {
+ return this->get_tx_lo_sources(MAGNESIUM_LO1, chan_idx);
+ });
+ subtree->create<std::string>(tx_fe_path / "los" / MAGNESIUM_LO1 / "source/value")
+ .add_coerced_subscriber([this, chan_idx](std::string src) {
+ this->set_tx_lo_source(src, MAGNESIUM_LO1, chan_idx);
+ })
+ .set_publisher([this, chan_idx]() {
+ return this->get_tx_lo_source(MAGNESIUM_LO1, chan_idx);
+ });
+ subtree->create<double>(tx_fe_path / "los" / MAGNESIUM_LO1 / "freq/value ")
+ .set_publisher(
+ [this, chan_idx]() { return this->get_tx_lo_freq(MAGNESIUM_LO1, chan_idx); })
+ .set_coercer([this, chan_idx](double freq) {
+ return this->set_tx_lo_freq(freq, MAGNESIUM_LO1, chan_idx);
+ });
+ subtree->create<meta_range_t>(tx_fe_path / "los" / MAGNESIUM_LO2 / "freq/range")
+ .set_publisher([this, chan_idx]() {
+ return this->get_tx_lo_freq_range(MAGNESIUM_LO2, chan_idx);
+ });
+ subtree
+ ->create<std::vector<std::string>>(
+ tx_fe_path / "los" / MAGNESIUM_LO2 / "source/options")
+ .set_publisher([this, chan_idx]() {
+ return this->get_tx_lo_sources(MAGNESIUM_LO2, chan_idx);
+ });
+ subtree->create<std::string>(tx_fe_path / "los" / MAGNESIUM_LO2 / "source/value")
+ .add_coerced_subscriber([this, chan_idx](std::string src) {
+ this->set_tx_lo_source(src, MAGNESIUM_LO2, chan_idx);
+ })
+ .set_publisher([this, chan_idx]() {
+ return this->get_tx_lo_source(MAGNESIUM_LO2, chan_idx);
+ });
+ subtree->create<double>(tx_fe_path / "los" / MAGNESIUM_LO2 / "freq/value")
+ .set_publisher(
+ [this, chan_idx]() { return this->get_tx_lo_freq(MAGNESIUM_LO2, chan_idx); })
+ .set_coercer([this, chan_idx](double freq) {
+ return this->set_tx_lo_freq(freq, MAGNESIUM_LO2, chan_idx);
+ });
+
+ // Sensors
+ auto rx_sensor_names = get_rx_sensor_names(chan_idx);
+ for (const auto& sensor_name : rx_sensor_names) {
+ RFNOC_LOG_TRACE("Adding RX sensor " << sensor_name);
+ get_tree()->create<sensor_value_t>(rx_fe_path / "sensors" / sensor_name)
+ .add_coerced_subscriber([](const sensor_value_t&) {
+ throw uhd::runtime_error("Attempting to write to sensor!");
+ })
+ .set_publisher([this, sensor_name, chan_idx]() {
+ return get_rx_sensor(sensor_name, chan_idx);
+ });
+ }
+ auto tx_sensor_names = get_tx_sensor_names(chan_idx);
+ for (const auto& sensor_name : tx_sensor_names) {
+ RFNOC_LOG_TRACE("Adding TX sensor " << sensor_name);
+ get_tree()->create<sensor_value_t>(tx_fe_path / "sensors" / sensor_name)
+ .add_coerced_subscriber([](const sensor_value_t&) {
+ throw uhd::runtime_error("Attempting to write to sensor!");
+ })
+ .set_publisher([this, sensor_name, chan_idx]() {
+ return get_tx_sensor(sensor_name, chan_idx);
+ });
+ }
+}
+
+void magnesium_radio_control_impl::_init_prop_tree()
+{
+ for (size_t chan_idx = 0; chan_idx < MAGNESIUM_NUM_CHANS; chan_idx++) {
+ this->_init_frontend_subtree(get_tree()->subtree(DB_PATH), chan_idx);
+ }
+
+ // DB EEPROM
+ get_tree()->create<eeprom_map_t>("eeprom")
+ .add_coerced_subscriber(
+ [this](const eeprom_map_t& db_eeprom) { set_db_eeprom(db_eeprom); })
+ .set_publisher([this]() { return get_db_eeprom(); });
+}
+
+void magnesium_radio_control_impl::_init_mpm()
+{
+ auto block_args = get_block_args();
+ RFNOC_LOG_TRACE("Instantiating AD9371 control object...");
+ _ad9371 = magnesium_ad9371_iface::uptr(
+ new magnesium_ad9371_iface(_rpcc, (_radio_slot == "A") ? 0 : 1));
+
+ if (block_args.has_key("identify")) {
+ const std::string identify_val = block_args.get("identify");
+ int identify_duration = std::atoi(identify_val.c_str());
+ if (identify_duration == 0) {
+ identify_duration = 5;
+ }
+ RFNOC_LOG_INFO("Running LED identification process for " << identify_duration
+ << " seconds.");
+ _identify_with_leds(identify_duration);
+ }
+
+ // Note: MCR gets set during the init() call (prior to this), which takes
+ // in arguments from the device args. So if block_args contains a
+ // master_clock_rate key, then it should better be whatever the device is
+ // configured to do.
+ _master_clock_rate =
+ _rpcc->request_with_token<double>(_rpc_prefix + "get_master_clock_rate");
+ if (block_args.cast<double>("master_clock_rate", _master_clock_rate)
+ != _master_clock_rate) {
+ throw uhd::runtime_error(str(
+ boost::format("Master clock rate mismatch. Device returns %f MHz, "
+ "but should have been %f MHz.")
+ % (_master_clock_rate / 1e6)
+ % (block_args.cast<double>("master_clock_rate", _master_clock_rate) / 1e6)));
+ }
+ RFNOC_LOG_DEBUG("Master Clock Rate is: " << (_master_clock_rate / 1e6) << " MHz.");
+ set_tick_rate(_master_clock_rate);
+ _n3xx_timekeeper->update_tick_rate(_master_clock_rate);
+ radio_control_impl::set_rate(_master_clock_rate);
+}
+
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.cpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.cpp
deleted file mode 100644
index 405d5955e..000000000
--- a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.cpp
+++ /dev/null
@@ -1,847 +0,0 @@
-//
-// Copyright 2017 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include "magnesium_radio_ctrl_impl.hpp"
-#include "magnesium_constants.hpp"
-#include "magnesium_gain_table.hpp"
-#include <uhd/exception.hpp>
-#include <uhd/rfnoc/node_ctrl_base.hpp>
-#include <uhd/transport/chdr.hpp>
-#include <uhd/types/direction.hpp>
-#include <uhd/types/eeprom.hpp>
-#include <uhd/utils/algorithm.hpp>
-#include <uhd/utils/log.hpp>
-#include <uhd/utils/math.hpp>
-#include <boost/algorithm/string.hpp>
-#include <boost/format.hpp>
-#include <boost/make_shared.hpp>
-#include <cmath>
-#include <cstdlib>
-#include <sstream>
-
-using namespace uhd;
-using namespace uhd::usrp;
-using namespace uhd::rfnoc;
-using namespace uhd::math::fp_compare;
-
-namespace {
-/**************************************************************************
- * ADF4351 Controls
- *************************************************************************/
-/*!
- * \param lo_iface Reference to the LO object
- * \param freq Frequency (in Hz) of the tone to be generated from the LO
- * \param ref_clock_freq Frequency (in Hz) of the reference clock at the
- * PLL input of the LO
- * \param int_n_mode Integer-N mode on or off
- */
-double _lo_set_frequency(adf435x_iface::sptr lo_iface,
- const double freq,
- const double ref_clock_freq,
- const bool int_n_mode)
-{
- UHD_LOG_TRACE("MG/ADF4351",
- "Attempting to tune low band LO to " << freq << " Hz with ref clock freq "
- << ref_clock_freq);
- lo_iface->set_feedback_select(adf435x_iface::FB_SEL_DIVIDED);
- lo_iface->set_reference_freq(ref_clock_freq);
- lo_iface->set_prescaler(adf435x_iface::PRESCALER_4_5);
- const double actual_freq = lo_iface->set_frequency(freq, int_n_mode);
- lo_iface->set_output_power(
- adf435x_iface::RF_OUTPUT_A, adf435x_iface::OUTPUT_POWER_2DBM);
- lo_iface->set_output_power(
- adf435x_iface::RF_OUTPUT_B, adf435x_iface::OUTPUT_POWER_2DBM);
- lo_iface->set_charge_pump_current(adf435x_iface::CHARGE_PUMP_CURRENT_0_31MA);
- return actual_freq;
-}
-
-/*! Configure and enable LO
- *
- * Will tune it to requested frequency and enable outputs.
- *
- * \param lo_iface Reference to the LO object
- * \param lo_freq Frequency (in Hz) of the tone to be generated from the LO
- * \param ref_clock_freq Frequency (in Hz) of the reference clock at the
- * PLL input of the LO
- * \param int_n_mode Integer-N mode on or off
- * \returns the actual frequency the LO is running at
- */
-double _lo_enable(adf435x_iface::sptr lo_iface,
- const double lo_freq,
- const double ref_clock_freq,
- const bool int_n_mode)
-{
- const double actual_lo_freq =
- _lo_set_frequency(lo_iface, lo_freq, ref_clock_freq, int_n_mode);
- lo_iface->set_output_enable(adf435x_iface::RF_OUTPUT_A, true);
- lo_iface->set_output_enable(adf435x_iface::RF_OUTPUT_B, true);
- lo_iface->commit();
- return actual_lo_freq;
-}
-
-/*! Disable LO
- */
-void _lo_disable(adf435x_iface::sptr lo_iface)
-{
- lo_iface->set_output_enable(adf435x_iface::RF_OUTPUT_A, false);
- lo_iface->set_output_enable(adf435x_iface::RF_OUTPUT_B, false);
- lo_iface->commit();
-}
-} // namespace
-
-
-/******************************************************************************
- * Structors
- *****************************************************************************/
-UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR(magnesium_radio_ctrl)
-{
- UHD_LOG_TRACE(unique_id(), "Entering magnesium_radio_ctrl_impl ctor...");
- const char radio_slot_name[2] = {'A', 'B'};
- _radio_slot = radio_slot_name[get_block_id().get_block_count()];
- UHD_LOG_TRACE(unique_id(), "Radio slot: " << _radio_slot);
- _rpc_prefix = (_radio_slot == "A") ? "db_0_" : "db_1_";
-
- _init_defaults();
- _init_peripherals();
- _init_prop_tree();
-}
-
-magnesium_radio_ctrl_impl::~magnesium_radio_ctrl_impl()
-{
- UHD_LOG_TRACE(unique_id(), "magnesium_radio_ctrl_impl::dtor() ");
-}
-
-
-/******************************************************************************
- * API Calls
- *****************************************************************************/
-double magnesium_radio_ctrl_impl::set_rate(double requested_rate)
-{
- meta_range_t rates;
- for (const double rate : MAGNESIUM_RADIO_RATES) {
- rates.push_back(range_t(rate));
- }
-
- const double rate = rates.clip(requested_rate);
- if (!math::frequencies_are_equal(requested_rate, rate)) {
- UHD_LOG_WARNING(unique_id(),
- "Coercing requested sample rate from " << (requested_rate / 1e6) << " to "
- << (rate / 1e6));
- }
-
- const double current_rate = get_rate();
- if (math::frequencies_are_equal(current_rate, rate)) {
- UHD_LOG_DEBUG(
- unique_id(), "Rate is already at " << rate << ". Skipping set_rate()");
- return current_rate;
- }
-
- std::lock_guard<std::mutex> l(_set_lock);
- // Now commit to device. First, disable LOs.
- _lo_disable(_tx_lo);
- _lo_disable(_rx_lo);
- const double new_rate = _ad9371->set_master_clock_rate(rate);
- // Frequency settings apply to both channels, no loop needed. Will also
- // re-enable the lowband LOs if they were used.
- set_rx_frequency(get_rx_frequency(0), 0);
- set_tx_frequency(get_tx_frequency(0), 0);
- // Gain and bandwidth need to be looped:
- for (size_t radio_idx = 0; radio_idx < _get_num_radios(); radio_idx++) {
- set_rx_gain(get_rx_gain(radio_idx), radio_idx);
- set_tx_gain(get_rx_gain(radio_idx), radio_idx);
- set_rx_bandwidth(get_rx_bandwidth(radio_idx), radio_idx);
- set_tx_bandwidth(get_tx_bandwidth(radio_idx), radio_idx);
- }
- radio_ctrl_impl::set_rate(new_rate);
- return new_rate;
-}
-
-void magnesium_radio_ctrl_impl::set_tx_antenna(const std::string& ant, const size_t chan)
-{
- if (ant != get_tx_antenna(chan)) {
- throw uhd::value_error(
- str(boost::format("[%s] Requesting invalid TX antenna value: %s")
- % unique_id() % ant));
- }
- // We can't actually set the TX antenna, so let's stop here.
-}
-
-void magnesium_radio_ctrl_impl::set_rx_antenna(const std::string& ant, const size_t chan)
-{
- UHD_ASSERT_THROW(chan <= MAGNESIUM_NUM_CHANS);
- if (std::find(MAGNESIUM_RX_ANTENNAS.begin(), MAGNESIUM_RX_ANTENNAS.end(), ant)
- == MAGNESIUM_RX_ANTENNAS.end()) {
- throw uhd::value_error(
- str(boost::format("[%s] Requesting invalid RX antenna value: %s")
- % unique_id() % ant));
- }
- UHD_LOG_TRACE(unique_id(), "Setting RX antenna to " << ant << " for chan " << chan);
- magnesium_cpld_ctrl::chan_sel_t chan_sel = chan == 0 ? magnesium_cpld_ctrl::CHAN1
- : magnesium_cpld_ctrl::CHAN2;
- _update_atr_switches(chan_sel, RX_DIRECTION, ant);
-
- radio_ctrl_impl::set_rx_antenna(ant, chan);
-}
-
-double magnesium_radio_ctrl_impl::set_tx_frequency(
- const double req_freq, const size_t chan)
-{
- const double freq = MAGNESIUM_FREQ_RANGE.clip(req_freq);
- UHD_LOG_TRACE(unique_id(), "set_tx_frequency(f=" << freq << ", chan=" << chan << ")");
- _desired_rf_freq[TX_DIRECTION] = freq;
- std::lock_guard<std::mutex> l(_set_lock);
- // We need to set the switches on both channels, because they share an LO.
- // This way, if we tune channel 0 it will not put channel 1 into a bad
- // state.
- _update_tx_freq_switches(freq, _tx_bypass_amp, magnesium_cpld_ctrl::BOTH);
- const std::string ad9371_source = this->get_tx_lo_source(MAGNESIUM_LO1, chan);
- const std::string adf4351_source = this->get_tx_lo_source(MAGNESIUM_LO2, chan);
- UHD_ASSERT_THROW(adf4351_source == "internal");
- double coerced_if_freq = freq;
-
- if (_map_freq_to_tx_band(_tx_band_map, freq) == tx_band::LOWBAND) {
- _is_low_band[TX_DIRECTION] = true;
- const double desired_low_freq = MAGNESIUM_TX_IF_FREQ - freq;
- coerced_if_freq =
- this->_set_tx_lo_freq(adf4351_source, MAGNESIUM_LO2, desired_low_freq, chan)
- + freq;
- UHD_LOG_TRACE(unique_id(), "coerced_if_freq = " << coerced_if_freq);
- } else {
- _is_low_band[TX_DIRECTION] = false;
- _lo_disable(_tx_lo);
- }
- // external LO required to tune at 2xdesired_frequency.
- const double desired_if_freq = (ad9371_source == "internal") ? coerced_if_freq
- : 2 * coerced_if_freq;
-
- this->_set_tx_lo_freq(ad9371_source, MAGNESIUM_LO1, desired_if_freq, chan);
- this->_update_freq(chan, TX_DIRECTION);
- this->_update_gain(chan, TX_DIRECTION);
- return radio_ctrl_impl::get_tx_frequency(chan);
-}
-
-void magnesium_radio_ctrl_impl::_update_gain(
- const size_t chan, const uhd::direction_t dir)
-{
- const std::string fe = (dir == TX_DIRECTION) ? "tx_frontends" : "rx_frontends";
- const double freq = (dir == TX_DIRECTION) ? this->get_tx_frequency(chan)
- : this->get_rx_frequency(chan);
- this->_set_all_gain(this->_get_all_gain(chan, dir), freq, chan, dir);
-}
-
-void magnesium_radio_ctrl_impl::_update_freq(
- const size_t chan, const uhd::direction_t dir)
-{
- const std::string ad9371_source = dir == TX_DIRECTION
- ? this->get_tx_lo_source(MAGNESIUM_LO1, chan)
- : this->get_rx_lo_source(MAGNESIUM_LO1, chan);
-
- const double ad9371_freq = ad9371_source == "external" ? _ad9371_freq[dir] / 2
- : _ad9371_freq[dir];
- const double rf_freq = _is_low_band[dir] ? ad9371_freq - _adf4351_freq[dir]
- : ad9371_freq;
-
- UHD_LOG_TRACE(unique_id(), "RF freq = " << rf_freq);
- UHD_ASSERT_THROW(fp_compare_epsilon<double>(rf_freq) >= 0);
- UHD_ASSERT_THROW(fp_compare_epsilon<double>(std::abs(rf_freq - _desired_rf_freq[dir]))
- <= _master_clock_rate / 2);
- if (dir == RX_DIRECTION) {
- radio_ctrl_impl::set_rx_frequency(rf_freq, chan);
- } else if (dir == TX_DIRECTION) {
- radio_ctrl_impl::set_tx_frequency(rf_freq, chan);
- } else {
- UHD_THROW_INVALID_CODE_PATH();
- }
-}
-
-double magnesium_radio_ctrl_impl::set_rx_frequency(
- const double req_freq, const size_t chan)
-{
- const double freq = MAGNESIUM_FREQ_RANGE.clip(req_freq);
- UHD_LOG_TRACE(unique_id(), "set_rx_frequency(f=" << freq << ", chan=" << chan << ")");
- _desired_rf_freq[RX_DIRECTION] = freq;
- std::lock_guard<std::mutex> l(_set_lock);
- // We need to set the switches on both channels, because they share an LO.
- // This way, if we tune channel 0 it will not put channel 1 into a bad
- // state.
- _update_rx_freq_switches(freq, _rx_bypass_lnas, magnesium_cpld_ctrl::BOTH);
- const std::string ad9371_source = this->get_rx_lo_source(MAGNESIUM_LO1, chan);
- const std::string adf4351_source = this->get_rx_lo_source(MAGNESIUM_LO2, chan);
- UHD_ASSERT_THROW(adf4351_source == "internal");
- double coerced_if_freq = freq;
-
- if (_map_freq_to_rx_band(_rx_band_map, freq) == rx_band::LOWBAND) {
- _is_low_band[RX_DIRECTION] = true;
- const double desired_low_freq = MAGNESIUM_RX_IF_FREQ - freq;
- coerced_if_freq =
- this->_set_rx_lo_freq(adf4351_source, MAGNESIUM_LO2, desired_low_freq, chan)
- + freq;
- UHD_LOG_TRACE(unique_id(), "coerced_if_freq = " << coerced_if_freq);
- } else {
- _is_low_band[RX_DIRECTION] = false;
- _lo_disable(_rx_lo);
- }
- // external LO required to tune at 2xdesired_frequency.
- const double desired_if_freq = ad9371_source == "internal" ? coerced_if_freq
- : 2 * coerced_if_freq;
-
- this->_set_rx_lo_freq(ad9371_source, MAGNESIUM_LO1, desired_if_freq, chan);
-
- this->_update_freq(chan, RX_DIRECTION);
- this->_update_gain(chan, RX_DIRECTION);
-
- return radio_ctrl_impl::get_rx_frequency(chan);
-}
-
-double magnesium_radio_ctrl_impl::get_tx_frequency(const size_t chan)
-{
- UHD_LOG_TRACE(unique_id(), "get_tx_frequency(chan=" << chan << ")");
- return radio_ctrl_impl::get_tx_frequency(chan);
-}
-
-double magnesium_radio_ctrl_impl::get_rx_frequency(const size_t chan)
-{
- UHD_LOG_TRACE(unique_id(), "get_rx_frequency(chan=" << chan << ")");
- return radio_ctrl_impl::get_rx_frequency(chan);
-}
-double magnesium_radio_ctrl_impl::set_rx_bandwidth(
- const double bandwidth, const size_t chan)
-{
- std::lock_guard<std::mutex> l(_set_lock);
- _ad9371->set_bandwidth(bandwidth, chan, RX_DIRECTION);
- // FIXME: setting analog bandwidth on AD9371 take no effect.
- // Remove this warning when ADI can confirm that it works.
- UHD_LOG_WARNING(unique_id(),
- "set_rx_bandwidth take no effect on AD9371. "
- "Default analog bandwidth is 100MHz");
- return AD9371_RX_MAX_BANDWIDTH;
-}
-
-double magnesium_radio_ctrl_impl::set_tx_bandwidth(
- const double bandwidth, const size_t chan)
-{
- std::lock_guard<std::mutex> l(_set_lock);
- _ad9371->set_bandwidth(bandwidth, chan, TX_DIRECTION);
- // FIXME: setting analog bandwidth on AD9371 take no effect.
- // Remove this warning when ADI can confirm that it works.
- UHD_LOG_WARNING(unique_id(),
- "set_tx_bandwidth take no effect on AD9371. "
- "Default analog bandwidth is 100MHz");
- return AD9371_TX_MAX_BANDWIDTH;
-}
-
-double magnesium_radio_ctrl_impl::set_tx_gain(const double gain, const size_t chan)
-{
- std::lock_guard<std::mutex> l(_set_lock);
- UHD_LOG_TRACE(unique_id(), "set_tx_gain(gain=" << gain << ", chan=" << chan << ")");
- const double coerced_gain =
- _set_all_gain(gain, this->get_tx_frequency(chan), chan, TX_DIRECTION);
- radio_ctrl_impl::set_tx_gain(coerced_gain, chan);
- return coerced_gain;
-}
-
-double magnesium_radio_ctrl_impl::_set_tx_gain(
- const std::string& name, const double gain, const size_t chan)
-{
- std::lock_guard<std::mutex> l(_set_lock);
- UHD_LOG_TRACE(unique_id(),
- "_set_tx_gain(name=" << name << ", gain=" << gain << ", chan=" << chan << ")");
- UHD_LOG_TRACE(unique_id(),
- "_set_tx_gain(name=" << name << ", gain=" << gain << ", chan=" << chan << ")");
- double clip_gain = 0;
- if (name == MAGNESIUM_GAIN1) {
- clip_gain = uhd::clip(gain, AD9371_MIN_TX_GAIN, AD9371_MAX_TX_GAIN);
- _ad9371_att[TX_DIRECTION] = clip_gain;
- } else if (name == MAGNESIUM_GAIN2) {
- clip_gain = uhd::clip(gain, DSA_MIN_GAIN, DSA_MAX_GAIN);
- _dsa_att[TX_DIRECTION] = clip_gain;
- } else if (name == MAGNESIUM_AMP) {
- clip_gain = gain > 0.0 ? AMP_MAX_GAIN : AMP_MIN_GAIN;
- _amp_bypass[TX_DIRECTION] = clip_gain == 0.0;
- } else {
- throw uhd::value_error("Could not find gain element " + name);
- }
- UHD_LOG_TRACE(unique_id(), "_set_tx_gain calling update gain");
- this->_set_all_gain(this->_get_all_gain(chan, TX_DIRECTION),
- this->get_tx_frequency(chan),
- chan,
- TX_DIRECTION);
- return clip_gain;
-}
-
-double magnesium_radio_ctrl_impl::_get_tx_gain(
- const std::string& name, const size_t /*chan*/
-)
-{
- std::lock_guard<std::mutex> l(_set_lock);
- if (name == MAGNESIUM_GAIN1) {
- return _ad9371_att[TX_DIRECTION];
- } else if (name == MAGNESIUM_GAIN2) {
- return _dsa_att[TX_DIRECTION];
- } else if (name == MAGNESIUM_AMP) {
- return _amp_bypass[TX_DIRECTION] ? AMP_MIN_GAIN : AMP_MAX_GAIN;
- } else {
- throw uhd::value_error("Could not find gain element " + name);
- }
-}
-
-double magnesium_radio_ctrl_impl::set_rx_gain(const double gain, const size_t chan)
-{
- std::lock_guard<std::mutex> l(_set_lock);
- UHD_LOG_TRACE(unique_id(), "set_rx_gain(gain=" << gain << ", chan=" << chan << ")");
- const double coerced_gain =
- _set_all_gain(gain, this->get_rx_frequency(chan), chan, RX_DIRECTION);
- radio_ctrl_impl::set_rx_gain(coerced_gain, chan);
- return coerced_gain;
-}
-
-double magnesium_radio_ctrl_impl::_set_rx_gain(
- const std::string& name, const double gain, const size_t chan)
-{
- std::lock_guard<std::mutex> l(_set_lock);
- UHD_LOG_TRACE(unique_id(),
- "_set_rx_gain(name=" << name << ", gain=" << gain << ", chan=" << chan << ")");
- double clip_gain = 0;
- if (name == MAGNESIUM_GAIN1) {
- clip_gain = uhd::clip(gain, AD9371_MIN_RX_GAIN, AD9371_MAX_RX_GAIN);
- _ad9371_att[RX_DIRECTION] = clip_gain;
- } else if (name == MAGNESIUM_GAIN2) {
- clip_gain = uhd::clip(gain, DSA_MIN_GAIN, DSA_MAX_GAIN);
- _dsa_att[RX_DIRECTION] = clip_gain;
- } else if (name == MAGNESIUM_AMP) {
- clip_gain = gain > 0.0 ? AMP_MAX_GAIN : AMP_MIN_GAIN;
- _amp_bypass[RX_DIRECTION] = clip_gain == 0.0;
- } else {
- throw uhd::value_error("Could not find gain element " + name);
- }
- UHD_LOG_TRACE(unique_id(), "_set_rx_gain calling update gain");
- this->_set_all_gain(this->_get_all_gain(chan, RX_DIRECTION),
- this->get_rx_frequency(chan),
- chan,
- RX_DIRECTION);
- return clip_gain; // not really any coerced here (only clip) for individual gain
-}
-
-double magnesium_radio_ctrl_impl::_get_rx_gain(
- const std::string& name, const size_t /*chan*/
-)
-{
- std::lock_guard<std::mutex> l(_set_lock);
-
- if (name == MAGNESIUM_GAIN1) {
- return _ad9371_att[RX_DIRECTION];
- } else if (name == MAGNESIUM_GAIN2) {
- return _dsa_att[RX_DIRECTION];
- } else if (name == MAGNESIUM_AMP) {
- return _amp_bypass[RX_DIRECTION] ? AMP_MIN_GAIN : AMP_MAX_GAIN;
- } else {
- throw uhd::value_error("Could not find gain element " + name);
- }
-}
-
-std::vector<std::string> magnesium_radio_ctrl_impl::get_rx_lo_names(const size_t /*chan*/
-)
-{
- return std::vector<std::string>{MAGNESIUM_LO1, MAGNESIUM_LO2};
-}
-
-std::vector<std::string> magnesium_radio_ctrl_impl::get_rx_lo_sources(
- const std::string& name, const size_t /*chan*/
-)
-{
- if (name == MAGNESIUM_LO2) {
- return std::vector<std::string>{"internal"};
- } else if (name == MAGNESIUM_LO1) {
- return std::vector<std::string>{"internal", "external"};
- } else {
- throw uhd::value_error("Could not find LO stage " + name);
- }
-}
-
-freq_range_t magnesium_radio_ctrl_impl::get_rx_lo_freq_range(
- const std::string& name, const size_t /*chan*/
-)
-{
- if (name == MAGNESIUM_LO1) {
- return freq_range_t{ADF4351_MIN_FREQ, ADF4351_MAX_FREQ};
- } else if (name == MAGNESIUM_LO2) {
- return freq_range_t{AD9371_MIN_FREQ, AD9371_MAX_FREQ};
- } else {
- throw uhd::value_error("Could not find LO stage " + name);
- }
-}
-
-void magnesium_radio_ctrl_impl::set_rx_lo_source(
- const std::string& src, const std::string& name, const size_t /*chan*/
-)
-{
- // TODO: checking what options are there
- std::lock_guard<std::mutex> l(_set_lock);
- UHD_LOG_TRACE(unique_id(), "Setting RX LO " << name << " to " << src);
-
- if (name == MAGNESIUM_LO1) {
- _ad9371->set_lo_source(src, RX_DIRECTION);
- } else {
- UHD_LOG_ERROR(unique_id(),
- "RX LO " << name << " does not support setting source to " << src);
- }
-}
-
-const std::string magnesium_radio_ctrl_impl::get_rx_lo_source(
- const std::string& name, const size_t /*chan*/
-)
-{
- if (name == MAGNESIUM_LO1) {
- // TODO: should we use this from cache?
- return _ad9371->get_lo_source(RX_DIRECTION);
- }
- return "internal";
-}
-
-double magnesium_radio_ctrl_impl::_set_rx_lo_freq(const std::string source,
- const std::string name,
- const double freq,
- const size_t chan)
-{
- double coerced_lo_freq = freq;
- if (source != "internal") {
- UHD_LOG_WARNING(
- unique_id(), "LO source is not internal. This set frequency will be ignored");
- if (name == MAGNESIUM_LO1) {
- // handle ad9371 external LO case
- coerced_lo_freq = freq;
- _ad9371_freq[RX_DIRECTION] = coerced_lo_freq;
- }
- } else {
- if (name == MAGNESIUM_LO1) {
- coerced_lo_freq = _ad9371->set_frequency(freq, chan, RX_DIRECTION);
- _ad9371_freq[RX_DIRECTION] = coerced_lo_freq;
- } else if (name == MAGNESIUM_LO2) {
- // TODO: no hardcode the init_n_mode
- coerced_lo_freq = _lo_enable(_rx_lo, freq, _master_clock_rate, false);
- _adf4351_freq[RX_DIRECTION] = coerced_lo_freq;
- } else {
- UHD_LOG_WARNING(unique_id(),
- "There's no LO with this name of "
- << name << " in the system. This set rx lo freq will be ignored");
- };
- }
- return coerced_lo_freq;
-}
-
-double magnesium_radio_ctrl_impl::set_rx_lo_freq(
- double freq, const std::string& name, const size_t chan)
-{
- UHD_LOG_TRACE(
- unique_id(), "Setting rx lo frequency for " << name << " with freq = " << freq);
- std::lock_guard<std::mutex> l(_set_lock);
- std::string source = this->get_rx_lo_source(name, chan);
- const double coerced_lo_freq = this->_set_rx_lo_freq(source, name, freq, chan);
- this->_update_freq(chan, RX_DIRECTION);
- this->_update_gain(chan, RX_DIRECTION);
- return coerced_lo_freq;
-}
-
-double magnesium_radio_ctrl_impl::get_rx_lo_freq(
- const std::string& name, const size_t chan)
-{
- UHD_LOG_TRACE(unique_id(), "Getting rx lo frequency for " << name);
- std::string source = this->get_rx_lo_source(name, chan);
- if (name == MAGNESIUM_LO1) {
- return _ad9371_freq[RX_DIRECTION];
- } else if (name == "adf4531") {
- return _adf4351_freq[RX_DIRECTION];
- } else {
- UHD_LOG_ERROR(unique_id(),
- "There's no LO with this name of "
- << name << " in the system. This set rx lo freq will be ignored");
- }
- UHD_THROW_INVALID_CODE_PATH();
-}
-
-// TX LO
-std::vector<std::string> magnesium_radio_ctrl_impl::get_tx_lo_names(const size_t /*chan*/
-)
-{
- return std::vector<std::string>{MAGNESIUM_LO1, MAGNESIUM_LO2};
-}
-
-std::vector<std::string> magnesium_radio_ctrl_impl::get_tx_lo_sources(
- const std::string& name, const size_t /*chan*/
-)
-{
- if (name == MAGNESIUM_LO2) {
- return std::vector<std::string>{"internal"};
- } else if (name == MAGNESIUM_LO1) {
- return std::vector<std::string>{"internal", "external"};
- } else {
- throw uhd::value_error("Could not find LO stage " + name);
- }
-}
-
-freq_range_t magnesium_radio_ctrl_impl::get_tx_lo_freq_range(
- const std::string& name, const size_t /*chan*/
-)
-{
- if (name == MAGNESIUM_LO2) {
- return freq_range_t{ADF4351_MIN_FREQ, ADF4351_MAX_FREQ};
- } else if (name == MAGNESIUM_LO1) {
- return freq_range_t{AD9371_MIN_FREQ, AD9371_MAX_FREQ};
- } else {
- throw uhd::value_error("Could not find LO stage " + name);
- }
-}
-
-void magnesium_radio_ctrl_impl::set_tx_lo_source(
- const std::string& src, const std::string& name, const size_t /*chan*/
-)
-{
- // TODO: checking what options are there
- std::lock_guard<std::mutex> l(_set_lock);
- UHD_LOG_TRACE(unique_id(), "Setting TX LO " << name << " to " << src);
- if (name == MAGNESIUM_LO1) {
- _ad9371->set_lo_source(src, TX_DIRECTION);
- } else {
- UHD_LOG_ERROR(unique_id(),
- "TX LO " << name << " does not support setting source to " << src);
- }
-}
-
-const std::string magnesium_radio_ctrl_impl::get_tx_lo_source(
- const std::string& name, const size_t /*chan*/
-)
-{
- if (name == MAGNESIUM_LO1) {
- // TODO: should we use this from cache?
- return _ad9371->get_lo_source(TX_DIRECTION);
- }
- return "internal";
-}
-
-double magnesium_radio_ctrl_impl::_set_tx_lo_freq(const std::string source,
- const std::string name,
- const double freq,
- const size_t chan)
-{
- double coerced_lo_freq = freq;
- if (source != "internal") {
- UHD_LOG_WARNING(
- unique_id(), "LO source is not internal. This set frequency will be ignored");
- if (name == MAGNESIUM_LO1) {
- // handle ad9371 external LO case
- coerced_lo_freq = freq;
- _ad9371_freq[TX_DIRECTION] = coerced_lo_freq;
- }
- } else {
- if (name == MAGNESIUM_LO1) {
- coerced_lo_freq = _ad9371->set_frequency(freq, chan, TX_DIRECTION);
- _ad9371_freq[TX_DIRECTION] = coerced_lo_freq;
- } else if (name == MAGNESIUM_LO2) {
- // TODO: no hardcode the int_n_mode
- const bool int_n_mode = false;
- coerced_lo_freq = _lo_enable(_tx_lo, freq, _master_clock_rate, int_n_mode);
- _adf4351_freq[TX_DIRECTION] = coerced_lo_freq;
- } else {
- UHD_LOG_WARNING(unique_id(),
- "There's no LO with this name of "
- << name << " in the system. This set tx lo freq will be ignored");
- };
- }
- return coerced_lo_freq;
-}
-
-double magnesium_radio_ctrl_impl::set_tx_lo_freq(
- double freq, const std::string& name, const size_t chan)
-{
- UHD_LOG_TRACE(
- unique_id(), "Setting tx lo frequency for " << name << " with freq = " << freq);
- std::string source = this->get_tx_lo_source(name, chan);
- const double return_freq = this->_set_tx_lo_freq(source, name, freq, chan);
- this->_update_freq(chan, TX_DIRECTION);
- this->_update_gain(chan, TX_DIRECTION);
- return return_freq;
-}
-
-double magnesium_radio_ctrl_impl::get_tx_lo_freq(
- const std::string& name, const size_t chan)
-{
- UHD_LOG_TRACE(unique_id(), "Getting tx lo frequency for " << name);
- std::string source = this->get_tx_lo_source(name, chan);
- if (name == MAGNESIUM_LO1) {
- return _ad9371_freq[TX_DIRECTION];
- } else if (name == MAGNESIUM_LO2) {
- return _adf4351_freq[TX_DIRECTION];
- } else {
- UHD_LOG_ERROR(
- unique_id(), "There's no LO with this name of " << name << " in the system.");
- };
-
- UHD_THROW_INVALID_CODE_PATH();
-}
-
-
-size_t magnesium_radio_ctrl_impl::get_chan_from_dboard_fe(
- const std::string& fe, const direction_t /* dir */
-)
-{
- return boost::lexical_cast<size_t>(fe);
-}
-
-std::string magnesium_radio_ctrl_impl::get_dboard_fe_from_chan(
- const size_t chan, const direction_t /* dir */
-)
-{
- return std::to_string(chan);
-}
-
-
-void magnesium_radio_ctrl_impl::_remap_band_limits(
- const std::string band_map, const uhd::direction_t dir)
-{
- const size_t dflt_band_size = (dir == RX_DIRECTION) ? _rx_band_map.size()
- : _tx_band_map.size();
-
- std::vector<std::string> band_map_split;
- double band_lim;
-
- UHD_LOG_DEBUG(unique_id(), "Using user specified frequency band limits");
- boost::split(band_map_split, band_map, boost::is_any_of(";"));
- if (band_map_split.size() != dflt_band_size) {
- throw uhd::runtime_error((
- boost::format(
- "size %s of given frequency band map doesn't match the required size: %s")
- % band_map_split.size() % dflt_band_size)
- .str());
- }
- UHD_LOG_DEBUG(unique_id(), "newly used band limits: ");
- for (size_t i = 0; i < band_map_split.size(); i++) {
- try {
- band_lim = std::stod(band_map_split.at(i));
- } catch (...) {
- throw uhd::value_error(
- (boost::format("error while converting given frequency string %s "
- "to a double value")
- % band_map_split.at(i))
- .str());
- }
- UHD_LOG_DEBUG(unique_id(), "band " << i << " limit: " << band_lim << "Hz");
- if (dir == RX_DIRECTION)
- _rx_band_map.at(i) = band_lim;
- else
- _tx_band_map.at(i) = band_lim;
- }
-}
-
-
-void magnesium_radio_ctrl_impl::set_rpc_client(
- uhd::rpc_client::sptr rpcc, const uhd::device_addr_t& block_args)
-{
- _rpcc = rpcc;
- _block_args = block_args;
- UHD_LOG_TRACE(unique_id(), "Instantiating AD9371 control object...");
- _ad9371 = magnesium_ad9371_iface::uptr(
- new magnesium_ad9371_iface(_rpcc, (_radio_slot == "A") ? 0 : 1));
-
- if (block_args.has_key("identify")) {
- const std::string identify_val = block_args.get("identify");
- int identify_duration = std::atoi(identify_val.c_str());
- if (identify_duration == 0) {
- identify_duration = 5;
- }
- UHD_LOG_INFO(unique_id(),
- "Running LED identification process for " << identify_duration
- << " seconds.");
- _identify_with_leds(identify_duration);
- }
-
- if (block_args.has_key("tx_gain_profile")) {
- UHD_LOG_INFO(unique_id(),
- "Using user specified TX gain profile: " << block_args.get(
- "tx_gain_profile"));
- _gain_profile[TX_DIRECTION] = block_args.get("tx_gain_profile");
- }
-
- if (block_args.has_key("rx_gain_profile")) {
- UHD_LOG_INFO(unique_id(),
- "Using user specified RX gain profile: " << block_args.get(
- "rx_gain_profile"));
- _gain_profile[RX_DIRECTION] = block_args.get("rx_gain_profile");
- }
-
- if (block_args.has_key("rx_band_map")) {
- UHD_LOG_INFO(unique_id(), "Using user specified RX band limits");
- _remap_band_limits(block_args.get("rx_band_map"), RX_DIRECTION);
- }
-
- if (block_args.has_key("tx_band_map")) {
- UHD_LOG_INFO(unique_id(), "Using user specified TX band limits");
- _remap_band_limits(block_args.get("tx_band_map"), TX_DIRECTION);
- }
-
- // Note: MCR gets set during the init() call (prior to this), which takes
- // in arguments from the device args. So if block_args contains a
- // master_clock_rate key, then it should better be whatever the device is
- // configured to do.
- _master_clock_rate =
- _rpcc->request_with_token<double>(_rpc_prefix + "get_master_clock_rate");
- if (block_args.cast<double>("master_clock_rate", _master_clock_rate)
- != _master_clock_rate) {
- throw uhd::runtime_error(str(
- boost::format("Master clock rate mismatch. Device returns %f MHz, "
- "but should have been %f MHz.")
- % (_master_clock_rate / 1e6)
- % (block_args.cast<double>("master_clock_rate", _master_clock_rate) / 1e6)));
- }
- UHD_LOG_DEBUG(
- unique_id(), "Master Clock Rate is: " << (_master_clock_rate / 1e6) << " MHz.");
- radio_ctrl_impl::set_rate(_master_clock_rate);
-
- // EEPROM paths subject to change FIXME
- const size_t db_idx = get_block_id().get_block_count();
- _tree->access<eeprom_map_t>(_root_path / "eeprom")
- .add_coerced_subscriber([this, db_idx](const eeprom_map_t& db_eeprom) {
- this->_rpcc->notify_with_token("set_db_eeprom", db_idx, db_eeprom);
- })
- .set_publisher([this, db_idx]() {
- return this->_rpcc->request_with_token<eeprom_map_t>("get_db_eeprom", db_idx);
- });
-
- // Init sensors
- for (const auto& dir : std::vector<direction_t>{RX_DIRECTION, TX_DIRECTION}) {
- for (size_t chan_idx = 0; chan_idx < MAGNESIUM_NUM_CHANS; chan_idx++) {
- _init_mpm_sensors(dir, chan_idx);
- }
- }
-}
-
-bool magnesium_radio_ctrl_impl::get_lo_lock_status(const direction_t dir)
-{
- if (not(bool(_rpcc))) {
- UHD_LOG_DEBUG(unique_id(), "Reported no LO lock due to lack of RPC connection.");
- return false;
- }
-
- const std::string trx = (dir == RX_DIRECTION) ? "rx" : "tx";
- const size_t chan = 0; // They're the same after all
- const double freq = (dir == RX_DIRECTION) ? get_rx_frequency(chan)
- : get_tx_frequency(chan);
-
- bool lo_lock =
- _rpcc->request_with_token<bool>(_rpc_prefix + "get_ad9371_lo_lock", trx);
- UHD_LOG_TRACE(unique_id(),
- "AD9371 " << trx << " LO reports lock: " << (lo_lock ? "Yes" : "No"));
- if (lo_lock and _map_freq_to_rx_band(_rx_band_map, freq) == rx_band::LOWBAND) {
- lo_lock =
- lo_lock
- && _rpcc->request_with_token<bool>(_rpc_prefix + "get_lowband_lo_lock", trx);
- UHD_LOG_TRACE(unique_id(),
- "ADF4351 " << trx << " LO reports lock: " << (lo_lock ? "Yes" : "No"));
- }
-
- return lo_lock;
-}
-
-UHD_RFNOC_BLOCK_REGISTER(magnesium_radio_ctrl, "MagnesiumRadio");
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_init.cpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_init.cpp
deleted file mode 100644
index 89db61428..000000000
--- a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_init.cpp
+++ /dev/null
@@ -1,713 +0,0 @@
-//
-// Copyright 2017 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include "magnesium_constants.hpp"
-#include "magnesium_radio_ctrl_impl.hpp"
-#include <uhd/transport/chdr.hpp>
-#include <uhd/types/eeprom.hpp>
-#include <uhd/types/sensors.hpp>
-#include <uhd/utils/log.hpp>
-#include <uhdlib/usrp/cores/spi_core_3000.hpp>
-#include <boost/algorithm/string.hpp>
-#include <boost/algorithm/string/case_conv.hpp>
-#include <boost/algorithm/string/split.hpp>
-#include <string>
-#include <vector>
-using namespace uhd;
-using namespace uhd::rfnoc;
-
-namespace {
-enum slave_select_t { SEN_CPLD = 1, SEN_TX_LO = 2, SEN_RX_LO = 4, SEN_PHASE_DAC = 8 };
-
-constexpr double MAGNESIUM_DEFAULT_FREQ = 2.5e9; // Hz
-constexpr double MAGNESIUM_DEFAULT_BANDWIDTH = 100e6; // Hz
-constexpr char MAGNESIUM_DEFAULT_RX_ANTENNA[] = "RX2";
-constexpr char MAGNESIUM_DEFAULT_TX_ANTENNA[] = "TX/RX";
-
-//! Magnesium gain profile options
-const std::vector<std::string> MAGNESIUM_GP_OPTIONS = {"manual",
- "default",
- "default_rf_filter_bypass_always_on",
- "default_rf_filter_bypass_always_off"};
-} // namespace
-
-//! Helper function to extract single value of port number.
-//
-// Each GPIO pins can be controlled by each radio output ports.
-// This function convert the format of attribute "Radio_N_M"
-// to a single value port number = N*number_of_port_per_radio + M
-
-uint32_t extract_port_number(std::string radio_src_string, uhd::property_tree::sptr ptree)
-{
- std::string s_val = "0";
- std::vector<std::string> radio_strings;
- boost::algorithm::split(radio_strings,
- radio_src_string,
- boost::is_any_of("_/"),
- boost::token_compress_on);
- boost::to_lower(radio_strings[0]);
- if (radio_strings.size() < 3) {
- throw uhd::runtime_error(str(
- boost::format("%s is an invalid GPIO source string.") % radio_src_string));
- }
- size_t radio_num = std::stoi(radio_strings[1]);
- size_t port_num = std::stoi(radio_strings[2]);
- if (radio_strings[0] != "radio") {
- throw uhd::runtime_error(
- "Front panel GPIO bank can only accept a radio block as its driver.");
- }
- std::string radio_port_out = "Radio_" + radio_strings[1] + "/ports/out";
- std::string radio_port_path = radio_port_out + "/" + radio_strings[2];
- auto found = ptree->exists(fs_path("xbar") / radio_port_path);
- if (not found) {
- throw uhd::runtime_error(
- str(boost::format("Could not find radio port %s.\n") % radio_port_path));
- }
- size_t port_size = ptree->list(fs_path("xbar") / radio_port_out).size();
- return radio_num * port_size + port_num;
-}
-
-void magnesium_radio_ctrl_impl::_init_defaults()
-{
- UHD_LOG_TRACE(unique_id(), "Initializing defaults...");
- const size_t num_rx_chans = get_output_ports().size();
- const size_t num_tx_chans = get_input_ports().size();
-
- UHD_LOG_TRACE(unique_id(),
- "Num TX chans: " << num_tx_chans << " Num RX chans: " << num_rx_chans);
-
- for (size_t chan = 0; chan < num_rx_chans; chan++) {
- radio_ctrl_impl::set_rx_frequency(MAGNESIUM_DEFAULT_FREQ, chan);
- radio_ctrl_impl::set_rx_gain(0, chan);
- radio_ctrl_impl::set_rx_antenna(MAGNESIUM_DEFAULT_RX_ANTENNA, chan);
- radio_ctrl_impl::set_rx_bandwidth(MAGNESIUM_DEFAULT_BANDWIDTH, chan);
- }
-
- for (size_t chan = 0; chan < num_tx_chans; chan++) {
- radio_ctrl_impl::set_tx_frequency(MAGNESIUM_DEFAULT_FREQ, chan);
- radio_ctrl_impl::set_tx_gain(0, chan);
- radio_ctrl_impl::set_tx_antenna(MAGNESIUM_DEFAULT_TX_ANTENNA, chan);
- radio_ctrl_impl::set_tx_bandwidth(MAGNESIUM_DEFAULT_BANDWIDTH, chan);
- }
-
-
- /** 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));
- UHD_LOG_DEBUG(unique_id(), "Setting default spp to " << default_spp);
- _tree->access<int>(get_arg_path("spp") / "value").set(default_spp);
-}
-
-void magnesium_radio_ctrl_impl::_init_peripherals()
-{
- UHD_LOG_TRACE(unique_id(), "Initializing peripherals...");
- UHD_LOG_TRACE(unique_id(), "Initializing SPI core...");
- _spi = spi_core_3000::make(
- _get_ctrl(0), regs::sr_addr(regs::SPI), regs::rb_addr(regs::RB_SPI));
- UHD_LOG_TRACE(unique_id(), "Initializing CPLD...");
- UHD_LOG_TRACE(unique_id(), "Creating new CPLD object...");
- spi_config_t spi_config;
- spi_config.use_custom_divider = true;
- spi_config.divider = 125;
- spi_config.mosi_edge = spi_config_t::EDGE_RISE;
- spi_config.miso_edge = spi_config_t::EDGE_FALL;
- UHD_LOG_TRACE(unique_id(), "Making CPLD object...");
- _cpld = std::make_shared<magnesium_cpld_ctrl>(
- [this, spi_config](const uint32_t transaction) { // Write functor
- this->_spi->write_spi(SEN_CPLD, spi_config, transaction, 24);
- },
- [this, spi_config](const uint32_t transaction) { // Read functor
- return this->_spi->read_spi(SEN_CPLD, spi_config, transaction, 24);
- });
- _update_atr_switches(
- magnesium_cpld_ctrl::BOTH, DX_DIRECTION, radio_ctrl_impl::get_rx_antenna(0));
- UHD_LOG_TRACE(unique_id(), "Initializing TX LO...");
- _tx_lo = adf435x_iface::make_adf4351([this](
- const std::vector<uint32_t> transactions) {
- for (const uint32_t transaction : transactions) {
- this->_spi->write_spi(SEN_TX_LO, spi_config_t::EDGE_RISE, transaction, 32);
- }
- });
- UHD_LOG_TRACE(unique_id(), "Initializing RX LO...");
- _rx_lo = adf435x_iface::make_adf4351([this](
- const std::vector<uint32_t> transactions) {
- for (const uint32_t transaction : transactions) {
- this->_spi->write_spi(SEN_RX_LO, spi_config_t::EDGE_RISE, transaction, 32);
- }
- });
-
- _gpio.clear(); // Following the as-if rule, this can get optimized out
- for (size_t radio_idx = 0; radio_idx < _get_num_radios(); radio_idx++) {
- UHD_LOG_TRACE(unique_id(), "Initializing GPIOs for channel " << radio_idx);
- _gpio.emplace_back(usrp::gpio_atr::gpio_atr_3000::make(_get_ctrl(radio_idx),
- regs::sr_addr(regs::GPIO),
- regs::rb_addr(regs::RB_DB_GPIO)));
- // DSA and AD9371 gain bits do *not* toggle on ATR modes. If we ever
- // connect anything else to this core, we might need to set_atr_mode()
- // to MODE_ATR on those bits. For now, all bits simply do what they're
- // told, and don't toggle on RX/TX state changes.
- _gpio.back()->set_atr_mode(usrp::gpio_atr::MODE_GPIO, // Disable ATR mode
- usrp::gpio_atr::gpio_atr_3000::MASK_SET_ALL);
- _gpio.back()->set_gpio_ddr(usrp::gpio_atr::DDR_OUTPUT, // Make all GPIOs outputs
- usrp::gpio_atr::gpio_atr_3000::MASK_SET_ALL);
- }
- UHD_LOG_TRACE(unique_id(), "Initializing front-panel GPIO control...")
- _fp_gpio = usrp::gpio_atr::gpio_atr_3000::make(
- _get_ctrl(0), regs::sr_addr(regs::FP_GPIO), regs::rb_addr(regs::RB_FP_GPIO));
-}
-
-void magnesium_radio_ctrl_impl::_init_frontend_subtree(
- uhd::property_tree::sptr subtree, const size_t chan_idx)
-{
- const fs_path tx_fe_path = fs_path("tx_frontends") / chan_idx;
- const fs_path rx_fe_path = fs_path("rx_frontends") / chan_idx;
- UHD_LOG_TRACE(unique_id(),
- "Adding non-RFNoC block properties for channel "
- << chan_idx << " to prop tree path " << tx_fe_path << " and " << rx_fe_path);
- // TX Standard attributes
- subtree->create<std::string>(tx_fe_path / "name")
- .set(str(boost::format("Magnesium")));
- subtree->create<std::string>(tx_fe_path / "connection").set("IQ");
- // RX Standard attributes
- subtree->create<std::string>(rx_fe_path / "name")
- .set(str(boost::format("Magnesium")));
- subtree->create<std::string>(rx_fe_path / "connection").set("IQ");
- // TX Antenna
- subtree->create<std::string>(tx_fe_path / "antenna" / "value")
- .add_coerced_subscriber([this, chan_idx](const std::string& ant) {
- this->set_tx_antenna(ant, chan_idx);
- })
- .set_publisher([this, chan_idx]() { return this->get_tx_antenna(chan_idx); });
- subtree->create<std::vector<std::string>>(tx_fe_path / "antenna" / "options")
- .set({MAGNESIUM_DEFAULT_TX_ANTENNA})
- .add_coerced_subscriber([](const std::vector<std::string>&) {
- throw uhd::runtime_error("Attempting to update antenna options!");
- });
- // RX Antenna
- subtree->create<std::string>(rx_fe_path / "antenna" / "value")
- .add_coerced_subscriber([this, chan_idx](const std::string& ant) {
- this->set_rx_antenna(ant, chan_idx);
- })
- .set_publisher([this, chan_idx]() { return this->get_rx_antenna(chan_idx); });
- subtree->create<std::vector<std::string>>(rx_fe_path / "antenna" / "options")
- .set(MAGNESIUM_RX_ANTENNAS)
- .add_coerced_subscriber([](const std::vector<std::string>&) {
- throw uhd::runtime_error("Attempting to update antenna options!");
- });
- // TX frequency
- subtree->create<double>(tx_fe_path / "freq" / "value")
- .set_coercer([this, chan_idx](const double freq) {
- return this->set_tx_frequency(freq, chan_idx);
- })
- .set_publisher([this, chan_idx]() { return this->get_tx_frequency(chan_idx); });
- subtree->create<meta_range_t>(tx_fe_path / "freq" / "range")
- .set(meta_range_t(MAGNESIUM_MIN_FREQ, MAGNESIUM_MAX_FREQ, 1.0))
- .add_coerced_subscriber([](const meta_range_t&) {
- throw uhd::runtime_error("Attempting to update freq range!");
- });
- // RX frequency
- subtree->create<double>(rx_fe_path / "freq" / "value")
- .set_coercer([this, chan_idx](const double freq) {
- return this->set_rx_frequency(freq, chan_idx);
- })
- .set_publisher([this, chan_idx]() { return this->get_rx_frequency(chan_idx); });
- subtree->create<meta_range_t>(rx_fe_path / "freq" / "range")
- .set(meta_range_t(MAGNESIUM_MIN_FREQ, MAGNESIUM_MAX_FREQ, 1.0))
- .add_coerced_subscriber([](const meta_range_t&) {
- throw uhd::runtime_error("Attempting to update freq range!");
- });
- // TX bandwidth
- subtree->create<double>(tx_fe_path / "bandwidth" / "value")
- .set(AD9371_TX_MAX_BANDWIDTH)
- .set_coercer([this, chan_idx](const double bw) {
- return this->set_tx_bandwidth(bw, chan_idx);
- })
- .set_publisher([this, chan_idx]() { return this->get_tx_bandwidth(chan_idx); });
- subtree->create<meta_range_t>(tx_fe_path / "bandwidth" / "range")
- .set(meta_range_t(AD9371_TX_MIN_BANDWIDTH, AD9371_TX_MAX_BANDWIDTH))
- .add_coerced_subscriber([](const meta_range_t&) {
- throw uhd::runtime_error("Attempting to update bandwidth range!");
- });
- // RX bandwidth
- subtree->create<double>(rx_fe_path / "bandwidth" / "value")
- .set(AD9371_RX_MAX_BANDWIDTH)
- .set_coercer([this, chan_idx](const double bw) {
- return this->set_rx_bandwidth(bw, chan_idx);
- });
- subtree->create<meta_range_t>(rx_fe_path / "bandwidth" / "range")
- .set(meta_range_t(AD9371_RX_MIN_BANDWIDTH, AD9371_RX_MAX_BANDWIDTH))
- .add_coerced_subscriber([](const meta_range_t&) {
- throw uhd::runtime_error("Attempting to update bandwidth range!");
- });
- // TX gains
- subtree->create<double>(tx_fe_path / "gains" / "all" / "value")
- .set_coercer([this, chan_idx](
- const double gain) { return this->set_tx_gain(gain, chan_idx); })
- .set_publisher(
- [this, chan_idx]() { return radio_ctrl_impl::get_tx_gain(chan_idx); });
- subtree->create<meta_range_t>(tx_fe_path / "gains" / "all" / "range")
- .add_coerced_subscriber([](const meta_range_t&) {
- throw uhd::runtime_error("Attempting to update gain range!");
- })
- .set_publisher([this]() {
- if (_gain_profile[TX_DIRECTION] == "manual") {
- return meta_range_t(0.0, 0.0, 0.0);
- } else {
- return meta_range_t(ALL_TX_MIN_GAIN, ALL_TX_MAX_GAIN, ALL_TX_GAIN_STEP);
- }
- });
-
- subtree->create<std::vector<std::string>>(tx_fe_path / "gains/all/profile/options")
- .set(MAGNESIUM_GP_OPTIONS);
-
- subtree->create<std::string>(tx_fe_path / "gains/all/profile/value")
- .set_coercer([this](const std::string& profile) {
- // check if given profile is valid, otherwise use default profile
- std::string return_profile = profile;
- if (std::find(
- MAGNESIUM_GP_OPTIONS.begin(), MAGNESIUM_GP_OPTIONS.end(), profile)
- == MAGNESIUM_GP_OPTIONS.end()) {
- return_profile = "default";
- }
- _gain_profile[TX_DIRECTION] = return_profile;
- return return_profile;
- })
- .set_publisher([this]() { return _gain_profile[TX_DIRECTION]; });
-
- // RX gains
- subtree->create<double>(rx_fe_path / "gains" / "all" / "value")
- .set_coercer([this, chan_idx](
- const double gain) { return this->set_rx_gain(gain, chan_idx); })
- .set_publisher(
- [this, chan_idx]() { return radio_ctrl_impl::get_rx_gain(chan_idx); });
-
- subtree->create<meta_range_t>(rx_fe_path / "gains" / "all" / "range")
- .add_coerced_subscriber([](const meta_range_t&) {
- throw uhd::runtime_error("Attempting to update gain range!");
- })
- .set_publisher([this]() {
- if (_gain_profile[RX_DIRECTION] == "manual") {
- return meta_range_t(0.0, 0.0, 0.0);
- } else {
- return meta_range_t(ALL_RX_MIN_GAIN, ALL_RX_MAX_GAIN, ALL_RX_GAIN_STEP);
- }
- });
-
- subtree->create<std::vector<std::string>>(rx_fe_path / "gains/all/profile/options")
- .set(MAGNESIUM_GP_OPTIONS);
-
- subtree->create<std::string>(rx_fe_path / "gains/all/profile/value")
- .set_coercer([this](const std::string& profile) {
- // check if given profile is valid, otherwise use default profile
- std::string return_profile = profile;
- if (std::find(
- MAGNESIUM_GP_OPTIONS.begin(), MAGNESIUM_GP_OPTIONS.end(), profile)
- == MAGNESIUM_GP_OPTIONS.end()) {
- return_profile = "default";
- }
- _gain_profile[RX_DIRECTION] = return_profile;
- return return_profile;
- })
- .set_publisher([this]() { return _gain_profile[RX_DIRECTION]; });
-
- // TX mykonos attenuation
- subtree->create<double>(tx_fe_path / "gains" / MAGNESIUM_GAIN1 / "value")
- .set_coercer([this, chan_idx](const double gain) {
- return _set_tx_gain(MAGNESIUM_GAIN1, gain, chan_idx);
- })
- .set_publisher(
- [this, chan_idx]() { return this->_get_tx_gain(MAGNESIUM_GAIN1, chan_idx); });
-
- subtree->create<meta_range_t>(tx_fe_path / "gains" / MAGNESIUM_GAIN1 / "range")
- .add_coerced_subscriber([](const meta_range_t&) {
- throw uhd::runtime_error("Attempting to update gain range!");
- })
- .set_publisher([this]() {
- if (_gain_profile[TX_DIRECTION] == "manual") {
- return meta_range_t(
- AD9371_MIN_TX_GAIN, AD9371_MAX_TX_GAIN, AD9371_TX_GAIN_STEP);
- } else {
- return meta_range_t(0.0, 0.0, 0.0);
- }
- });
- // TX DSA
- subtree->create<double>(tx_fe_path / "gains" / MAGNESIUM_GAIN2 / "value")
- .set_coercer([this, chan_idx](const double gain) {
- return this->_set_tx_gain(MAGNESIUM_GAIN2, gain, chan_idx);
- })
- .set_publisher(
- [this, chan_idx]() { return this->_get_tx_gain(MAGNESIUM_GAIN2, chan_idx); });
-
- subtree->create<meta_range_t>(tx_fe_path / "gains" / MAGNESIUM_GAIN2 / "range")
- .add_coerced_subscriber([](const meta_range_t&) {
- throw uhd::runtime_error("Attempting to update gain range!");
- })
- .set_publisher([this]() {
- if (_gain_profile[TX_DIRECTION] == "manual") {
- return meta_range_t(DSA_MIN_GAIN, DSA_MAX_GAIN, DSA_GAIN_STEP);
- } else {
- return meta_range_t(0.0, 0.0, 0.0);
- }
- });
- // TX amp
- subtree->create<double>(tx_fe_path / "gains" / MAGNESIUM_AMP / "value")
- .set_coercer([this, chan_idx](const double gain) {
- return this->_set_tx_gain(MAGNESIUM_AMP, gain, chan_idx);
- })
- .set_publisher(
- [this, chan_idx]() { return this->_get_tx_gain(MAGNESIUM_AMP, chan_idx); });
-
- subtree->create<meta_range_t>(tx_fe_path / "gains" / MAGNESIUM_AMP / "range")
- .add_coerced_subscriber([](const meta_range_t&) {
- throw uhd::runtime_error("Attempting to update gain range!");
- })
- .set_publisher([this]() {
- if (_gain_profile[TX_DIRECTION] == "manual") {
- return meta_range_t(AMP_MIN_GAIN, AMP_MAX_GAIN, AMP_GAIN_STEP);
- } else {
- return meta_range_t(0.0, 0.0, 0.0);
- }
- });
-
- // RX mykonos attenuation
- subtree->create<double>(rx_fe_path / "gains" / MAGNESIUM_GAIN1 / "value")
- .set_coercer([this, chan_idx](const double gain) {
- UHD_VAR(gain);
- return this->_set_rx_gain(MAGNESIUM_GAIN1, gain, chan_idx);
- })
- .set_publisher(
- [this, chan_idx]() { return this->_get_rx_gain(MAGNESIUM_GAIN1, chan_idx); });
-
- subtree->create<meta_range_t>(rx_fe_path / "gains" / MAGNESIUM_GAIN1 / "range")
- .add_coerced_subscriber([](const meta_range_t&) {
- throw uhd::runtime_error("Attempting to update gain range!");
- })
- .set_publisher([this]() {
- if (_gain_profile[RX_DIRECTION] == "manual") {
- return meta_range_t(
- AD9371_MIN_RX_GAIN, AD9371_MAX_RX_GAIN, AD9371_RX_GAIN_STEP);
- } else {
- return meta_range_t(0.0, 0.0, 0.0);
- }
- });
- // RX DSA
- subtree->create<double>(rx_fe_path / "gains" / MAGNESIUM_GAIN2 / "value")
- .set_coercer([this, chan_idx](const double gain) {
- UHD_VAR(gain);
- return this->_set_rx_gain(MAGNESIUM_GAIN2, gain, chan_idx);
- })
- .set_publisher(
- [this, chan_idx]() { return this->_get_rx_gain(MAGNESIUM_GAIN2, chan_idx); });
-
- subtree->create<meta_range_t>(rx_fe_path / "gains" / MAGNESIUM_GAIN2 / "range")
- .add_coerced_subscriber([](const meta_range_t&) {
- throw uhd::runtime_error("Attempting to update gain range!");
- })
- .set_publisher([this]() {
- if (_gain_profile[RX_DIRECTION] == "manual") {
- return meta_range_t(DSA_MIN_GAIN, DSA_MAX_GAIN, DSA_MAX_GAIN);
- } else {
- return meta_range_t(0.0, 0.0, 0.0);
- }
- });
-
- // RX amp
- subtree->create<double>(rx_fe_path / "gains" / MAGNESIUM_AMP / "value")
- .set_coercer([this, chan_idx](const double gain) {
- return this->_set_rx_gain(MAGNESIUM_AMP, gain, chan_idx);
- })
- .set_publisher(
- [this, chan_idx]() { return this->_get_rx_gain(MAGNESIUM_AMP, chan_idx); });
-
- subtree->create<meta_range_t>(rx_fe_path / "gains" / MAGNESIUM_AMP / "range")
- .add_coerced_subscriber([](const meta_range_t&) {
- throw uhd::runtime_error("Attempting to update gain range!");
- })
- .set_publisher([this]() {
- if (_gain_profile[RX_DIRECTION] == "manual") {
- return meta_range_t(AMP_MIN_GAIN, AMP_MAX_GAIN, AMP_GAIN_STEP);
- } else {
- return meta_range_t(0.0, 0.0, 0.0);
- }
- });
-
- // TX LO lock sensor //////////////////////////////////////////////////////
- // Note: The lowband and AD9371 LO lock sensors are generated
- // programmatically in set_rpc_client(). The actual lo_locked publisher is
- // also set there.
- subtree->create<sensor_value_t>(tx_fe_path / "sensors" / "lo_locked")
- .set(sensor_value_t("all_los", false, "locked", "unlocked"))
- .add_coerced_subscriber([](const sensor_value_t&) {
- throw uhd::runtime_error("Attempting to write to sensor!");
- })
- .set_publisher([this]() {
- return sensor_value_t(
- "all_los", this->get_lo_lock_status(TX_DIRECTION), "locked", "unlocked");
- });
- // RX LO lock sensor (see not on TX LO lock sensor)
- subtree->create<sensor_value_t>(rx_fe_path / "sensors" / "lo_locked")
- .set(sensor_value_t("all_los", false, "locked", "unlocked"))
- .add_coerced_subscriber([](const sensor_value_t&) {
- throw uhd::runtime_error("Attempting to write to sensor!");
- })
- .set_publisher([this]() {
- return sensor_value_t(
- "all_los", this->get_lo_lock_status(RX_DIRECTION), "locked", "unlocked");
- });
- // LO Specific
- // RX LO
- subtree->create<meta_range_t>(rx_fe_path / "los" / MAGNESIUM_LO1 / "freq/range")
- .set_publisher([this, chan_idx]() {
- return this->get_rx_lo_freq_range(MAGNESIUM_LO1, chan_idx);
- });
- subtree
- ->create<std::vector<std::string>>(
- rx_fe_path / "los" / MAGNESIUM_LO1 / "source/options")
- .set_publisher([this, chan_idx]() {
- return this->get_rx_lo_sources(MAGNESIUM_LO1, chan_idx);
- });
- subtree->create<std::string>(rx_fe_path / "los" / MAGNESIUM_LO1 / "source/value")
- .add_coerced_subscriber([this, chan_idx](std::string src) {
- this->set_rx_lo_source(src, MAGNESIUM_LO1, chan_idx);
- })
- .set_publisher([this, chan_idx]() {
- return this->get_rx_lo_source(MAGNESIUM_LO1, chan_idx);
- });
- subtree->create<double>(rx_fe_path / "los" / MAGNESIUM_LO1 / "freq/value")
- .set_publisher(
- [this, chan_idx]() { return this->get_rx_lo_freq(MAGNESIUM_LO1, chan_idx); })
- .set_coercer([this, chan_idx](const double freq) {
- return this->set_rx_lo_freq(freq, MAGNESIUM_LO1, chan_idx);
- });
-
- subtree->create<meta_range_t>(rx_fe_path / "los" / MAGNESIUM_LO2 / "freq/range")
- .set_publisher([this, chan_idx]() {
- return this->get_rx_lo_freq_range(MAGNESIUM_LO2, chan_idx);
- });
- subtree
- ->create<std::vector<std::string>>(
- rx_fe_path / "los" / MAGNESIUM_LO2 / "source/options")
- .set_publisher([this, chan_idx]() {
- return this->get_rx_lo_sources(MAGNESIUM_LO2, chan_idx);
- });
-
- subtree->create<std::string>(rx_fe_path / "los" / MAGNESIUM_LO2 / "source/value")
- .add_coerced_subscriber([this, chan_idx](std::string src) {
- this->set_rx_lo_source(src, MAGNESIUM_LO2, chan_idx);
- })
- .set_publisher([this, chan_idx]() {
- return this->get_rx_lo_source(MAGNESIUM_LO2, chan_idx);
- });
- subtree->create<double>(rx_fe_path / "los" / MAGNESIUM_LO2 / "freq/value")
- .set_publisher(
- [this, chan_idx]() { return this->get_rx_lo_freq(MAGNESIUM_LO2, chan_idx); })
- .set_coercer([this, chan_idx](double freq) {
- return this->set_rx_lo_freq(freq, MAGNESIUM_LO2, chan_idx);
- });
- // TX LO
- subtree->create<meta_range_t>(tx_fe_path / "los" / MAGNESIUM_LO1 / "freq/range")
- .set_publisher([this, chan_idx]() {
- return this->get_rx_lo_freq_range(MAGNESIUM_LO1, chan_idx);
- });
- subtree
- ->create<std::vector<std::string>>(
- tx_fe_path / "los" / MAGNESIUM_LO1 / "source/options")
- .set_publisher([this, chan_idx]() {
- return this->get_tx_lo_sources(MAGNESIUM_LO1, chan_idx);
- });
- subtree->create<std::string>(tx_fe_path / "los" / MAGNESIUM_LO1 / "source/value")
- .add_coerced_subscriber([this, chan_idx](std::string src) {
- this->set_tx_lo_source(src, MAGNESIUM_LO1, chan_idx);
- })
- .set_publisher([this, chan_idx]() {
- return this->get_tx_lo_source(MAGNESIUM_LO1, chan_idx);
- });
- subtree->create<double>(tx_fe_path / "los" / MAGNESIUM_LO1 / "freq/value ")
- .set_publisher(
- [this, chan_idx]() { return this->get_tx_lo_freq(MAGNESIUM_LO1, chan_idx); })
- .set_coercer([this, chan_idx](double freq) {
- return this->set_tx_lo_freq(freq, MAGNESIUM_LO1, chan_idx);
- });
-
- subtree->create<meta_range_t>(tx_fe_path / "los" / MAGNESIUM_LO2 / "freq/range")
- .set_publisher([this, chan_idx]() {
- return this->get_tx_lo_freq_range(MAGNESIUM_LO2, chan_idx);
- });
- subtree
- ->create<std::vector<std::string>>(
- tx_fe_path / "los" / MAGNESIUM_LO2 / "source/options")
- .set_publisher([this, chan_idx]() {
- return this->get_tx_lo_sources(MAGNESIUM_LO2, chan_idx);
- });
-
- subtree->create<std::string>(tx_fe_path / "los" / MAGNESIUM_LO2 / "source/value")
- .add_coerced_subscriber([this, chan_idx](std::string src) {
- this->set_tx_lo_source(src, MAGNESIUM_LO2, chan_idx);
- })
- .set_publisher([this, chan_idx]() {
- return this->get_tx_lo_source(MAGNESIUM_LO2, chan_idx);
- });
- subtree->create<double>(tx_fe_path / "los" / MAGNESIUM_LO2 / "freq/value")
- .set_publisher(
- [this, chan_idx]() { return this->get_tx_lo_freq(MAGNESIUM_LO2, chan_idx); })
- .set_coercer([this, chan_idx](double freq) {
- return this->set_tx_lo_freq(freq, MAGNESIUM_LO2, chan_idx);
- });
-}
-
-void magnesium_radio_ctrl_impl::_init_prop_tree()
-{
- const fs_path fe_base = fs_path("dboards") / _radio_slot;
- for (size_t chan_idx = 0; chan_idx < MAGNESIUM_NUM_CHANS; chan_idx++) {
- this->_init_frontend_subtree(_tree->subtree(fe_base), chan_idx);
- }
-
- // EEPROM paths subject to change FIXME
- _tree->create<eeprom_map_t>(_root_path / "eeprom").set(eeprom_map_t());
-
- // TODO change codec names
- _tree->create<int>("rx_codecs" / _radio_slot / "gains");
- _tree->create<int>("tx_codecs" / _radio_slot / "gains");
- _tree->create<std::string>("rx_codecs" / _radio_slot / "name").set("AD9371 Dual ADC");
- _tree->create<std::string>("tx_codecs" / _radio_slot / "name").set("AD9371 Dual DAC");
-
- // TODO remove this dirty hack
- if (not _tree->exists("tick_rate")) {
- _tree->create<double>("tick_rate").set_publisher([this]() {
- return this->get_rate();
- });
- }
-
- // *****FP_GPIO************************
- for (const auto& attr : usrp::gpio_atr::gpio_attr_map) {
- if (not _tree->exists(fs_path("gpio") / "FP0" / attr.second)) {
- switch (attr.first) {
- case usrp::gpio_atr::GPIO_SRC:
- // FIXME: move this creation of this branch of ptree out side of
- // radio impl;
- // since there's no data dependency between radio and SRC setting for
- // FP0
- _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 radio_src_value = 0;
- uint32_t master_value = 0;
- for (size_t i = 0; i < str_val.size(); i++) {
- if (str_val[i] == "PS") {
- master_value += 1 << i;
- ;
- } else {
- auto port_num =
- extract_port_number(str_val[i], _tree);
- radio_src_value =
- (1 << (2 * i)) * port_num + radio_src_value;
- }
- }
- _rpcc->notify_with_token(
- "set_fp_gpio_master", master_value);
- _rpcc->notify_with_token(
- "set_fp_gpio_radio_src", radio_src_value);
- });
- 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" / attr.second)
- .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);
- });
- }
- } else {
- switch (attr.first) {
- case usrp::gpio_atr::GPIO_SRC:
- break;
- case usrp::gpio_atr::GPIO_CTRL:
- case usrp::gpio_atr::GPIO_DDR:
- _tree
- ->access<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:
- break;
- default:
- _tree->access<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);
- });
- }
- }
- }
-}
-
-
-void magnesium_radio_ctrl_impl::_init_mpm_sensors(
- const direction_t dir, const size_t chan_idx)
-{
- const std::string trx = (dir == RX_DIRECTION) ? "RX" : "TX";
- const fs_path fe_path = fs_path("dboards") / _radio_slot
- / (dir == RX_DIRECTION ? "rx_frontends" : "tx_frontends")
- / chan_idx;
- auto sensor_list = _rpcc->request_with_token<std::vector<std::string>>(
- this->_rpc_prefix + "get_sensors", trx);
- UHD_LOG_TRACE(unique_id(),
- "Chan " << chan_idx << ": Found " << sensor_list.size() << " " << trx
- << " sensors.");
- for (const auto& sensor_name : sensor_list) {
- UHD_LOG_TRACE(unique_id(), "Adding " << trx << " sensor " << sensor_name);
- _tree->create<sensor_value_t>(fe_path / "sensors" / sensor_name)
- .add_coerced_subscriber([](const sensor_value_t&) {
- throw uhd::runtime_error("Attempting to write to sensor!");
- })
- .set_publisher([this, trx, sensor_name, chan_idx]() {
- return sensor_value_t(
- this->_rpcc->request_with_token<sensor_value_t::sensor_map_t>(
- this->_rpc_prefix + "get_sensor", trx, sensor_name, chan_idx));
- });
- }
-}