aboutsummaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
authorMartin Braun <martin.braun@ettus.com>2017-11-03 16:56:03 -0700
committerMartin Braun <martin.braun@ettus.com>2017-12-22 15:05:05 -0800
commitb5f6ba518e80fe3f3f64f112d657bc9fc631fe4f (patch)
treed228fb6365e8227cadabd1e730549c2200bef290 /host
parentf700f5a43afa8840262fadf15c4d6fd2648b298b (diff)
downloaduhd-b5f6ba518e80fe3f3f64f112d657bc9fc631fe4f.tar.gz
uhd-b5f6ba518e80fe3f3f64f112d657bc9fc631fe4f.tar.bz2
uhd-b5f6ba518e80fe3f3f64f112d657bc9fc631fe4f.zip
mg: Refactor magnesium_radio_ctrl and friends
- Spin out AD9371 control into its own class - Split file into multiple compilation units - Fixed many minor code formatting issues
Diffstat (limited to 'host')
-rw-r--r--host/lib/usrp/dboard/magnesium/CMakeLists.txt3
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_ad9371_iface.cpp113
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_ad9371_iface.hpp76
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_constants.hpp64
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_cpld_ctrl.cpp3
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_cpld.cpp281
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.cpp1136
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.hpp126
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_init.cpp487
9 files changed, 1275 insertions, 1014 deletions
diff --git a/host/lib/usrp/dboard/magnesium/CMakeLists.txt b/host/lib/usrp/dboard/magnesium/CMakeLists.txt
index a0578d7b0..d1db7d1ea 100644
--- a/host/lib/usrp/dboard/magnesium/CMakeLists.txt
+++ b/host/lib/usrp/dboard/magnesium/CMakeLists.txt
@@ -18,6 +18,9 @@
IF(ENABLE_MPMD)
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_ad9371_iface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/magnesium_cpld_ctrl.cpp
)
LIBUHD_APPEND_SOURCES(${MAGNESIUM_SOURCES})
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_ad9371_iface.cpp b/host/lib/usrp/dboard/magnesium/magnesium_ad9371_iface.cpp
new file mode 100644
index 000000000..2fe31f066
--- /dev/null
+++ b/host/lib/usrp/dboard/magnesium/magnesium_ad9371_iface.cpp
@@ -0,0 +1,113 @@
+//
+// Copyright 2017 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0
+//
+
+#include "magnesium_ad9371_iface.hpp"
+#include <uhd/utils/log.hpp>
+#include <uhd/utils/log.hpp>
+
+using namespace uhd;
+
+namespace {
+ /*! Return a valid 'which' string for use with AD9371 API calls
+ *
+ * These strings take the form of "RX1", "TX2", ...
+ */
+ std::string _get_which(
+ const direction_t dir,
+ const size_t chan
+ ) {
+ UHD_ASSERT_THROW(dir == RX_DIRECTION or dir == TX_DIRECTION);
+ UHD_ASSERT_THROW(chan == 0 or chan == 1);
+ return str(boost::format("%s%d")
+ % (dir == RX_DIRECTION ? "RX" : "TX")
+ % (chan+1)
+ );
+ }
+}
+
+/******************************************************************************
+ * Structors
+ *****************************************************************************/
+magnesium_ad9371_iface::magnesium_ad9371_iface(
+ uhd::rpc_client::sptr rpcc,
+ const size_t slot_idx
+) : _rpcc(rpcc)
+ , _slot_idx(slot_idx)
+ , _rpc_prefix((slot_idx == 0) ? "db_0_" : "db_1_")
+ , _L((slot_idx == 0) ? "AD9371-0" : "AD9371-1")
+{
+ UHD_LOG_TRACE(_L,
+ "Initialized controls with RPC prefix " << _rpc_prefix <<
+ " for slot " << _slot_idx);
+}
+
+double magnesium_ad9371_iface::set_frequency(
+ const double freq,
+ const size_t chan,
+ const direction_t dir
+) {
+ // Note: This sets the frequency for both channels (1 and 2).
+ auto which = _get_which(dir, chan);
+ UHD_LOG_TRACE(_L,
+ "Calling " << _rpc_prefix << "set_freq on "
+ << which << " with " << freq);
+ auto actual_freq =
+ _rpcc->request_with_token<double>(_rpc_prefix + "set_freq",
+ which, freq, false);
+ UHD_LOG_TRACE(_L,
+ _rpc_prefix << "set_freq returned " << actual_freq);
+ return actual_freq;
+}
+
+double magnesium_ad9371_iface::set_gain(
+ const double gain,
+ const size_t chan,
+ const direction_t dir
+) {
+ auto which = _get_which(dir, chan);
+ UHD_LOG_TRACE(_L, "Calling " << _rpc_prefix << "set_gain on " << which << " with " << gain);
+ auto retval = _rpcc->request_with_token<double>(_rpc_prefix + "set_gain", which, gain);
+ UHD_LOG_TRACE(_L, _rpc_prefix << "set_gain returned " << retval);
+
+ return retval;
+ //return 0.0;
+}
+
+
+double magnesium_ad9371_iface::set_bandwidth(const double bandwidth, const size_t chan, const direction_t dir)
+{
+ // TODO: implement
+ UHD_LOG_WARNING(_L, "Ignoring attempt to set bandwidth");
+ return 0.0;
+}
+
+double magnesium_ad9371_iface::get_frequency(
+ const size_t chan,
+ const direction_t dir
+) {
+ auto which = _get_which(dir, chan);
+ UHD_LOG_TRACE(_L, "calling " << _rpc_prefix << "get_freq on " << which);
+ auto retval = _rpcc->request_with_token<double>(_rpc_prefix + "get_freq", which);
+ UHD_LOG_TRACE(_L, _rpc_prefix << "get_freq returned " << retval);
+ return retval;
+}
+
+double magnesium_ad9371_iface::get_gain(const size_t chan, const direction_t dir)
+{
+ auto which = _get_which(dir, chan);
+ UHD_LOG_TRACE(_L, "calling " << _rpc_prefix << "get_gain on " << which);
+ auto retval = _rpcc->request_with_token<double>(_rpc_prefix + "get_gain", which);
+ UHD_LOG_TRACE(_L, _rpc_prefix << "get_gain returned " << retval);
+ return retval;
+}
+
+double magnesium_ad9371_iface::get_bandwidth(const size_t chan, const direction_t dir)
+{
+ // TODO: implement
+ UHD_LOG_WARNING(_L, "Ignoring attempt to get bandwidth");
+ return 0.0;
+}
+
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_ad9371_iface.hpp b/host/lib/usrp/dboard/magnesium/magnesium_ad9371_iface.hpp
new file mode 100644
index 000000000..9529e1519
--- /dev/null
+++ b/host/lib/usrp/dboard/magnesium/magnesium_ad9371_iface.hpp
@@ -0,0 +1,76 @@
+//
+// Copyright 2017 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0
+//
+
+#ifndef INCLUDED_LIBUHD_RFNOC_MAGNESIUM_AD9371_IFACE_HPP
+#define INCLUDED_LIBUHD_RFNOC_MAGNESIUM_AD9371_IFACE_HPP
+
+#include "../../../utils/rpc.hpp"
+#include <uhd/types/direction.hpp>
+#include <iostream>
+#include <string>
+
+class magnesium_ad9371_iface
+{
+public:
+ using uptr = std::unique_ptr<magnesium_ad9371_iface>;
+
+ magnesium_ad9371_iface(
+ uhd::rpc_client::sptr rpcc,
+ const size_t slot_idx
+ );
+
+ double set_frequency(
+ const double freq,
+ const size_t chan,
+ const uhd::direction_t dir
+ );
+
+ double get_frequency(
+ const size_t chan,
+ const uhd::direction_t dir
+ );
+
+ double set_gain(
+ const double gain,
+ const size_t chan,
+ const uhd::direction_t dir
+ );
+
+ double get_gain(
+ const size_t chan,
+ const uhd::direction_t dir
+ );
+
+ double set_bandwidth(
+ const double bandwidth,
+ const size_t chan,
+ const uhd::direction_t dir
+ );
+
+ double get_bandwidth(
+ const size_t chan,
+ const uhd::direction_t dir
+ );
+
+private:
+ //! Reference to the RPC client
+ uhd::rpc_client::sptr _rpcc;
+
+ //! Slot index
+ const size_t _slot_idx;
+
+ //! Stores the prefix to RPC calls
+ const std::string _rpc_prefix;
+
+ //! Logger prefix
+ const std::string _L;
+
+
+
+};
+
+#endif /* INCLUDED_LIBUHD_RFNOC_MAGNESIUM_AD9371_IFACE_HPP */
+// vim: sw=4 et:
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_constants.hpp b/host/lib/usrp/dboard/magnesium/magnesium_constants.hpp
new file mode 100644
index 000000000..f66d9ab8e
--- /dev/null
+++ b/host/lib/usrp/dboard/magnesium/magnesium_constants.hpp
@@ -0,0 +1,64 @@
+//
+// Copyright 2017 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0
+//
+
+#ifndef INCLUDED_LIBUHD_MAGNESIUM_CONSTANTS_HPP
+#define INCLUDED_LIBUHD_MAGNESIUM_CONSTANTS_HPP
+
+#include <vector>
+#include <string>
+#include <cstddef>
+
+static const size_t FPGPIO_MASTER_RADIO = 0;
+
+static const double MAGNESIUM_TICK_RATE = 125e6; // Hz
+static const double MAGNESIUM_RADIO_RATE = 125e6; // Hz
+static const double MAGNESIUM_MIN_FREQ = 1e6; // Hz
+static const double MAGNESIUM_MAX_FREQ = 6e9; // Hz
+
+static const double MAGNESIUM_LOWBAND_FREQ = 300e6;
+
+static const double MAGNESIUM_RX_BAND1_MIN_FREQ = MAGNESIUM_LOWBAND_FREQ;
+static const double MAGNESIUM_RX_BAND2_MIN_FREQ = 600e6;
+static const double MAGNESIUM_RX_BAND3_MIN_FREQ = 1050e6;
+static const double MAGNESIUM_RX_BAND4_MIN_FREQ = 1600e6;
+static const double MAGNESIUM_RX_BAND5_MIN_FREQ = 2100e6;
+static const double MAGNESIUM_RX_BAND6_MIN_FREQ = 2700e6;
+
+static const double MAGNESIUM_TX_BAND1_MIN_FREQ = MAGNESIUM_LOWBAND_FREQ;
+static const double MAGNESIUM_TX_BAND2_MIN_FREQ = 800e6;
+static const double MAGNESIUM_TX_BAND3_MIN_FREQ = 1700e6;
+static const double MAGNESIUM_TX_BAND4_MIN_FREQ = 3400e6;
+
+static const double AD9371_MIN_RX_GAIN = 0.0; // dB
+static const double AD9371_MAX_RX_GAIN = 30.0; // dB
+static const double AD9371_RX_GAIN_STEP = 0.5;
+static const double DSA_MIN_GAIN = 0; // dB
+static const double DSA_MAX_GAIN = 31.5; // dB
+static const double DSA_GAIN_STEP = 0.5; // db
+static const double AD9371_MIN_TX_GAIN = 0.0; // dB
+static const double AD9371_MAX_TX_GAIN = 41.95; // dB
+static const double AD9371_TX_GAIN_STEP = 0.05;
+static const double ALL_RX_MIN_GAIN = 0.0;
+static const double ALL_RX_MAX_GAIN = 61.5;
+static const double ALL_RX_GAIN_STEP = 0.5;
+static const double ALL_TX_MIN_GAIN = 0.0;
+static const double ALL_TX_MAX_GAIN = 73.45;
+static const double ALL_TX_GAIN_STEP = 0.5;
+static const double MAGNESIUM_CENTER_FREQ = 2.5e9; // Hz
+static const std::vector<std::string> MAGNESIUM_RX_ANTENNAS = {
+ "TX/RX", "RX2"
+};
+static const char* MAGNESIUM_DEFAULT_RX_ANTENNA = "RX2";
+static const char* MAGNESIUM_DEFAULT_TX_ANTENNA = "TX/RX";
+static const double MAGNESIUM_DEFAULT_BANDWIDTH = 40e6; // Hz TODO: fix
+// 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.
+static const size_t MAGNESIUM_NUM_CHANS = 2;
+static const double MAGNESIUM_RX_IF_FREQ = 2.44e9;
+static const double MAGNESIUM_TX_IF_FREQ = 1.95e9;
+
+#endif /* INCLUDED_LIBUHD_MAGNESIUM_CONSTANTS_HPP */
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_cpld_ctrl.cpp b/host/lib/usrp/dboard/magnesium/magnesium_cpld_ctrl.cpp
index 66fa02360..dac8ca5c1 100644
--- a/host/lib/usrp/dboard/magnesium/magnesium_cpld_ctrl.cpp
+++ b/host/lib/usrp/dboard/magnesium/magnesium_cpld_ctrl.cpp
@@ -5,6 +5,7 @@
//
#include "magnesium_cpld_ctrl.hpp"
+#include "magnesium_constants.hpp"
#include <uhd/utils/log.hpp>
#include <boost/format.hpp>
#include <chrono>
@@ -12,6 +13,8 @@
namespace {
//! Address of the CPLD scratch register
const uint8_t CPLD_REGS_SCRATCH = 0x0040;
+
+ //! Address of the CPLD reset register
const uint8_t CPLD_REGS_RESET = 0x0041;
}
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_cpld.cpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_cpld.cpp
new file mode 100644
index 000000000..fa0c7cba5
--- /dev/null
+++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_cpld.cpp
@@ -0,0 +1,281 @@
+//
+// Copyright 2017 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0
+//
+
+#include "magnesium_radio_ctrl_impl.hpp"
+#include "magnesium_cpld_ctrl.hpp"
+#include "magnesium_constants.hpp"
+#include <uhd/utils/log.hpp>
+
+/*
+ * Magnesium Rev C frequency bands:
+ *
+ * RX IF frequency is 2.4418 GHz. Have 80 MHz of bandwidth for loband.
+ * TX IF frequency is 1.8-2.1 GHz (1.95 GHz is best).
+ *
+ * For RX:
+ * Band SW2-AB SW3-ABC SW4-ABC SW5-ABCD SW6-ABC SW7-AB SW8-AB MIX
+ * WB RF1 01 OFF 111 NA --- NA ---- RF3 001 RF2 01 RF2 01 0
+ * LB RF2 10 RF5 100 NA --- RF3 0010 RF1 100 RF1 10 RF1 10 1
+ * 440-530 RF2 10 RF2 001 NA --- RF1 1000 RF1 100 RF2 01 RF2 01 0
+ * 650-1000 RF2 10 RF6 101 NA --- RF4 0001 RF1 100 RF2 01 RF2 01 0
+ * 1100-1575 RF2 10 RF4 011 NA --- RF2 0100 RF1 100 RF2 01 RF2 01 0
+ * 1600-2250 RF2 10 RF3 010 RF2 010 NA ---- RF2 010 RF2 01 RF2 01 0
+ * 2100-2850 RF2 10 RF1 000 RF1 100 NA ---- RF2 010 RF2 01 RF2 01 0
+ * 2700+ RF3 11 OFF 111 RF3 001 NA ---- RF2 010 RF2 01 RF2 01 0
+ *
+ * For TX:
+ * Band SW5-AB SW4-AB SW3-X SW2-ABCD SW1-AB SWTRX-AB MIX
+ * WB RF1 10 RF2 01 RF1 0 NA ---- SHD 00 RF4 11 0
+ * LB RF2 01 RF1 10 RF2 1 RF3 0010 RF3 11 RF1 00 1
+ * <800 RF1 10 RF2 01 RF2 1 RF3 0010 RF3 11 RF1 00 0
+ * 800-1700 RF1 10 RF2 01 RF2 1 RF2 0100 RF2 10 RF1 00 0
+ * 1700-3400 RF1 10 RF2 01 RF2 1 RF1 1000 RF1 01 RF1 00 0
+ * 3400-6400 RF1 10 RF2 01 RF2 1 RF4 0001 SHD 00 RF2 10 0
+ */
+
+using namespace uhd;
+using namespace uhd::usrp;
+using namespace uhd::rfnoc;
+
+void magnesium_radio_ctrl_impl::_update_atr_switches(
+ const magnesium_cpld_ctrl::chan_sel_t chan,
+ const direction_t dir,
+ const std::string &ant
+){
+ magnesium_cpld_ctrl::rx_sw1_t rx_sw1 = magnesium_cpld_ctrl::RX_SW1_RX2INPUT;
+ magnesium_cpld_ctrl::sw_trx_t sw_trx = _sw_trx[chan];
+
+ bool trx_led = false, rx2_led = true;
+ //bool tx_pa_enb = true, tx_amp_enb = true, tx_myk_en=true;
+ if (ant == "TX/RX" and dir == RX_DIRECTION) {
+ rx_sw1 = magnesium_cpld_ctrl::RX_SW1_TRXSWITCHOUTPUT;
+ sw_trx = magnesium_cpld_ctrl::SW_TRX_RXCHANNELPATH;
+ trx_led = true;
+ rx2_led = false;
+ }
+ UHD_LOG_TRACE(unique_id(), "Update all atr related switches for " << dir << " " << ant );
+ if (dir == RX_DIRECTION){
+ _cpld->set_rx_atr_bits(
+ chan,
+ magnesium_cpld_ctrl::ON,
+ rx_sw1,
+ trx_led,
+ rx2_led,
+ true,
+ true,
+ true,
+ true
+ );
+ _cpld->set_tx_atr_bits(
+ chan,
+ magnesium_cpld_ctrl::IDLE,
+ false,
+ sw_trx,
+ false,
+ false,
+ false
+ );
+ _cpld->set_rx_atr_bits(
+ chan,
+ magnesium_cpld_ctrl::IDLE,
+ rx_sw1,
+ false,
+ false,
+ false,
+ false,
+ false,
+ true
+ );
+ }
+ if (dir == TX_DIRECTION){
+ _cpld->set_tx_atr_bits(
+ chan,
+ magnesium_cpld_ctrl::ON,
+ true,
+ sw_trx,
+ true,
+ true,
+ true
+ );
+ _cpld->set_rx_atr_bits(
+ chan,
+ magnesium_cpld_ctrl::IDLE,
+ rx_sw1,
+ false,
+ false,
+ false,
+ false,
+ false,
+ true
+ );
+ };
+}
+
+void magnesium_radio_ctrl_impl::_update_rx_freq_switches(
+ const double freq,
+ const size_t chan
+) {
+ UHD_LOG_TRACE(unique_id(),
+ "Update all RX freq related switches. f=" << freq << " Hz, "
+ "chan=" << chan);
+
+ // Set filters based on frequency. Note: We always switch both channels
+ if (freq < MAGNESIUM_RX_BAND1_MIN_FREQ) {
+ _cpld->set_rx_switches(
+ magnesium_cpld_ctrl::BOTH,
+ magnesium_cpld_ctrl::RX_SW2_LOWERFILTERBANKTOSWITCH3,
+ magnesium_cpld_ctrl::RX_SW3_FILTER0490LPMHZ,
+ magnesium_cpld_ctrl::RX_SW4_FILTER2700HPMHZ,
+ magnesium_cpld_ctrl::RX_SW5_FILTER0490LPMHZFROM,
+ magnesium_cpld_ctrl::RX_SW6_LOWERFILTERBANKFROMSWITCH5,
+ magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_LOBAND,
+ true
+ );
+ } else if (freq < MAGNESIUM_RX_BAND2_MIN_FREQ) {
+ _cpld->set_rx_switches(
+ magnesium_cpld_ctrl::BOTH,
+ magnesium_cpld_ctrl::RX_SW2_LOWERFILTERBANKTOSWITCH3,
+ magnesium_cpld_ctrl::RX_SW3_FILTER0440X0530MHZ,
+ magnesium_cpld_ctrl::RX_SW4_FILTER2700HPMHZ,
+ magnesium_cpld_ctrl::RX_SW5_FILTER0440X0530MHZFROM,
+ magnesium_cpld_ctrl::RX_SW6_LOWERFILTERBANKFROMSWITCH5,
+ magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_BYPASS,
+ false
+ );
+ } else if (freq < MAGNESIUM_RX_BAND3_MIN_FREQ) {
+ _cpld->set_rx_switches(
+ magnesium_cpld_ctrl::BOTH,
+ magnesium_cpld_ctrl::RX_SW2_LOWERFILTERBANKTOSWITCH3,
+ magnesium_cpld_ctrl::RX_SW3_FILTER0650X1000MHZ,
+ magnesium_cpld_ctrl::RX_SW4_FILTER2700HPMHZ,
+ magnesium_cpld_ctrl::RX_SW5_FILTER0650X1000MHZFROM,
+ magnesium_cpld_ctrl::RX_SW6_LOWERFILTERBANKFROMSWITCH5,
+ magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_BYPASS,
+ false
+ );
+ } else if (freq < MAGNESIUM_RX_BAND4_MIN_FREQ) {
+ _cpld->set_rx_switches(
+ magnesium_cpld_ctrl::BOTH,
+ magnesium_cpld_ctrl::RX_SW2_LOWERFILTERBANKTOSWITCH3,
+ magnesium_cpld_ctrl::RX_SW3_FILTER1100X1575MHZ,
+ magnesium_cpld_ctrl::RX_SW4_FILTER2700HPMHZ,
+ magnesium_cpld_ctrl::RX_SW5_FILTER1100X1575MHZFROM,
+ magnesium_cpld_ctrl::RX_SW6_LOWERFILTERBANKFROMSWITCH5,
+ magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_BYPASS,
+ false
+ );
+ } else if (freq < MAGNESIUM_RX_BAND5_MIN_FREQ) {
+ _cpld->set_rx_switches(
+ magnesium_cpld_ctrl::BOTH,
+ magnesium_cpld_ctrl::RX_SW2_LOWERFILTERBANKTOSWITCH3,
+ magnesium_cpld_ctrl::RX_SW3_FILTER1600X2250MHZ,
+ magnesium_cpld_ctrl::RX_SW4_FILTER1600X2250MHZFROM,
+ magnesium_cpld_ctrl::RX_SW5_FILTER0440X0530MHZFROM,
+ magnesium_cpld_ctrl::RX_SW6_UPPERFILTERBANKFROMSWITCH4,
+ magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_BYPASS,
+ false
+ );
+ } else if (freq < MAGNESIUM_RX_BAND6_MIN_FREQ) {
+ _cpld->set_rx_switches(
+ magnesium_cpld_ctrl::BOTH,
+ magnesium_cpld_ctrl::RX_SW2_LOWERFILTERBANKTOSWITCH3,
+ magnesium_cpld_ctrl::RX_SW3_FILTER2100X2850MHZ,
+ magnesium_cpld_ctrl::RX_SW4_FILTER2100X2850MHZFROM,
+ magnesium_cpld_ctrl::RX_SW5_FILTER0440X0530MHZFROM,
+ magnesium_cpld_ctrl::RX_SW6_UPPERFILTERBANKFROMSWITCH4,
+ magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_BYPASS,
+ false
+ );
+ } else {
+ _cpld->set_rx_switches(
+ magnesium_cpld_ctrl::BOTH,
+ magnesium_cpld_ctrl::RX_SW2_UPPERFILTERBANKTOSWITCH4,
+ magnesium_cpld_ctrl::RX_SW3_SHUTDOWNSW3,
+ magnesium_cpld_ctrl::RX_SW4_FILTER2700HPMHZ,
+ magnesium_cpld_ctrl::RX_SW5_FILTER0440X0530MHZFROM,
+ magnesium_cpld_ctrl::RX_SW6_UPPERFILTERBANKFROMSWITCH4,
+ magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_BYPASS,
+ false
+ );
+ }
+}
+
+void magnesium_radio_ctrl_impl::_update_tx_freq_switches(
+ const double freq,
+ const size_t chan
+){
+ UHD_LOG_TRACE(unique_id(),
+ "Update all TX freq related switches. f=" << freq << " Hz, "
+ "chan=" << chan);
+ magnesium_cpld_ctrl::chan_sel_t chan_sel =
+ _master ? magnesium_cpld_ctrl::CHAN1 : magnesium_cpld_ctrl::CHAN2;
+
+ // Set filters based on frequency
+ if (freq < MAGNESIUM_TX_BAND1_MIN_FREQ) {
+ _cpld->set_tx_switches(
+ magnesium_cpld_ctrl::BOTH,
+ magnesium_cpld_ctrl::SW_TRX_FROMLOWERFILTERBANKTXSW1,
+ magnesium_cpld_ctrl::TX_SW1_FROMTXFILTERLP0800MHZ,
+ magnesium_cpld_ctrl::TX_SW2_TOTXFILTERLP0800MHZ,
+ magnesium_cpld_ctrl::TX_SW3_TOTXFILTERBANKS,
+ magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_LOBAND,
+ true,
+ magnesium_cpld_ctrl::ON
+ );
+ _sw_trx[chan_sel] = magnesium_cpld_ctrl::SW_TRX_FROMLOWERFILTERBANKTXSW1;
+ } else if (freq < MAGNESIUM_TX_BAND2_MIN_FREQ) {
+ _cpld->set_tx_switches(
+ magnesium_cpld_ctrl::BOTH,
+ magnesium_cpld_ctrl::SW_TRX_FROMLOWERFILTERBANKTXSW1,
+ magnesium_cpld_ctrl::TX_SW1_FROMTXFILTERLP0800MHZ,
+ magnesium_cpld_ctrl::TX_SW2_TOTXFILTERLP0800MHZ,
+ magnesium_cpld_ctrl::TX_SW3_TOTXFILTERBANKS,
+ magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_BYPASS,
+ false,
+ magnesium_cpld_ctrl::ON
+ );
+ _sw_trx[chan_sel] = magnesium_cpld_ctrl::SW_TRX_FROMLOWERFILTERBANKTXSW1;
+ } else if (freq < MAGNESIUM_TX_BAND3_MIN_FREQ) {
+ _cpld->set_tx_switches(
+ magnesium_cpld_ctrl::BOTH,
+ magnesium_cpld_ctrl::SW_TRX_FROMLOWERFILTERBANKTXSW1,
+ magnesium_cpld_ctrl::TX_SW1_FROMTXFILTERLP1700MHZ,
+ magnesium_cpld_ctrl::TX_SW2_TOTXFILTERLP1700MHZ,
+ magnesium_cpld_ctrl::TX_SW3_TOTXFILTERBANKS,
+ magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_BYPASS,
+ false,
+ magnesium_cpld_ctrl::ON
+ );
+ _sw_trx[chan_sel] = magnesium_cpld_ctrl::SW_TRX_FROMLOWERFILTERBANKTXSW1;
+ } else if (freq < MAGNESIUM_TX_BAND4_MIN_FREQ) {
+ _cpld->set_tx_switches(
+ magnesium_cpld_ctrl::BOTH,
+ magnesium_cpld_ctrl::SW_TRX_FROMLOWERFILTERBANKTXSW1,
+ magnesium_cpld_ctrl::TX_SW1_FROMTXFILTERLP3400MHZ,
+ magnesium_cpld_ctrl::TX_SW2_TOTXFILTERLP3400MHZ,
+ magnesium_cpld_ctrl::TX_SW3_TOTXFILTERBANKS,
+ magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_BYPASS,
+ false,
+ magnesium_cpld_ctrl::ON
+ );
+ _sw_trx[chan_sel] = magnesium_cpld_ctrl::SW_TRX_FROMLOWERFILTERBANKTXSW1;
+ } else {
+ _cpld->set_tx_switches(
+ magnesium_cpld_ctrl::BOTH,
+ magnesium_cpld_ctrl::SW_TRX_FROMTXUPPERFILTERBANKLP6400MHZ,
+ magnesium_cpld_ctrl::TX_SW1_SHUTDOWNTXSW1,
+ magnesium_cpld_ctrl::TX_SW2_TOTXFILTERLP6400MHZ,
+ magnesium_cpld_ctrl::TX_SW3_TOTXFILTERBANKS,
+ magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_BYPASS,
+ false,
+ magnesium_cpld_ctrl::ON
+ );
+ _sw_trx[chan_sel] = magnesium_cpld_ctrl::SW_TRX_FROMTXUPPERFILTERBANKLP6400MHZ;
+ }
+}
+
+
+
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.cpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.cpp
index fe386aa38..b0157bdef 100644
--- a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.cpp
+++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.cpp
@@ -5,7 +5,7 @@
//
#include "magnesium_radio_ctrl_impl.hpp"
-#include "spi_core_3000.hpp"
+#include "magnesium_constants.hpp"
#include <uhd/utils/log.hpp>
#include <uhd/rfnoc/node_ctrl_base.hpp>
#include <uhd/transport/chdr.hpp>
@@ -23,105 +23,54 @@ using namespace uhd::usrp;
using namespace uhd::rfnoc;
namespace {
- enum slave_select_t {
- SEN_CPLD = 1,
- SEN_TX_LO = 2,
- SEN_RX_LO = 4,
- SEN_PHASE_DAC = 8
- };
-
- const double MAGNESIUM_TICK_RATE = 125e6; // Hz
- const double MAGNESIUM_RADIO_RATE = 125e6; // Hz
- const double MAGNESIUM_MIN_FREQ = 1e6; // Hz
- const double MAGNESIUM_MAX_FREQ = 6e9; // Hz
- const double AD9371_MIN_RX_GAIN = 0.0; // dB
- const double AD9371_MAX_RX_GAIN = 30.0; // dB
- const double AD9371_RX_GAIN_STEP = 0.5;
- const double DSA_MIN_GAIN = 0; // dB
- const double DSA_MAX_GAIN = 31.5; // dB
- const double DSA_GAIN_STEP = 0.5; // db
- const double AD9371_MIN_TX_GAIN = 0.0; // dB
- const double AD9371_MAX_TX_GAIN = 41.95; // dB
- const double AD9371_TX_GAIN_STEP = 0.05;
- const double ALL_RX_MIN_GAIN = 0.0;
- const double ALL_RX_MAX_GAIN = 61.5;
- const double ALL_RX_GAIN_STEP = 0.5;
- const double ALL_TX_MIN_GAIN = 0.0;
- const double ALL_TX_MAX_GAIN = 73.45;
- const double ALL_TX_GAIN_STEP = 0.5;
- const double MAGNESIUM_CENTER_FREQ = 2.5e9; // Hz
- const char* MAGNESIUM_DEFAULT_RX_ANTENNA = "RX2";
- const char* MAGNESIUM_DEFAULT_TX_ANTENNA = "TX/RX";
- const double MAGNESIUM_DEFAULT_BANDWIDTH = 40e6; // Hz TODO: fix
- const size_t MAGNESIUM_NUM_TX_CHANS = 1;
- const size_t MAGNESIUM_NUM_RX_CHANS = 1;
- const double MAGNESIUM_RX_IF_FREQ = 2.44e9;
- const double MAGNESIUM_TX_IF_FREQ = 1.95e9;
- const double MAGNESIUM_LOWBAND_FREQ = 300e6;
-/*
-Magnesium Rev C frequency bands:
-
-RX IF frequency is 2.4418 GHz. Have 80 MHz of bandwidth for loband.
-TX IF frequency is 1.8-2.1 GHz (1.95 GHz is best).
-
-For RX:
- Band SW2-AB SW3-ABC SW4-ABC SW5-ABCD SW6-ABC SW7-AB SW8-AB MIX
- WB RF1 01 OFF 111 NA --- NA ---- RF3 001 RF2 01 RF2 01 0
- LB RF2 10 RF5 100 NA --- RF3 0010 RF1 100 RF1 10 RF1 10 1
- 440-530 RF2 10 RF2 001 NA --- RF1 1000 RF1 100 RF2 01 RF2 01 0
- 650-1000 RF2 10 RF6 101 NA --- RF4 0001 RF1 100 RF2 01 RF2 01 0
- 1100-1575 RF2 10 RF4 011 NA --- RF2 0100 RF1 100 RF2 01 RF2 01 0
- 1600-2250 RF2 10 RF3 010 RF2 010 NA ---- RF2 010 RF2 01 RF2 01 0
- 2100-2850 RF2 10 RF1 000 RF1 100 NA ---- RF2 010 RF2 01 RF2 01 0
- 2700+ RF3 11 OFF 111 RF3 001 NA ---- RF2 010 RF2 01 RF2 01 0
-
-For TX:
- Band SW5-AB SW4-AB SW3-X SW2-ABCD SW1-AB SWTRX-AB MIX
- WB RF1 10 RF2 01 RF1 0 NA ---- SHD 00 RF4 11 0
- LB RF2 01 RF1 10 RF2 1 RF3 0010 RF3 11 RF1 00 1
- <800 RF1 10 RF2 01 RF2 1 RF3 0010 RF3 11 RF1 00 0
- 800-1700 RF1 10 RF2 01 RF2 1 RF2 0100 RF2 10 RF1 00 0
- 1700-3400 RF1 10 RF2 01 RF2 1 RF1 1000 RF1 01 RF1 00 0
- 3400-6400 RF1 10 RF2 01 RF2 1 RF4 0001 SHD 00 RF2 10 0
-
-*/
-
-
- const double MAGNESIUM_RX_BAND1_MIN_FREQ = MAGNESIUM_LOWBAND_FREQ;
- const double MAGNESIUM_RX_BAND2_MIN_FREQ = 600e6;
- const double MAGNESIUM_RX_BAND3_MIN_FREQ = 1050e6;
- const double MAGNESIUM_RX_BAND4_MIN_FREQ = 1600e6;
- const double MAGNESIUM_RX_BAND5_MIN_FREQ = 2100e6;
- const double MAGNESIUM_RX_BAND6_MIN_FREQ = 2700e6;
-
- const double MAGNESIUM_TX_BAND1_MIN_FREQ = MAGNESIUM_LOWBAND_FREQ;
- const double MAGNESIUM_TX_BAND2_MIN_FREQ = 800e6;
- const double MAGNESIUM_TX_BAND3_MIN_FREQ = 1700e6;
- const double MAGNESIUM_TX_BAND4_MIN_FREQ = 3400e6;
+ /**************************************************************************
+ * ADF4351 Controls
+ *************************************************************************/
+ 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;
+ }
- const size_t FPGPIO_MASTER_RADIO = 0;
+ 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;
+ }
- /*! Return a valid 'which' string for use with AD9371 API calls
- *
- * These strings take the form of "RX1", "TX2", ...
- */
- std::string _get_which(const direction_t dir,std::string _radio_slot)
+ void _lo_disable(adf435x_iface::sptr lo_iface)
{
- UHD_ASSERT_THROW(dir == RX_DIRECTION or dir == TX_DIRECTION);
- size_t chan = 0;
- if (_radio_slot == "A" or _radio_slot == "C")
- {
- chan = 0;
- }
- if (_radio_slot == "B" or _radio_slot == "D")
- {
- chan = 1;
- }
- UHD_LOG_WARNING("MAGNESIUM_MYKONOS","board slot to chan map " << _radio_slot << " "<<chan)
- return str(boost::format("%s%d")
- % (dir == RX_DIRECTION ? "RX" : "TX")
- % (chan+1)
- );
+ 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();
}
}
@@ -131,379 +80,23 @@ For TX:
*****************************************************************************/
UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR(magnesium_radio_ctrl)
{
- UHD_LOG_TRACE("MAGNESIUM", "Entering magnesium_radio_ctrl_impl ctor...");
- UHD_LOG_DEBUG("MAGNESIUM", "Note: Running in one-block-per-channel mode!");
- const char radio_slot_name[4] = {'A','B','C','D'};
+ UHD_LOG_TRACE(unique_id(), "Entering magnesium_radio_ctrl_impl ctor...");
+ UHD_LOG_DEBUG(unique_id(), "Note: Running in one-block-per-channel mode!");
+ const char radio_slot_name[4] = {'A', 'B', 'C', 'D'};
_radio_slot = radio_slot_name[get_block_id().get_block_count()];
- UHD_LOG_TRACE("MAGNESIUM", "Radio slot: " << _radio_slot);
- if (_radio_slot == "A" or _radio_slot =="B"){
- _rpc_prefix = "db_0_";
- }
- if (_radio_slot == "C" or _radio_slot=="D")
- {
- _rpc_prefix = "db_1_";
- }
- UHD_LOG_WARNING("MAGNESIUM", "Using RPC prefix `" << _rpc_prefix << "'");
+ UHD_LOG_TRACE(unique_id(), "Radio slot: " << _radio_slot);
+ _master = _radio_slot == "A" or _radio_slot == "C";
+ UHD_LOG_DEBUG(unique_id(),
+ "Radio type: " << (_master ? "master" : "slave"));
_init_peripherals();
_init_defaults();
-
- fs_path gain_mode_path = _root_path.branch_path()
- / str(boost::format("Radio_%d") % ((get_block_id().get_block_count()/2)*2))
- / "args/0/gain_mode/value";
- UHD_LOG_DEBUG("GAIN_MODE_STRING","Gain mode path " << gain_mode_path);
- std::string gain_mode = _tree->access<std::string>(gain_mode_path).get();
- UHD_LOG_DEBUG("GAIN_MODE_STRING","Gain mode string" << gain_mode);
- //////// REST OF CTOR IS PROP TREE SETUP //////////////////////////////////
-
- /**** Set up legacy compatible properties ******************************/
- // For use with multi_usrp APIs etc.
- // For legacy prop tree init:
- // TODO: determine DB number
- const fs_path fe_base = fs_path("dboards") / _radio_slot;
- const std::vector<uhd::direction_t> dir({ RX_DIRECTION, TX_DIRECTION });
- const std::vector<std::string> fe({ "rx_frontends", "tx_frontends" });
- const std::vector<std::string> ant({ "RX" , "TX" });
- const std::vector<size_t> num_chans({ MAGNESIUM_NUM_RX_CHANS , MAGNESIUM_NUM_TX_CHANS });
- const size_t RX_IDX = 0;
- // const size_t TX_IDX = 1;
- //this->_dsa_set_gain(0.5,0,RX_DIRECTION);
- for (size_t fe_idx = 0; fe_idx < fe.size(); ++fe_idx)
- {
- const fs_path fe_direction_path = fe_base / fe[fe_idx];
- for (size_t chan = 0; chan < num_chans[fe_idx]; ++chan)
- {
- const fs_path fe_path = fe_direction_path / chan;
- UHD_LOG_TRACE("MAGNESIUM", "Adding FE at " << fe_path);
- // Shared TX/RX attributes
- _tree->create<std::string>(fe_path / "name")
- .set(str(boost::format("Magnesium %s %d") % ant[fe_idx] % chan))
- ;
- _tree->create<std::string>(fe_path / "connection")
- .set("IQ")
- ;
- {
- // TODO: fix antenna name
- // Now witness the firepower of this fully armed and operational lambda
- auto dir_ = dir[fe_idx];
- auto coerced_lambda = [this, chan, dir_](const std::string &ant)
- {
- return this->_myk_set_antenna(ant, chan, dir_);
- };
- auto publisher_lambda = [this, chan, dir_]()
- {
- return this->_myk_get_antenna(chan, dir_);
- };
- _tree->create<std::string>(fe_path / "antenna" / "value")
- .set(str(boost::format("%s%d") % ant[fe_idx] % (chan + 1)))
- .add_coerced_subscriber(coerced_lambda)
- .set_publisher(publisher_lambda);
- // TODO: fix options
- _tree->create<std::vector<std::string>>(fe_path / "antenna" / "options")
- .set(std::vector<std::string>(1, str(boost::format("%s%d") % ant[fe_idx] % (chan + 1))));
- }
- {
- auto dir_ = dir[fe_idx];
- auto coerced_lambda = [this, chan, dir_](const double freq)
- {
- return this->_myk_set_frequency(freq, chan, dir_);
- };
- auto publisher_lambda = [this, chan, dir_]()
- {
- return this->_myk_get_frequency(chan, dir_);
- };
- _tree->create<double>(fe_path / "freq" / "value")
- .set(MAGNESIUM_CENTER_FREQ)
- .set_coercer(coerced_lambda)
- .set_publisher(publisher_lambda);
- _tree->create<meta_range_t>(fe_path / "freq" / "range")
- .set(meta_range_t(MAGNESIUM_MIN_FREQ, MAGNESIUM_MAX_FREQ));
- }
- {
- auto ad9371_min_gain = (fe_idx == RX_IDX) ? AD9371_MIN_RX_GAIN : AD9371_MIN_TX_GAIN;
- auto ad9371_max_gain = (fe_idx == RX_IDX) ? AD9371_MAX_RX_GAIN : AD9371_MAX_TX_GAIN;
- auto ad9371_gain_step = (fe_idx == RX_IDX) ? AD9371_RX_GAIN_STEP : AD9371_TX_GAIN_STEP;
- auto dsa_min_gain = DSA_MIN_GAIN;
- auto dsa_max_gain = DSA_MAX_GAIN;
- auto dsa_gain_step = DSA_GAIN_STEP;
- auto all_min_gain = (fe_idx == RX_IDX) ? ALL_RX_MIN_GAIN : ALL_TX_MIN_GAIN;
- auto all_max_gain = (fe_idx == RX_IDX) ? ALL_TX_MAX_GAIN : ALL_TX_MAX_GAIN;
- auto all_gain_step = 0.5;
- if (gain_mode == "auto"){
- ad9371_min_gain = 0;
- ad9371_max_gain = 0;
- ad9371_gain_step = 0;
- dsa_min_gain = 0;
- dsa_max_gain = 0;
- dsa_gain_step = 0;
- }
- if (gain_mode == "manual")
- {
- all_min_gain = 0 ;
- all_max_gain = 0 ;
- all_gain_step = 0 ;
-
- }
- auto dir_ = dir[fe_idx];
- //Create gain property for mykonos
- auto myk_set_gain_func = [this, chan, dir_](const double gain)
- {
- return this->_myk_set_gain(gain, chan, dir_);
- };
- auto myk_get_gain_func = [this, chan, dir_]()
- {
- return this->_myk_get_gain(chan, dir_);
- };
-
- _tree->create<double>(fe_path / "gains" / "ad9371" / "value")
- .set(0)
- .set_coercer(myk_set_gain_func)
- .set_publisher(myk_get_gain_func);
- _tree->create<meta_range_t>(fe_path / "gains" / "ad9371" / "range")
- .set(meta_range_t(ad9371_min_gain, ad9371_max_gain, ad9371_gain_step));
- // Create gain property for DSA
- auto dsa_set_gain_func = [this, chan, dir_](const double gain)
- {
- return this->_dsa_set_gain(gain, chan, dir_);
- };
- auto dsa_get_gain_func = [this, chan, dir_]()
- {
- return this->_dsa_get_gain(chan, dir_);
- };
- _tree->create<double>(fe_path / "gains" / "dsa" / "value")
- .set(0)
- .set_coercer(dsa_set_gain_func)
- .set_publisher(dsa_get_gain_func);
- _tree->create<meta_range_t>(fe_path / "gains" / "dsa" / "range")
- .set(meta_range_t(dsa_min_gain, dsa_max_gain, dsa_gain_step));
-
- // Create gain property for all gains
- auto set_all_gain_func = [this, chan, dir_](const double gain)
- {
- return this->_set_all_gain(gain, chan, dir_);
- };
- auto get_all_gain_func = [this, chan, dir_]()
- {
- return this->_get_all_gain(chan, dir_);
- };
- _tree->create<double>(fe_path / "gains" / "all" / "value")
- .set(0)
- .set_coercer(set_all_gain_func)
- .set_publisher(get_all_gain_func);
- _tree->create<meta_range_t>(fe_path / "gains" / "all" / "range")
- .set(meta_range_t(all_min_gain, all_max_gain, all_gain_step));
-
- }
- // TODO: set up read/write of bandwidth properties correctly
- if (fe_idx == RX_IDX)
- {
- auto coerced_lambda = [this, chan](const double bw)
- {
- return this->set_rx_bandwidth(bw, chan);
- };
- auto publisher_lambda = [this, chan]()
- {
- return this->get_rx_bandwidth(chan);
- };
- _tree->create<double>(fe_path / "bandwidth" / "value")
- .set(MAGNESIUM_DEFAULT_BANDWIDTH)
- .set_coercer(coerced_lambda)
- .set_publisher(publisher_lambda);
- }
- else {
- _tree->create<double>(fe_path / "bandwidth" / "value")
- .set(MAGNESIUM_DEFAULT_BANDWIDTH);
- }
- _tree->create<meta_range_t>(fe_path / "bandwidth" / "range")
- .set(meta_range_t(MAGNESIUM_DEFAULT_BANDWIDTH, MAGNESIUM_DEFAULT_BANDWIDTH));
- }
- }
-
- // 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(MAGNESIUM_TICK_RATE);
- }
+ _init_prop_tree();
}
magnesium_radio_ctrl_impl::~magnesium_radio_ctrl_impl()
{
- UHD_LOG_TRACE("MAGNESIUM", "magnesium_radio_ctrl_impl::dtor() ");
-}
-
-/**************************************************************************
- * Init Helpers
- *************************************************************************/
-void magnesium_radio_ctrl_impl::_init_peripherals()
-{
- UHD_LOG_TRACE("MAGNESIUM", "Initializing peripherals...");
- fs_path cpld_path = _root_path.branch_path()
- / str(boost::format("Radio_%d") % ((get_block_id().get_block_count()/2)*2))
- / "cpld";
- fs_path rx_lo_path = _root_path.branch_path()
- / str(boost::format("Radio_%d") % ((get_block_id().get_block_count()/2)*2))
- / "rx_lo";
- fs_path tx_lo_path = _root_path.branch_path()
- / str(boost::format("Radio_%d") % ((get_block_id().get_block_count()/2)*2))
- / "tx_lo";
- // TODO: When we move back to 2 chans per RFNoC block, this needs to be
- // non-conditional, and the else-branch goes away:
- if (_radio_slot == "A" or _radio_slot == "C") {
- UHD_LOG_TRACE("MAGNESIUM", "Initializing SPI core...");
- _spi = spi_core_3000::make(_get_ctrl(0),
- radio_ctrl_impl::regs::sr_addr(radio_ctrl_impl::regs::SPI),
- radio_ctrl_impl::regs::RB_SPI);
- } else {
- UHD_LOG_TRACE("MAGNESIUM", "Not a master radio, no SPI core.");
- }
-
- UHD_LOG_TRACE("MAGNESIUM", "Initializing CPLD...");
- UHD_LOG_TRACE("MAGNESIUM", "CPLD path: " << cpld_path);
- if (not _tree->exists(cpld_path)) {
- UHD_LOG_TRACE("MAGNESIUM", "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("MAGNESIUM", "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
- );
- }
- );
- _tree->create<magnesium_cpld_ctrl::sptr>(cpld_path).set(_cpld);
- } else {
- UHD_LOG_TRACE("MAGNESIUM", "Reusing someone else's CPLD object...");
- _cpld = _tree->access<magnesium_cpld_ctrl::sptr>(cpld_path).get();
- }
-
- // TODO: Same comment as above applies
- if (_radio_slot == "A" or _radio_slot == "C") {
- UHD_LOG_TRACE("MAGNESIUM", "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("MAGNESIUM", "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
- );
- }
- }
- );
- } else {
- UHD_LOG_TRACE("MAGNESIUM", "Not a master radio, no LOs.");
- }
- if (not _tree->exists(rx_lo_path)) {
- _tree->create<adf435x_iface::sptr>(rx_lo_path).set(_rx_lo);
- }else
- {
- UHD_LOG_TRACE("MAGNESIUM", "Not a master radio. Getting LO from master" );
- _rx_lo = _tree->access<adf435x_iface::sptr>(rx_lo_path).get();
- }
- if (not _tree->exists(tx_lo_path)) {
- _tree->create<adf435x_iface::sptr>(tx_lo_path).set(_tx_lo);
- }else
- {
- UHD_LOG_TRACE("MAGNESIUM", "Not a master radio. Getting LO from master" );
- _tx_lo = _tree->access<adf435x_iface::sptr>(tx_lo_path).get();
- }
-
- _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("MAGNESIUM",
- "Initializing GPIOs for channel " << radio_idx);
- _gpio.emplace_back(
- gpio_atr::gpio_atr_3000::make(
- _get_ctrl(radio_idx),
- regs::sr_addr(regs::GPIO),
- 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
- );
- }
- if (get_block_id().get_block_count() == FPGPIO_MASTER_RADIO) {
- UHD_LOG_TRACE(unique_id(), "Initializing front-panel GPIO control...")
- _fp_gpio = gpio_atr::gpio_atr_3000::make(
- _get_ctrl(0), regs::sr_addr(regs::FP_GPIO), regs::RB_FP_GPIO);
- }
-}
-
-void magnesium_radio_ctrl_impl::_init_defaults()
-{
- UHD_LOG_TRACE("MAGNESIUM", "Initializing defaults...");
- const size_t num_rx_chans = get_output_ports().size();
- //UHD_ASSERT_THROW(num_rx_chans == MAGNESIUM_NUM_RX_CHANS);
- const size_t num_tx_chans = get_input_ports().size();
- //UHD_ASSERT_THROW(num_tx_chans == MAGNESIUM_NUM_TX_CHANS);
-
- UHD_LOG_TRACE("MAGNESIUM",
- "Num TX chans: " << num_tx_chans
- << " Num RX chans: " << num_rx_chans);
- UHD_LOG_TRACE("MAGNESIUM",
- "Setting tick rate to " << MAGNESIUM_TICK_RATE / 1e6 << " MHz");
- radio_ctrl_impl::set_rate(MAGNESIUM_TICK_RATE);
-
- for (size_t chan = 0; chan < num_rx_chans; chan++) {
- radio_ctrl_impl::set_rx_frequency(MAGNESIUM_CENTER_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_CENTER_FREQ, chan);
- radio_ctrl_impl::set_tx_gain(0, chan);
- radio_ctrl_impl::set_tx_antenna(MAGNESIUM_DEFAULT_TX_ANTENNA, chan);
- }
+ UHD_LOG_TRACE(unique_id(), "magnesium_radio_ctrl_impl::dtor() ");
}
@@ -514,7 +107,7 @@ double magnesium_radio_ctrl_impl::set_rate(double rate)
{
// TODO: implement
if (rate != get_rate()) {
- UHD_LOG_WARNING("MAGNESIUM",
+ UHD_LOG_WARNING(unique_id(),
"Attempting to set sampling rate to invalid value " << rate);
}
return get_rate();
@@ -522,43 +115,134 @@ double magnesium_radio_ctrl_impl::set_rate(double rate)
void magnesium_radio_ctrl_impl::set_tx_antenna(
const std::string &ant,
- const size_t chan
+ const size_t /* chan */
) {
- _myk_set_antenna(ant, chan, TX_DIRECTION);
+ if (ant != MAGNESIUM_DEFAULT_TX_ANTENNA) {
+ throw uhd::value_error(str(
+ boost::format("[%s] Requesting invalid TX antenna value: %s")
+ % 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
) {
- _myk_set_antenna(ant, chan, RX_DIRECTION);
+ UHD_ASSERT_THROW(chan <= MAGNESIUM_NUM_CHANS);
+ // TODO can we please not hardcode the antenna names here?
+ // We need a map somewhere, anyway, to store the available options in the
+ // prop tree.
+ if (ant != "RX2" and ant != "TX/RX") {
+ throw uhd::value_error(str(
+ boost::format("[%s] Requesting invalid RX antenna value: %s")
+ % ant
+ ));
+ }
+
+ // TODO: When we go to 1 block per dboard, this entire if statement can go
+ // away.
+ if (not _master) {
+ // tbi
+ }
+
+ UHD_LOG_TRACE(unique_id(),
+ "Setting RX antenna to " << ant << " for chan " << chan);
+ magnesium_cpld_ctrl::chan_sel_t chan_sel =
+ _master ? 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 freq,
const size_t chan
) {
- return _myk_set_frequency(freq, chan, TX_DIRECTION);
+ // Note: There is only one LO per tx or TX, so changing frequency will
+ // affect the adjacent channel in the same direction. We have to make sure
+ // that getters will always tell the truth! This is true for low and high
+ // bands.
+ UHD_LOG_TRACE(unique_id(),
+ "set_tx_frequency(f=" << freq << ", chan=" << chan << ")");
+ _update_tx_freq_switches(freq, chan);
+ //double ad9371_freq = freq;
+ double if_freq = 0.0;
+ auto lo_iface = _tx_lo;
+
+ if (freq < MAGNESIUM_LOWBAND_FREQ) { // Low band
+ if_freq = MAGNESIUM_TX_IF_FREQ ;
+ const double lo_freq = if_freq - freq;
+ const bool int_n_mode = false; // FIXME no hardcode
+ const double ref_clk_freq = 100e6; // FIXME no hardcode
+ //const double actual_lo_freq =
+ _lo_enable(lo_iface, lo_freq, ref_clk_freq, int_n_mode);
+ //ad9371_freq = actual_lo_freq - freq;
+ } else {
+ _lo_disable(lo_iface);
+ }
+
+ //const double actual_ad9371_freq =
+ _ad9371->set_frequency(freq, chan, TX_DIRECTION);
+ radio_ctrl_impl::set_tx_frequency(freq, chan);
+ return freq; // FIXME calc the actual frequency
}
double magnesium_radio_ctrl_impl::set_rx_frequency(
const double freq,
const size_t chan
) {
- return _myk_set_frequency(freq, chan, RX_DIRECTION);
+ // Note: There is only one LO per RX or TX, so changing frequency will
+ // affect the adjacent channel in the same direction. We have to make sure
+ // that getters will always tell the truth! This is true for low and high
+ // bands.
+ UHD_LOG_TRACE(unique_id(),
+ "set_rx_frequency(f=" << freq << ", chan=" << chan << ")");
+ _update_rx_freq_switches(freq, chan);
+ //double ad9371_freq = freq;
+ double if_freq = 0.0;
+ auto lo_iface = _rx_lo;
+
+ if (freq < MAGNESIUM_LOWBAND_FREQ) { // Low band
+ if_freq = MAGNESIUM_RX_IF_FREQ ;
+ const double lo_freq = if_freq - freq;
+ const bool int_n_mode = false; // FIXME no hardcode
+ const double ref_clk_freq = 100e6; // FIXME no hardcode
+ //const double actual_lo_freq =
+ _lo_enable(lo_iface, lo_freq, ref_clk_freq, int_n_mode);
+ //ad9371_freq = actual_lo_freq - freq;
+ } else {
+ _lo_disable(lo_iface);
+ }
+
+ //const double actual_ad9371_freq =
+ _ad9371->set_frequency(freq, chan, RX_DIRECTION);
+ radio_ctrl_impl::set_rx_frequency(freq, chan);
+ return freq; // FIXME calc the actual frequency
}
double magnesium_radio_ctrl_impl::set_rx_bandwidth(
const double bandwidth,
const size_t chan
) {
- return _myk_set_bandwidth(bandwidth, chan, RX_DIRECTION);
+ radio_ctrl_impl::set_rx_bandwidth(bandwidth, chan);
+ return _ad9371->set_bandwidth(bandwidth, chan, RX_DIRECTION);
+}
+
+double magnesium_radio_ctrl_impl::set_tx_bandwidth(
+ const double bandwidth,
+ const size_t chan
+) {
+ //radio_ctrl_impl::set_rx_bandwidth(bandwidth, chan);
+ return _ad9371->set_bandwidth(bandwidth, chan, TX_DIRECTION);
}
double magnesium_radio_ctrl_impl::set_tx_gain(
const double gain,
const size_t chan
) {
+ radio_ctrl_impl::set_tx_gain(gain, chan);
return _set_all_gain(gain, chan, TX_DIRECTION);
}
@@ -566,68 +250,26 @@ double magnesium_radio_ctrl_impl::set_rx_gain(
const double gain,
const size_t chan
) {
-
+ UHD_LOG_TRACE(unique_id(),
+ "set_rx_gain(gain=" << gain << ", chan=" << chan << ")");
+ radio_ctrl_impl::set_rx_gain(gain, chan);
return _set_all_gain(gain, chan, RX_DIRECTION);
}
-std::string magnesium_radio_ctrl_impl::get_tx_antenna(
- const size_t chan
-) /* const */ {
- return _myk_get_antenna(chan, TX_DIRECTION);
-}
-
-std::string magnesium_radio_ctrl_impl::get_rx_antenna(
- const size_t chan
-) /* const */ {
- return _myk_get_antenna(chan, RX_DIRECTION);
-}
-
-double magnesium_radio_ctrl_impl::get_tx_frequency(
- const size_t chan
-) /* const */ {
- return _myk_get_frequency(chan, TX_DIRECTION);
-}
-
-double magnesium_radio_ctrl_impl::get_rx_frequency(
- const size_t chan
-) /* const */ {
- return _myk_get_frequency(chan, RX_DIRECTION);
-}
-
-double magnesium_radio_ctrl_impl::get_tx_gain(
- const size_t chan
-) /* const */ {
- return _get_all_gain(chan, TX_DIRECTION);
-}
-
-double magnesium_radio_ctrl_impl::get_rx_gain(
- const size_t chan
-) /* const */ {
- return _get_all_gain(chan, RX_DIRECTION);
-}
-
-double magnesium_radio_ctrl_impl::get_rx_bandwidth(
- const size_t chan
-) /* const */ {
- return _myk_get_bandwidth(chan, RX_DIRECTION);
-}
-
size_t magnesium_radio_ctrl_impl::get_chan_from_dboard_fe(
- const std::string &fe, const direction_t dir
+ const std::string &fe, const direction_t /* dir */
) {
- // UHD_LOG_TRACE("MAGNESIUM", "get_chan_from_dboard_fe " << fe << " returns " << boost::lexical_cast<size_t>(fe));
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
+ const direction_t /* dir */
) {
- // UHD_LOG_TRACE("MAGNESIUM", "get_dboard_fe_from_chan " << chan << " returns " << std::to_string(chan));
return std::to_string(chan);
}
-double magnesium_radio_ctrl_impl::get_output_samp_rate(size_t port)
+double magnesium_radio_ctrl_impl::get_output_samp_rate(size_t /* port */)
{
return MAGNESIUM_RADIO_RATE;
}
@@ -638,6 +280,13 @@ void magnesium_radio_ctrl_impl::set_rpc_client(
) {
_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" or _radio_slot == "B") ? 0 : 1
+ )
+ );
// EEPROM paths subject to change FIXME
const size_t db_idx = get_block_id().get_block_count();
@@ -656,396 +305,15 @@ void magnesium_radio_ctrl_impl::set_rpc_client(
/******************************************************************************
* Helpers
*****************************************************************************/
-fs_path magnesium_radio_ctrl_impl::_get_fe_path(size_t chan, direction_t dir)
-{
- switch (dir)
- {
- case TX_DIRECTION:
- return fs_path("dboards" / _radio_slot / "tx_frontends" / get_dboard_fe_from_chan(chan, TX_DIRECTION));
- case RX_DIRECTION:
- return fs_path("dboards" / _radio_slot / "rx_frontends" / get_dboard_fe_from_chan(chan, RX_DIRECTION));
- default:
- UHD_THROW_INVALID_CODE_PATH();
- }
-}
-
-void magnesium_radio_ctrl_impl::_update_atr_switches(
- const magnesium_cpld_ctrl::chan_sel_t chan,
- const direction_t dir,
- const std::string &ant
-){
- magnesium_cpld_ctrl::rx_sw1_t rx_sw1 = magnesium_cpld_ctrl::RX_SW1_RX2INPUT;
- magnesium_cpld_ctrl::sw_trx_t sw_trx = _sw_trx[chan];
-
- bool trx_led = false, rx2_led = true;
- //bool tx_pa_enb = true, tx_amp_enb = true, tx_myk_en=true;
- if (ant == "TX/RX" && dir== RX_DIRECTION)
- {
- rx_sw1 = magnesium_cpld_ctrl::RX_SW1_TRXSWITCHOUTPUT;
- sw_trx = magnesium_cpld_ctrl::SW_TRX_RXCHANNELPATH;
- trx_led = true;
- rx2_led = false;
- }
- UHD_LOG_TRACE("MAGNESIUM", "Update all atr related switches for " << dir << " " << ant );
- if (dir == RX_DIRECTION){
- _cpld->set_rx_atr_bits(
- magnesium_cpld_ctrl::BOTH,
- magnesium_cpld_ctrl::ON,
- rx_sw1,
- trx_led,
- rx2_led,
- true,
- true,
- true,
- true
- );
- _cpld->set_tx_atr_bits(
- magnesium_cpld_ctrl::BOTH,
- magnesium_cpld_ctrl::IDLE,
- false,
- sw_trx,
- false,
- false,
- false
- );
- _cpld->set_rx_atr_bits(
- chan,
- magnesium_cpld_ctrl::IDLE,
- rx_sw1,
- false,
- false,
- false,
- false,
- false,
- true
- );
- }
- if (dir == TX_DIRECTION){
- _cpld->set_tx_atr_bits(
- chan,
- magnesium_cpld_ctrl::ON,
- true,
- sw_trx,
- true,
- true,
- true
- );
- _cpld->set_rx_atr_bits(
- chan,
- magnesium_cpld_ctrl::IDLE,
- rx_sw1,
- false,
- false,
- false,
- false,
- false,
- true
- );
- };
-}
-
-void magnesium_radio_ctrl_impl::_update_freq_switches(
- const double freq,
- const size_t chan,
- const direction_t dir
-){
- UHD_LOG_TRACE("MAGNESIUM", "Update all freq related switches for " << freq);
- magnesium_cpld_ctrl::chan_sel_t chan_sel = (_radio_slot == "A" or _radio_slot == "C")? magnesium_cpld_ctrl::CHAN1 : magnesium_cpld_ctrl::CHAN2;
-
- // Set filters based on frequency
- if (dir == RX_DIRECTION) {
- if (freq < MAGNESIUM_RX_BAND1_MIN_FREQ) {
- _cpld->set_rx_switches(
- magnesium_cpld_ctrl::BOTH,
- magnesium_cpld_ctrl::RX_SW2_LOWERFILTERBANKTOSWITCH3,
- magnesium_cpld_ctrl::RX_SW3_FILTER0490LPMHZ,
- magnesium_cpld_ctrl::RX_SW4_FILTER2700HPMHZ,
- magnesium_cpld_ctrl::RX_SW5_FILTER0490LPMHZFROM,
- magnesium_cpld_ctrl::RX_SW6_LOWERFILTERBANKFROMSWITCH5,
- magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_LOBAND,
- true
- );
- } else if (freq < MAGNESIUM_RX_BAND2_MIN_FREQ) {
- _cpld->set_rx_switches(
- magnesium_cpld_ctrl::BOTH,
- magnesium_cpld_ctrl::RX_SW2_LOWERFILTERBANKTOSWITCH3,
- magnesium_cpld_ctrl::RX_SW3_FILTER0440X0530MHZ,
- magnesium_cpld_ctrl::RX_SW4_FILTER2700HPMHZ,
- magnesium_cpld_ctrl::RX_SW5_FILTER0440X0530MHZFROM,
- magnesium_cpld_ctrl::RX_SW6_LOWERFILTERBANKFROMSWITCH5,
- magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_BYPASS,
- false
- );
- } else if (freq < MAGNESIUM_RX_BAND3_MIN_FREQ) {
- _cpld->set_rx_switches(
- magnesium_cpld_ctrl::BOTH,
- magnesium_cpld_ctrl::RX_SW2_LOWERFILTERBANKTOSWITCH3,
- magnesium_cpld_ctrl::RX_SW3_FILTER0650X1000MHZ,
- magnesium_cpld_ctrl::RX_SW4_FILTER2700HPMHZ,
- magnesium_cpld_ctrl::RX_SW5_FILTER0650X1000MHZFROM,
- magnesium_cpld_ctrl::RX_SW6_LOWERFILTERBANKFROMSWITCH5,
- magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_BYPASS,
- false
- );
- } else if (freq < MAGNESIUM_RX_BAND4_MIN_FREQ) {
- _cpld->set_rx_switches(
- magnesium_cpld_ctrl::BOTH,
- magnesium_cpld_ctrl::RX_SW2_LOWERFILTERBANKTOSWITCH3,
- magnesium_cpld_ctrl::RX_SW3_FILTER1100X1575MHZ,
- magnesium_cpld_ctrl::RX_SW4_FILTER2700HPMHZ,
- magnesium_cpld_ctrl::RX_SW5_FILTER1100X1575MHZFROM,
- magnesium_cpld_ctrl::RX_SW6_LOWERFILTERBANKFROMSWITCH5,
- magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_BYPASS,
- false
- );
- } else if (freq < MAGNESIUM_RX_BAND5_MIN_FREQ) {
- _cpld->set_rx_switches(
- magnesium_cpld_ctrl::BOTH,
- magnesium_cpld_ctrl::RX_SW2_LOWERFILTERBANKTOSWITCH3,
- magnesium_cpld_ctrl::RX_SW3_FILTER1600X2250MHZ,
- magnesium_cpld_ctrl::RX_SW4_FILTER1600X2250MHZFROM,
- magnesium_cpld_ctrl::RX_SW5_FILTER0440X0530MHZFROM,
- magnesium_cpld_ctrl::RX_SW6_UPPERFILTERBANKFROMSWITCH4,
- magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_BYPASS,
- false
- );
- } else if (freq < MAGNESIUM_RX_BAND6_MIN_FREQ) {
- _cpld->set_rx_switches(
- magnesium_cpld_ctrl::BOTH,
- magnesium_cpld_ctrl::RX_SW2_LOWERFILTERBANKTOSWITCH3,
- magnesium_cpld_ctrl::RX_SW3_FILTER2100X2850MHZ,
- magnesium_cpld_ctrl::RX_SW4_FILTER2100X2850MHZFROM,
- magnesium_cpld_ctrl::RX_SW5_FILTER0440X0530MHZFROM,
- magnesium_cpld_ctrl::RX_SW6_UPPERFILTERBANKFROMSWITCH4,
- magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_BYPASS,
- false
- );
- } else {
- _cpld->set_rx_switches(
- magnesium_cpld_ctrl::BOTH,
- magnesium_cpld_ctrl::RX_SW2_UPPERFILTERBANKTOSWITCH4,
- magnesium_cpld_ctrl::RX_SW3_SHUTDOWNSW3,
- magnesium_cpld_ctrl::RX_SW4_FILTER2700HPMHZ,
- magnesium_cpld_ctrl::RX_SW5_FILTER0440X0530MHZFROM,
- magnesium_cpld_ctrl::RX_SW6_UPPERFILTERBANKFROMSWITCH4,
- magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_BYPASS,
- false
- );
- }
- } else {
- if (freq < MAGNESIUM_TX_BAND1_MIN_FREQ) {
- _cpld->set_tx_switches(
- magnesium_cpld_ctrl::BOTH,
- magnesium_cpld_ctrl::SW_TRX_FROMLOWERFILTERBANKTXSW1,
- magnesium_cpld_ctrl::TX_SW1_FROMTXFILTERLP0800MHZ,
- magnesium_cpld_ctrl::TX_SW2_TOTXFILTERLP0800MHZ,
- magnesium_cpld_ctrl::TX_SW3_TOTXFILTERBANKS,
- magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_LOBAND,
- true,
- magnesium_cpld_ctrl::ON
- );
- _sw_trx[chan_sel] = magnesium_cpld_ctrl::SW_TRX_FROMLOWERFILTERBANKTXSW1;
- } else if (freq < MAGNESIUM_TX_BAND2_MIN_FREQ) {
- _cpld->set_tx_switches(
- magnesium_cpld_ctrl::BOTH,
- magnesium_cpld_ctrl::SW_TRX_FROMLOWERFILTERBANKTXSW1,
- magnesium_cpld_ctrl::TX_SW1_FROMTXFILTERLP0800MHZ,
- magnesium_cpld_ctrl::TX_SW2_TOTXFILTERLP0800MHZ,
- magnesium_cpld_ctrl::TX_SW3_TOTXFILTERBANKS,
- magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_BYPASS,
- false,
- magnesium_cpld_ctrl::ON
- );
- _sw_trx[chan_sel] = magnesium_cpld_ctrl::SW_TRX_FROMLOWERFILTERBANKTXSW1;
- } else if (freq < MAGNESIUM_TX_BAND3_MIN_FREQ) {
- _cpld->set_tx_switches(
- magnesium_cpld_ctrl::BOTH,
- magnesium_cpld_ctrl::SW_TRX_FROMLOWERFILTERBANKTXSW1,
- magnesium_cpld_ctrl::TX_SW1_FROMTXFILTERLP1700MHZ,
- magnesium_cpld_ctrl::TX_SW2_TOTXFILTERLP1700MHZ,
- magnesium_cpld_ctrl::TX_SW3_TOTXFILTERBANKS,
- magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_BYPASS,
- false,
- magnesium_cpld_ctrl::ON
- );
- _sw_trx[chan_sel] = magnesium_cpld_ctrl::SW_TRX_FROMLOWERFILTERBANKTXSW1;
- } else if (freq < MAGNESIUM_TX_BAND4_MIN_FREQ) {
- _cpld->set_tx_switches(
- magnesium_cpld_ctrl::BOTH,
- magnesium_cpld_ctrl::SW_TRX_FROMLOWERFILTERBANKTXSW1,
- magnesium_cpld_ctrl::TX_SW1_FROMTXFILTERLP3400MHZ,
- magnesium_cpld_ctrl::TX_SW2_TOTXFILTERLP3400MHZ,
- magnesium_cpld_ctrl::TX_SW3_TOTXFILTERBANKS,
- magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_BYPASS,
- false,
- magnesium_cpld_ctrl::ON
- );
- _sw_trx[chan_sel] = magnesium_cpld_ctrl::SW_TRX_FROMLOWERFILTERBANKTXSW1;
- } else {
- _cpld->set_tx_switches(
- magnesium_cpld_ctrl::BOTH,
- magnesium_cpld_ctrl::SW_TRX_FROMTXUPPERFILTERBANKLP6400MHZ,
- magnesium_cpld_ctrl::TX_SW1_SHUTDOWNTXSW1,
- magnesium_cpld_ctrl::TX_SW2_TOTXFILTERLP6400MHZ,
- magnesium_cpld_ctrl::TX_SW3_TOTXFILTERBANKS,
- magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_BYPASS,
- false,
- magnesium_cpld_ctrl::ON
- );
- _sw_trx[chan_sel] = magnesium_cpld_ctrl::SW_TRX_FROMTXUPPERFILTERBANKLP6400MHZ;
- }
- }
- UHD_LOG_INFO("MAGNESIUM", "Update all freq related switches for " << freq <<" finished!.");
-}
-/******************************************************************************
- * AD9371 Controls
- *****************************************************************************/
-double magnesium_radio_ctrl_impl::_myk_set_frequency(
- const double freq,
- const size_t chan,
- const direction_t dir
-) {
-
-
- // Note: There is only one LO per RX or TX, so changing frequency will
- // affect the adjacent channel in the same direction. We have to make sure
- // that getters will always tell the truth!
- auto which = _get_which(dir,_radio_slot);
- UHD_LOG_TRACE("MAGNESIUM", "requested frequency of " << freq);
- _update_freq_switches(freq,chan,dir);
- double ad9371_freq = freq;
- auto lo_iface = (dir == RX_DIRECTION) ? _rx_lo : _tx_lo;
-
- if (freq < MAGNESIUM_LOWBAND_FREQ) { // Low band
- UHD_LOG_WARNING("LO BAND", "requested frequency of " << freq);
- double if_freq = (dir == RX_DIRECTION) ? MAGNESIUM_RX_IF_FREQ
- : MAGNESIUM_TX_IF_FREQ;
- double lo_freq = if_freq - freq;
- _lo_set_frequency(lo_iface, lo_freq, chan);
- lo_iface->set_output_enable(adf435x_iface::RF_OUTPUT_A, true); // TODO: Find correct value
- lo_iface->set_output_enable(adf435x_iface::RF_OUTPUT_B, true); // TODO: Find correct value
- lo_iface->commit();
- ad9371_freq = if_freq;
- } else {
- UHD_LOG_WARNING("HI BAND", "requested frequency of " << freq);
- lo_iface->set_output_enable(adf435x_iface::RF_OUTPUT_A, false); // TODO: Find correct value
- lo_iface->set_output_enable(adf435x_iface::RF_OUTPUT_B, false); // TODO: Find correct value
- lo_iface->commit();
- }
-
- UHD_LOG_TRACE("MAGNESIUM",
- "Calling " << _rpc_prefix << "set_freq on " << which << " with " << ad9371_freq);
- auto retval = _rpcc->request_with_token<double>(_rpc_prefix + "set_freq", which, ad9371_freq, false);
- UHD_LOG_TRACE("MAGNESIUM",
- _rpc_prefix << "set_freq returned " << retval);
-
-
- return retval;
-}
-
-double magnesium_radio_ctrl_impl::_myk_set_gain(
- const double gain,
- const size_t chan,
- const direction_t dir
-) {
- auto which = _get_which(dir,_radio_slot);
- UHD_LOG_TRACE("MAGNESIUM", "Calling " << _rpc_prefix << "set_gain on " << which << " with " << gain);
- auto retval = _rpcc->request_with_token<double>(_rpc_prefix + "set_gain", which, gain);
- UHD_LOG_TRACE("MAGNESIUM", _rpc_prefix << "set_gain returned " << retval);
-
- return retval;
- //return 0.0;
-}
-
-void magnesium_radio_ctrl_impl::_myk_set_antenna(
- const std::string &ant,
- const size_t chan,
- const direction_t dir
-) {
- // TODO: implement
- UHD_LOG_WARNING("MAGNESIUM", "Attempting to set antenna " << ant << " " << chan << " " << dir );
- magnesium_cpld_ctrl::chan_sel_t chan_sel = (_radio_slot == "A" or _radio_slot == "C")? magnesium_cpld_ctrl::CHAN1 : magnesium_cpld_ctrl::CHAN2;
- _update_atr_switches(chan_sel,dir,ant);
-}
-
-double magnesium_radio_ctrl_impl::_myk_set_bandwidth(const double bandwidth, const size_t chan, const direction_t dir)
-{
- // TODO: implement
- UHD_LOG_WARNING("MAGNESIUM", "Ignoring attempt to set bandwidth");
- return get_rx_bandwidth(chan);
-}
-
-double magnesium_radio_ctrl_impl::_myk_get_frequency(const size_t chan, const direction_t dir)
-{
- auto which = _get_which(dir,_radio_slot);
- UHD_LOG_TRACE("MAGNESIUM", "calling " << _rpc_prefix << "get_freq on " << which);
- auto retval = _rpcc->request_with_token<double>(_rpc_prefix + "get_freq", which);
- UHD_LOG_TRACE("MAGNESIUM", _rpc_prefix << "get_freq returned " << retval);
- return retval;
-}
-
-double magnesium_radio_ctrl_impl::_myk_get_gain(const size_t chan, const direction_t dir)
-{
- auto which = _get_which(dir,_radio_slot);
- UHD_LOG_TRACE("MAGNESIUM", "calling " << _rpc_prefix << "get_gain on " << which);
- auto retval = _rpcc->request_with_token<double>(_rpc_prefix + "get_gain", which);
- UHD_LOG_TRACE("MAGNESIUM", _rpc_prefix << "get_gain returned " << retval);
- return retval;
-}
-
-std::string magnesium_radio_ctrl_impl::_myk_get_antenna(const size_t chan, const direction_t dir)
-{
- // TODO: implement
- UHD_LOG_WARNING("MAGNESIUM", "Ignoring attempt to get antenna");
- return "RX1";
- // CPLD control?
-}
-
-double magnesium_radio_ctrl_impl::_myk_get_bandwidth(const size_t chan, const direction_t dir)
-{
- // TODO: implement
- UHD_LOG_WARNING("MAGNESIUM", "Ignoring attempt to get bandwidth");
- return MAGNESIUM_DEFAULT_BANDWIDTH;
-}
-
-/******************************************************************************
- * ADF4351 Controls
- *****************************************************************************/
-double magnesium_radio_ctrl_impl::_lo_set_frequency(
- adf435x_iface::sptr lo_iface,
- const double freq,
- const size_t chan
-) {
-
- UHD_LOG_TRACE("MAGNESIUM", "attempting to tune low band LO to " << freq);
- lo_iface->set_feedback_select(adf435x_iface::FB_SEL_DIVIDED);
- lo_iface->set_reference_freq(100e6); // FIXME: How to get refclk freq? This can change.
- lo_iface->set_prescaler(adf435x_iface::PRESCALER_4_5);
-
- double actual_freq = 0.0;
- actual_freq = lo_iface->set_frequency(freq, false); // FIXME: always fractional-n mode
- UHD_LOG_TRACE("MAGNESIUM", "actual low band LO is " << actual_freq);
- lo_iface->set_output_power(adf435x_iface::RF_OUTPUT_A, adf435x_iface::OUTPUT_POWER_2DBM); // TODO: Find correct value
- lo_iface->set_output_power(adf435x_iface::RF_OUTPUT_B, adf435x_iface::OUTPUT_POWER_2DBM); // TODO: Find correct value
- lo_iface->set_charge_pump_current(adf435x_iface::CHARGE_PUMP_CURRENT_0_31MA);
-
- // TODO: Check for PLL lock
- //sleep(1);
- //auto lock_det = _rpcc->request_with_token<uint16_t>(_slot_prefix + "cpld_peek", 0x12);
- //UHD_LOG_TRACE("MAGNESIUM", "lock detect is " << lock_det);
-
- return actual_freq;
-}
double magnesium_radio_ctrl_impl::_set_all_gain(
const double gain,
const size_t chan,
const direction_t dir
-)
-{
- UHD_LOG_TRACE("MAGNESIUM", "Setting all gain " << gain);
+) {
+ UHD_LOG_TRACE(unique_id(), "Setting all gain " << gain);
// just naively distributed gain here
- _myk_set_gain(gain/2,chan,dir);
- _dsa_set_gain(gain/2,chan,dir);
+ _ad9371->set_gain(gain/2, chan, dir);
+ _dsa_set_gain(gain/2, chan, dir);
if(dir == RX_DIRECTION or dir == DX_DIRECTION)
{
_all_rx_gain = gain;
@@ -1057,70 +325,62 @@ double magnesium_radio_ctrl_impl::_set_all_gain(
return gain;
}
+
double magnesium_radio_ctrl_impl::_get_all_gain(
- const size_t chan,
+ const size_t /* chan */,
const direction_t dir
-)
-{
- UHD_LOG_TRACE("MAGNESIUM", "Getting all gain ");
- if(dir == RX_DIRECTION )
- {
+) {
+ UHD_LOG_TRACE(unique_id(), "Getting all gain ");
+ if (dir == RX_DIRECTION) {
return _all_rx_gain;
}
- if(dir == TX_DIRECTION)
- {
- return _all_tx_gain;
- }
-
+ return _all_tx_gain;
}
-double magnesium_radio_ctrl_impl::_dsa_set_gain(
+
+/******************************************************************************
+ * DSA Controls
+ *****************************************************************************/
+double magnesium_radio_ctrl_impl::_dsa_set_gain(
const double gain,
const size_t chan,
const direction_t dir
) {
-
uint32_t dsa_val = 63-2*gain;
- UHD_LOG_TRACE("MAGNESIUM", "Setting dsa gain " << dsa_val);
+ UHD_LOG_TRACE(unique_id(), "Setting dsa gain " << dsa_val);
_set_dsa_val(chan, dir, dsa_val);
- if(dir == RX_DIRECTION or dir == DX_DIRECTION)
- {
+ if (dir == RX_DIRECTION or dir == DX_DIRECTION) {
_dsa_rx_gain = gain;
}
- if(dir == TX_DIRECTION or dir == DX_DIRECTION)
- {
+ if (dir == TX_DIRECTION or dir == DX_DIRECTION) {
_dsa_tx_gain = gain;
}
return gain;
}
-double magnesium_radio_ctrl_impl::_dsa_get_gain(
- const size_t chan,
- const direction_t dir
- ){
- UHD_LOG_TRACE("MAGNESIUM", "Getting dsa gain ");
- if(dir == RX_DIRECTION )
- {
- return _dsa_rx_gain;
- }
- if(dir == TX_DIRECTION)
- {
- return _dsa_tx_gain;
- }
+double magnesium_radio_ctrl_impl::_dsa_get_gain(
+ const size_t /*chan*/,
+ const direction_t dir
+) {
+ if (dir == RX_DIRECTION) {
+ return _dsa_rx_gain;
+ }
+ return _dsa_tx_gain;
}
-/******************************************************************************
- * DSA Controls
- *****************************************************************************/
+
void magnesium_radio_ctrl_impl::_set_dsa_val(
const size_t chan,
const direction_t dir,
- const uint32_t dsa_val
+ const uint32_t dsa_val
) {
- UHD_LOG_TRACE("MAGNESIUM", "Setting dsa value" << dsa_val);
if (dir == RX_DIRECTION or dir == DX_DIRECTION){
+ UHD_LOG_TRACE(unique_id(),
+ "Chan: " << chan << " Setting RX DSA value" << dsa_val);
_gpio[chan]->set_gpio_out(dsa_val, 0x3F);
}
if (dir == TX_DIRECTION or dir == DX_DIRECTION){
+ UHD_LOG_TRACE(unique_id(),
+ "Chan: " << chan << " Setting TX DSA value" << dsa_val);
_gpio[chan]->set_gpio_out(dsa_val, 0x0FC0);
}
}
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.hpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.hpp
index e2cfab304..cf9ba765d 100644
--- a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.hpp
+++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.hpp
@@ -22,6 +22,7 @@
#include "rpc_block_ctrl.hpp"
#include "magnesium_cpld_ctrl.hpp"
#include "magnesium_cpld_regs.hpp"
+#include "magnesium_ad9371_iface.hpp"
#include "adf435x.hpp"
#include "gpio_atr_3000.hpp"
#include <uhd/types/serial.hpp>
@@ -47,6 +48,8 @@ public:
/************************************************************************
* 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);
@@ -54,21 +57,12 @@ public:
double set_tx_frequency(const double freq, const size_t chan);
double set_rx_frequency(const double freq, 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);
double set_tx_gain(const double gain, const size_t chan);
double set_rx_gain(const double gain, const size_t chan);
- std::string get_tx_antenna(const size_t chan);
- std::string get_rx_antenna(const size_t chan);
-
- double get_tx_frequency(const size_t chan);
- double get_rx_frequency(const size_t chan);
- double get_rx_bandwidth(const size_t chan);
-
- double get_tx_gain(const size_t chan);
- double get_rx_gain(const size_t chan);
-
size_t get_chan_from_dboard_fe(const std::string &fe, const direction_t dir);
std::string get_dboard_fe_from_chan(const size_t chan, const direction_t dir);
@@ -83,70 +77,64 @@ private:
/**************************************************************************
* Helpers
*************************************************************************/
- //! Return the path to the dboards property subtree
- fs_path _get_fe_path(const size_t chan, const direction_t dir);
-
//! Initialize all the peripherals connected to this block
void _init_peripherals();
//! Set state of this class to sensible defaults
void _init_defaults();
- /**************************************************************************
- * AD9371 Controls
- *************************************************************************/
- double _myk_set_frequency(
- const double freq,
- const size_t chan,
- const direction_t dir
+ //! Init a subtree for the RF frontends
+ void _init_frontend_subtree(
+ uhd::property_tree::sptr subtree,
+ const size_t fe_chan_idx,
+ const size_t chan_idx
);
- double _myk_set_gain(
+ //! Initialize property tree
+ void _init_prop_tree();
+
+ /**************************************************************************
+ * Gain Controls (implemented in magnesium_radio_ctrl_gain.cpp)
+ *************************************************************************/
+ double _dsa_set_gain(
const double gain,
const size_t chan,
const direction_t dir
);
- void _myk_set_antenna(
- const std::string &ant,
- const size_t chan,
- const direction_t dir
- );
- double _myk_set_bandwidth(
- const double bandwidth,
+ double _dsa_get_gain(
const size_t chan,
const direction_t dir
);
- double _myk_get_frequency(
- const size_t chan,
- const direction_t dir
+ double _set_all_gain(
+ const double gain,
+ const size_t chan,
+ const direction_t dir
);
- double _myk_get_gain(
- const size_t chan,
- const direction_t dir
+ double _get_all_gain(
+ const size_t chan,
+ const direction_t dir
);
- std::string _myk_get_antenna(
+ void _set_dsa_val(
const size_t chan,
- const direction_t dir
+ const direction_t dir,
+ const uint32_t dsa_val
);
- double _myk_get_bandwidth(
- const size_t chan,
- const direction_t dir
+ /**************************************************************************
+ * CPLD Controls (implemented in magnesium_radio_ctrl_cpld.cpp)
+ *************************************************************************/
+ void _update_rx_freq_switches(
+ const double freq,
+ const size_t chan
);
- double _lo_set_frequency(
- adf435x_iface::sptr lo_iface,
- const double freq,
- const size_t chan
- );
- void _update_freq_switches(
+ void _update_tx_freq_switches(
const double freq,
- const size_t chan,
- const direction_t dir
+ const size_t chan
);
void _update_atr_switches(
@@ -155,34 +143,15 @@ private:
const std::string &ant
);
- double _dsa_set_gain(
- const double gain,
- const size_t chan,
- const direction_t dir
- );
- double _dsa_get_gain(
- const size_t chan,
- const direction_t dir
- );
- double _set_all_gain(
- const double gain,
- const size_t chan,
- const direction_t dir
- );
- double _get_all_gain(
- const size_t chan,
- const direction_t dir
- );
- void _set_dsa_val(
- const size_t chan,
- const direction_t dir,
- const uint32_t dsa_val
- );
+ /**************************************************************************
+ * Private attributes
+ *************************************************************************/
//! Letter representation of the radio we're currently running
std::string _radio_slot;
- //! Stores the prefix to RPC calls
- std::string _rpc_prefix;
+ //! If true, this is a master radio. This attribute will go away when we
+ // move back to 1 radio block per dboard.
+ bool _master;
//! Additional block args; gets set during set_rpc_client()
uhd::device_addr_t _block_args;
@@ -203,6 +172,9 @@ private:
// there's only one CPLD control.
std::shared_ptr<magnesium_cpld_ctrl> _cpld;
+ //! Reference to the AD9371 controls
+ magnesium_ad9371_iface::uptr _ad9371;
+
//! ATR controls. These control the external DSA and the AD9371 gain
// up/down bits. They do *not* control the ATR state of the CPLD, the
// tx/rx run states are hooked up directly to the CPLD.
@@ -222,10 +194,12 @@ private:
//! All gain
double _all_rx_gain = 0.0;
double _all_tx_gain = 0.0;
- //! TRX switch state of 2 channels
- std::map<magnesium_cpld_ctrl::chan_sel_t,magnesium_cpld_ctrl::sw_trx_t> _sw_trx = {
- {magnesium_cpld_ctrl::CHAN1, magnesium_cpld_ctrl::SW_TRX_FROMLOWERFILTERBANKTXSW1},
- {magnesium_cpld_ctrl::CHAN2, magnesium_cpld_ctrl::SW_TRX_FROMLOWERFILTERBANKTXSW1}
+ //! TRX switch state of 2 channels
+ std::map<magnesium_cpld_ctrl::chan_sel_t, magnesium_cpld_ctrl::sw_trx_t> _sw_trx = {
+ {magnesium_cpld_ctrl::CHAN1,
+ magnesium_cpld_ctrl::SW_TRX_FROMLOWERFILTERBANKTXSW1},
+ {magnesium_cpld_ctrl::CHAN2,
+ magnesium_cpld_ctrl::SW_TRX_FROMLOWERFILTERBANKTXSW1}
};
}; /* class radio_ctrl_impl */
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_init.cpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_init.cpp
new file mode 100644
index 000000000..ed5cb61c3
--- /dev/null
+++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_init.cpp
@@ -0,0 +1,487 @@
+//
+// Copyright 2017 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0
+//
+
+#include "magnesium_radio_ctrl_impl.hpp"
+#include "magnesium_constants.hpp"
+#include "spi_core_3000.hpp"
+#include <uhd/utils/log.hpp>
+#include <uhd/types/eeprom.hpp>
+#include <vector>
+#include <string>
+
+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
+ };
+}
+
+void magnesium_radio_ctrl_impl::_init_peripherals()
+{
+ UHD_LOG_TRACE(unique_id(), "Initializing peripherals...");
+ fs_path cpld_path = _root_path.branch_path()
+ / str(boost::format("Radio_%d") % ((get_block_id().get_block_count()/2)*2))
+ / "cpld";
+ fs_path rx_lo_path = _root_path.branch_path()
+ / str(boost::format("Radio_%d") % ((get_block_id().get_block_count()/2)*2))
+ / "rx_lo";
+ fs_path tx_lo_path = _root_path.branch_path()
+ / str(boost::format("Radio_%d") % ((get_block_id().get_block_count()/2)*2))
+ / "tx_lo";
+ // TODO: When we move back to 2 chans per RFNoC block, this needs to be
+ // non-conditional, and the else-branch goes away:
+ if (_master) {
+ UHD_LOG_TRACE(unique_id(), "Initializing SPI core...");
+ _spi = spi_core_3000::make(_get_ctrl(0),
+ radio_ctrl_impl::regs::sr_addr(radio_ctrl_impl::regs::SPI),
+ radio_ctrl_impl::regs::RB_SPI);
+ } else {
+ UHD_LOG_TRACE(unique_id(), "Not a master radio, no SPI core.");
+ }
+
+ UHD_LOG_TRACE(unique_id(), "Initializing CPLD...");
+ UHD_LOG_TRACE(unique_id(), "CPLD path: " << cpld_path);
+ if (not _tree->exists(cpld_path)) {
+ 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
+ );
+ }
+ );
+ _tree->create<magnesium_cpld_ctrl::sptr>(cpld_path).set(_cpld);
+ } else {
+ UHD_LOG_TRACE(unique_id(), "Reusing someone else's CPLD object...");
+ _cpld = _tree->access<magnesium_cpld_ctrl::sptr>(cpld_path).get();
+ }
+
+ // TODO: Same comment as above applies
+ if (_master) {
+ 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
+ );
+ }
+ }
+ );
+ } else {
+ UHD_LOG_TRACE(unique_id(), "Not a master radio, no LOs.");
+ }
+ if (not _tree->exists(rx_lo_path)) {
+ _tree->create<adf435x_iface::sptr>(rx_lo_path).set(_rx_lo);
+ } else {
+ UHD_LOG_TRACE(unique_id(), "Not a master radio. Getting LO from master" );
+ _rx_lo = _tree->access<adf435x_iface::sptr>(rx_lo_path).get();
+ }
+ if (not _tree->exists(tx_lo_path)) {
+ _tree->create<adf435x_iface::sptr>(tx_lo_path).set(_tx_lo);
+ } else {
+ UHD_LOG_TRACE(unique_id(), "Not a master radio. Getting LO from master" );
+ _tx_lo = _tree->access<adf435x_iface::sptr>(tx_lo_path).get();
+ }
+
+ _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_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
+ );
+ }
+ if (get_block_id().get_block_count() == FPGPIO_MASTER_RADIO) {
+ 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_FP_GPIO);
+ }
+}
+
+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);
+ UHD_LOG_TRACE(unique_id(),
+ "Setting tick rate to " << MAGNESIUM_TICK_RATE / 1e6 << " MHz");
+ radio_ctrl_impl::set_rate(MAGNESIUM_TICK_RATE);
+
+ for (size_t chan = 0; chan < num_rx_chans; chan++) {
+ radio_ctrl_impl::set_rx_frequency(MAGNESIUM_CENTER_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_CENTER_FREQ, chan);
+ radio_ctrl_impl::set_tx_gain(0, chan);
+ radio_ctrl_impl::set_tx_antenna(MAGNESIUM_DEFAULT_TX_ANTENNA, chan);
+ }
+}
+
+void magnesium_radio_ctrl_impl::_init_frontend_subtree(
+ uhd::property_tree::sptr subtree,
+ const size_t fe_chan_idx,
+ const size_t chan_idx
+) {
+ const fs_path tx_fe_path = fs_path("tx_frontends") / fe_chan_idx;
+ const fs_path rx_fe_path = fs_path("rx_frontends") / fe_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_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);
+ return 0.0; // FIXME
+ })
+ ;
+ subtree->create<meta_range_t>(tx_fe_path / "bandwidth" / "range")
+ .set(meta_range_t(0.0, 0.0, 0.0)) // FIXME
+ .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_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(meta_range_t(0.0, 0.0, 0.0)) // FIXME
+ .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 this->get_tx_gain(chan_idx);
+ })
+ ;
+ subtree->create<meta_range_t>(tx_fe_path / "gains" / "all" / "range")
+ .set(meta_range_t(0.0, 60.0, 1.0)) // FIXME
+ .add_coerced_subscriber([](const meta_range_t &){
+ throw uhd::runtime_error(
+ "Attempting to update bandwidth range!");
+ })
+ ;
+ // RX gains
+ subtree->create<double>(rx_fe_path / "gains" / "all" / "value")
+ .set_coercer([this, chan_idx](const double gain){
+ UHD_VAR(gain);
+ return this->set_rx_gain(gain, chan_idx);
+ })
+ .set_publisher([this, chan_idx](){
+ return this->get_rx_gain(chan_idx);
+ })
+ ;
+ subtree->create<meta_range_t>(rx_fe_path / "gains" / "all" / "range")
+ .set(meta_range_t(0.0, 60.0, 1.0)) // FIXME
+ .add_coerced_subscriber([](const meta_range_t &){
+ throw uhd::runtime_error(
+ "Attempting to update bandwidth range!");
+ })
+ ;
+ // FIXME separate DSA and Myk gains
+}
+
+void magnesium_radio_ctrl_impl::_init_prop_tree()
+{
+ fs_path gain_mode_path =
+ _root_path.branch_path()
+ / str(boost::format("Radio_%d") % ((get_block_id().get_block_count()/2)*2))
+ / "args/0/gain_mode/value";
+ UHD_LOG_DEBUG("GAIN_MODE_STRING","Gain mode path " << gain_mode_path);
+ std::string gain_mode = _tree->access<std::string>(gain_mode_path).get();
+ UHD_LOG_DEBUG("GAIN_MODE_STRING","Gain mode string" << gain_mode);
+
+ /**** Set up legacy compatible properties ******************************/
+ // For use with multi_usrp APIs etc.
+ // For legacy prop tree init:
+ // TODO: determine DB number
+ const fs_path fe_base = fs_path("dboards") / _radio_slot;
+ const std::vector<uhd::direction_t> dir({ RX_DIRECTION, TX_DIRECTION });
+ const std::vector<std::string> fe({ "rx_frontends", "tx_frontends" });
+ const std::vector<std::string> ant({ "RX" , "TX" });
+ //const size_t RX_IDX = 0;
+ // const size_t TX_IDX = 1;
+ //this->_dsa_set_gain(0.5,0,RX_DIRECTION);
+ for (size_t fe_idx = 0; fe_idx < fe.size(); ++fe_idx)
+ {
+ const fs_path fe_direction_path = fe_base / fe[fe_idx];
+ for (size_t chan = 0; chan < MAGNESIUM_NUM_CHANS; ++chan)
+ {
+ const fs_path fe_path = fe_direction_path / chan;
+ UHD_LOG_TRACE(unique_id(), "Adding FE at " << fe_path);
+ // Shared TX/RX attributes
+ //{
+ //auto ad9371_min_gain = (fe_idx == RX_IDX) ? AD9371_MIN_RX_GAIN : AD9371_MIN_TX_GAIN;
+ //auto ad9371_max_gain = (fe_idx == RX_IDX) ? AD9371_MAX_RX_GAIN : AD9371_MAX_TX_GAIN;
+ //auto ad9371_gain_step = (fe_idx == RX_IDX) ? AD9371_RX_GAIN_STEP : AD9371_TX_GAIN_STEP;
+ //auto dsa_min_gain = DSA_MIN_GAIN;
+ //auto dsa_max_gain = DSA_MAX_GAIN;
+ //auto dsa_gain_step = DSA_GAIN_STEP;
+ //auto all_min_gain = (fe_idx == RX_IDX) ? ALL_RX_MIN_GAIN : ALL_TX_MIN_GAIN;
+ //auto all_max_gain = (fe_idx == RX_IDX) ? ALL_TX_MAX_GAIN : ALL_TX_MAX_GAIN;
+ //auto all_gain_step = 0.5;
+ //if (gain_mode == "auto"){
+ //ad9371_min_gain = 0;
+ //ad9371_max_gain = 0;
+ //ad9371_gain_step = 0;
+ //dsa_min_gain = 0;
+ //dsa_max_gain = 0;
+ //dsa_gain_step = 0;
+ //}
+ //if (gain_mode == "manual")
+ //{
+ //all_min_gain = 0 ;
+ //all_max_gain = 0 ;
+ //all_gain_step = 0 ;
+
+ //}
+ //auto dir_ = dir[fe_idx];
+ ////Create gain property for mykonos
+ //auto myk_set_gain_func = [this, chan, dir_](const double gain)
+ //{
+ //return this->_myk_set_gain(gain, chan, dir_);
+ //};
+ //auto myk_get_gain_func = [this, chan, dir_]()
+ //{
+ //return this->_myk_get_gain(chan, dir_);
+ //};
+
+ //_tree->create<double>(fe_path / "gains" / "ad9371" / "value")
+ //.set(0)
+ //.set_coercer(myk_set_gain_func)
+ //.set_publisher(myk_get_gain_func);
+ //_tree->create<meta_range_t>(fe_path / "gains" / "ad9371" / "range")
+ //.set(meta_range_t(ad9371_min_gain, ad9371_max_gain, ad9371_gain_step));
+ //// Create gain property for DSA
+ //auto dsa_set_gain_func = [this, chan, dir_](const double gain)
+ //{
+ //return this->_dsa_set_gain(gain, chan, dir_);
+ //};
+ //auto dsa_get_gain_func = [this, chan, dir_]()
+ //{
+ //return this->_dsa_get_gain(chan, dir_);
+ //};
+ //_tree->create<double>(fe_path / "gains" / "dsa" / "value")
+ //.set(0)
+ //.set_coercer(dsa_set_gain_func)
+ //.set_publisher(dsa_get_gain_func);
+ //_tree->create<meta_range_t>(fe_path / "gains" / "dsa" / "range")
+ //.set(meta_range_t(dsa_min_gain, dsa_max_gain, dsa_gain_step));
+
+ //// Create gain property for all gains
+ //auto set_all_gain_func = [this, chan, dir_](const double gain)
+ //{
+ //return this->_set_all_gain(gain, chan, dir_);
+ //};
+ //auto get_all_gain_func = [this, chan, dir_]()
+ //{
+ //return this->_get_all_gain(chan, dir_);
+ //};
+ //_tree->create<double>(fe_path / "gains" / "all" / "value")
+ //.set(0)
+ //.set_coercer(set_all_gain_func)
+ //.set_publisher(get_all_gain_func);
+ //_tree->create<meta_range_t>(fe_path / "gains" / "all" / "range")
+ //.set(meta_range_t(all_min_gain, all_max_gain, all_gain_step));
+
+ //}
+ }
+ }
+
+
+ // TODO this might be wrong
+ if (_master) {
+ this->_init_frontend_subtree(_tree->subtree(fe_base), 0, 0);
+ std::string slave_slot = (_radio_slot == "A") ? "B" : "D";
+ UHD_LOG_TRACE(unique_id(),
+ "Also registering props for slave radio " << slave_slot);
+ this->_init_frontend_subtree(
+ _tree->subtree(fs_path("dboards") / slave_slot), 0, 1);
+ }
+ // TODO: When we go to one radio per dboard, the above if statement goes
+ // away, and instead we have something like this:
+ /*
+ *for (chan_idx = 0; chan_idx < MAGNESIUM_NUM_CHANS; chan_idx++) {
+ * this->_init_frontend_subtree(
+ * _tree->get_subtree(fe_base), chan_idx, 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(MAGNESIUM_TICK_RATE);
+ }
+}
+