aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/include/uhdlib/usrp/dboard/debug_dboard.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/include/uhdlib/usrp/dboard/debug_dboard.hpp')
-rw-r--r--host/lib/include/uhdlib/usrp/dboard/debug_dboard.hpp592
1 files changed, 592 insertions, 0 deletions
diff --git a/host/lib/include/uhdlib/usrp/dboard/debug_dboard.hpp b/host/lib/include/uhdlib/usrp/dboard/debug_dboard.hpp
new file mode 100644
index 000000000..72ac16e28
--- /dev/null
+++ b/host/lib/include/uhdlib/usrp/dboard/debug_dboard.hpp
@@ -0,0 +1,592 @@
+//
+// Copyright 2020 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#pragma once
+
+#include "x400_dboard_iface.hpp"
+#include <uhd/exception.hpp>
+#include <uhd/property_tree.hpp>
+#include <uhd/types/eeprom.hpp>
+#include <uhdlib/rfnoc/rf_control/dboard_iface.hpp>
+#include <string>
+
+#define UHD_LOG_SKIP_CFG() \
+ UHD_LOG_TRACE( \
+ "RFNOC::DEBUG_DB", "Skipping unsupported debug db config for " << __FUNCTION__);
+
+namespace uhd { namespace rfnoc {
+
+const static uint16_t EMPTY_DB_PID = 0x0;
+const static uint16_t DEBUG_DB_PID = 0x4001;
+const static uint16_t IF_TEST_DBOARD_PID = 0x4006;
+
+/*! \brief Implementation of common dboard_iface for IF Test and Debug dboards.
+ */
+class debug_dboard_common_impl : public uhd::usrp::x400::x400_dboard_iface
+{
+public:
+ using sptr = std::shared_ptr<debug_dboard_common_impl>;
+
+ rf_control::gain_profile_iface::sptr get_tx_gain_profile_api() override
+ {
+ return rf_control::gain_profile_iface::sptr();
+ }
+
+ rf_control::gain_profile_iface::sptr get_rx_gain_profile_api() override
+ {
+ return rf_control::gain_profile_iface::sptr();
+ }
+
+ bool is_adc_self_cal_supported() override
+ {
+ return false;
+ }
+
+ uhd::usrp::x400::adc_self_cal_params_t get_adc_self_cal_params(double) override
+ {
+ return {
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ };
+ }
+
+ size_t get_chan_from_dboard_fe(const std::string& fe, direction_t) const override
+ {
+ if (fe == "0") {
+ return 0;
+ }
+ if (fe == "1") {
+ return 1;
+ }
+ throw uhd::key_error(std::string("[X400] Invalid frontend: ") + fe);
+ }
+
+ std::string get_dboard_fe_from_chan(size_t chan, direction_t) const override
+ {
+ if (chan == 0) {
+ return "0";
+ }
+ if (chan == 1) {
+ return "1";
+ }
+ throw uhd::lookup_error(
+ std::string("[X400] Invalid channel: ") + std::to_string(chan));
+ }
+
+ std::vector<usrp::pwr_cal_mgr::sptr>& get_pwr_mgr(direction_t) override
+ {
+ static std::vector<usrp::pwr_cal_mgr::sptr> empty_vtr;
+ return empty_vtr;
+ }
+
+ eeprom_map_t get_db_eeprom() override
+ {
+ return {};
+ }
+
+ std::string get_tx_antenna(const size_t) const override
+ {
+ return "";
+ }
+
+ std::vector<std::string> get_tx_antennas(const size_t) const override
+ {
+ return {};
+ }
+
+ void set_tx_antenna(const std::string&, const size_t) override{UHD_LOG_SKIP_CFG()}
+
+ std::string get_rx_antenna(const size_t) const override
+ {
+ return "";
+ }
+
+ std::vector<std::string> get_rx_antennas(const size_t) const override
+ {
+ return {};
+ }
+
+ void set_rx_antenna(const std::string&, const size_t) override
+ {
+ UHD_LOG_SKIP_CFG()
+ }
+
+ double get_tx_frequency(const size_t) override
+ {
+ return 0;
+ }
+
+ double set_tx_frequency(const double, size_t) override
+ {
+ UHD_LOG_SKIP_CFG()
+ return 0;
+ }
+
+ void set_tx_tune_args(const device_addr_t&, const size_t) override{UHD_LOG_SKIP_CFG()}
+
+ freq_range_t get_tx_frequency_range(const size_t) const override
+ {
+ return meta_range_t(0.0, 0.0);
+ }
+
+ double get_rx_frequency(const size_t) override
+ {
+ return 0;
+ }
+
+ double set_rx_frequency(const double, const size_t) override
+ {
+ UHD_LOG_SKIP_CFG()
+ return 0;
+ }
+
+ void set_rx_tune_args(const device_addr_t&, const size_t) override{UHD_LOG_SKIP_CFG()}
+
+ freq_range_t get_rx_frequency_range(const size_t) const override
+ {
+ return meta_range_t(0.0, 0.0);
+ }
+
+ std::vector<std::string> get_tx_gain_names(const size_t) const override
+ {
+ return {};
+ }
+
+ gain_range_t get_tx_gain_range(const size_t) const override
+ {
+ return meta_range_t(0.0, 0.0);
+ }
+
+ gain_range_t get_tx_gain_range(const std::string&, const size_t) const override
+ {
+ return meta_range_t(0.0, 0.0);
+ }
+
+ double get_tx_gain(const size_t) override
+ {
+ return 0;
+ }
+
+ double get_tx_gain(const std::string&, const size_t) override
+ {
+ UHD_LOG_SKIP_CFG()
+ return 0;
+ }
+
+ double set_tx_gain(const double, const size_t) override
+ {
+ UHD_LOG_SKIP_CFG()
+ return 0;
+ }
+
+ double set_tx_gain(const double, const std::string&, const size_t) override
+ {
+ UHD_LOG_SKIP_CFG()
+ return 0;
+ }
+
+ std::vector<std::string> get_rx_gain_names(const size_t) const override
+ {
+ return {};
+ }
+
+ gain_range_t get_rx_gain_range(const size_t) const override
+ {
+ UHD_LOG_SKIP_CFG()
+ return meta_range_t(0.0, 0.0);
+ }
+
+ gain_range_t get_rx_gain_range(const std::string&, const size_t) const override
+ {
+ UHD_LOG_SKIP_CFG()
+ return meta_range_t(0.0, 0.0);
+ }
+
+ double get_rx_gain(const size_t) override
+ {
+ return 0;
+ }
+
+ double get_rx_gain(const std::string&, const size_t) override
+ {
+ return 0;
+ }
+
+ double set_rx_gain(const double, const size_t) override
+ {
+ UHD_LOG_SKIP_CFG()
+ return 0;
+ }
+
+ double set_rx_gain(const double, const std::string&, const size_t) override
+ {
+ UHD_LOG_SKIP_CFG()
+ return 0;
+ }
+
+ void set_rx_agc(const bool, const size_t) override{UHD_LOG_SKIP_CFG()}
+
+ meta_range_t get_tx_bandwidth_range(size_t) const override
+ {
+ return meta_range_t(0.0, 0.0);
+ }
+
+ double get_tx_bandwidth(const size_t) override
+ {
+ return 0;
+ }
+
+ double set_tx_bandwidth(const double, const size_t) override
+ {
+ UHD_LOG_SKIP_CFG()
+ return 0;
+ }
+
+ meta_range_t get_rx_bandwidth_range(size_t) const override
+ {
+ return meta_range_t(0.0, 0.0);
+ }
+
+ double get_rx_bandwidth(const size_t) override
+ {
+ return 0;
+ }
+
+ double set_rx_bandwidth(const double, const size_t) override
+ {
+ UHD_LOG_SKIP_CFG()
+ return 0;
+ }
+
+ std::vector<std::string> get_rx_lo_names(const size_t) const override
+ {
+ return {};
+ }
+
+ std::vector<std::string> get_rx_lo_sources(
+ const std::string&, const size_t) const override
+ {
+ UHD_LOG_SKIP_CFG()
+ return {};
+ }
+
+ freq_range_t get_rx_lo_freq_range(const std::string&, const size_t) const override
+ {
+ return meta_range_t(0.0, 0.0);
+ }
+
+ void set_rx_lo_source(const std::string&, const std::string&, const size_t) override
+ {
+ UHD_LOG_SKIP_CFG()
+ }
+
+ const std::string get_rx_lo_source(const std::string&, const size_t) override
+ {
+ return "";
+ }
+
+ void set_rx_lo_export_enabled(bool, const std::string&, const size_t) override
+ {
+ UHD_LOG_SKIP_CFG()
+ }
+
+ bool get_rx_lo_export_enabled(const std::string&, const size_t) override
+ {
+ return false;
+ }
+
+ double set_rx_lo_freq(double, const std::string&, const size_t) override
+ {
+ UHD_LOG_SKIP_CFG()
+ return 0;
+ }
+
+ double get_rx_lo_freq(const std::string&, const size_t) override
+ {
+ return 0;
+ }
+
+ std::vector<std::string> get_tx_lo_names(const size_t) const override
+ {
+ return {};
+ }
+
+ std::vector<std::string> get_tx_lo_sources(const std::string&, const size_t) const override
+ {
+ return {};
+ }
+
+ freq_range_t get_tx_lo_freq_range(const std::string&, const size_t) override
+ {
+ return meta_range_t(0.0, 0.0);
+ }
+
+ void set_tx_lo_source(const std::string&, const std::string&, const size_t) override
+ {
+ UHD_LOG_SKIP_CFG()
+ }
+
+ const std::string get_tx_lo_source(const std::string&, const size_t) override
+ {
+ return "";
+ }
+
+ void set_tx_lo_export_enabled(const bool, const std::string&, const size_t) override
+ {
+ UHD_LOG_SKIP_CFG()
+ }
+
+ bool get_tx_lo_export_enabled(const std::string&, const size_t) override
+ {
+ return false;
+ }
+
+ double set_tx_lo_freq(const double, const std::string&, const size_t) override
+ {
+ UHD_LOG_SKIP_CFG()
+ return 0;
+ }
+
+ double get_tx_lo_freq(const std::string&, const size_t) override
+ {
+ return 0;
+ }
+
+ void set_command_time(uhd::time_spec_t, const size_t) override
+ {
+ // nop
+ }
+};
+
+/*! \brief Implementation of dboard_iface for debug_db.
+ */
+class debug_dboard_impl : public debug_dboard_common_impl
+{
+ // Just an empty class for conveniently organizing class hierarchy.
+};
+
+/*! \brief Fake dboard implementation for an empty slot
+ */
+class empty_slot_dboard_impl : public debug_dboard_common_impl
+{
+ // Just an empty class for conveniently organizing class hierarchy.
+};
+
+/*! \brief Implementation of dboard_iface for IF Test dboard.
+ */
+class if_test_dboard_impl : public debug_dboard_common_impl
+{
+public:
+ /******************************************************************************
+ * Structors
+ *****************************************************************************/
+ if_test_dboard_impl(const size_t db_idx,
+ const std::string& rpc_prefix,
+ const std::string& unique_id,
+ std::shared_ptr<mpmd_mb_controller> mb_controller,
+ uhd::property_tree::sptr tree)
+ : _unique_id(unique_id)
+ , _db_idx(db_idx)
+ , _rpc_prefix(rpc_prefix)
+ , _mb_control(mb_controller)
+ , _tree(tree)
+ {
+ RFNOC_LOG_TRACE("Entering " << __FUNCTION__);
+ RFNOC_LOG_TRACE("DB ID: " << _db_idx);
+ UHD_ASSERT_THROW(_mb_control);
+ _rpcc = _mb_control->get_rpc_client();
+ UHD_ASSERT_THROW(_rpcc);
+ _init_frontend_subtree();
+ }
+
+ ~if_test_dboard_impl()
+ {
+ RFNOC_LOG_TRACE(__FUNCTION__);
+ }
+
+ // The IF Test dboard muxes a single SMA port (for each of RX and TX) like so:
+ // /---> dac0
+ // /----> dac1
+ // TX SMA port -- [mux] -----> dac2
+ // \----> dac3
+ //
+ // (and similarly with the RX SMA port and the adcs)
+
+ std::vector<std::string> get_tx_muxes(void)
+ {
+ return {"DAC0", "DAC1", "DAC2", "DAC3"};
+ }
+
+ void set_tx_mux(const std::string& mux)
+ {
+ RFNOC_LOG_TRACE("Setting TX mux to " << mux);
+ _rpcc->notify_with_token(
+ _rpc_prefix + "config_tx_path", _get_tx_path_from_mux(mux));
+ }
+
+ std::string get_tx_mux(void)
+ {
+ return _rpcc->request_with_token<std::string>(_rpc_prefix + "get_tx_path");
+ }
+
+ std::vector<std::string> get_rx_muxes(void)
+ {
+ return {"ADC0", "ADC1", "ADC2", "ADC3"};
+ }
+
+ void set_rx_mux(const std::string& mux)
+ {
+ RFNOC_LOG_TRACE("Setting RX mux to " << mux);
+ _rpcc->notify_with_token(
+ _rpc_prefix + "config_rx_path", _get_rx_path_from_mux(mux));
+ }
+
+ std::string get_rx_mux(void)
+ {
+ return _rpcc->request_with_token<std::string>(_rpc_prefix + "get_rx_path");
+ }
+
+ eeprom_map_t get_db_eeprom() override
+ {
+ return _rpcc->request_with_token<eeprom_map_t>("get_db_eeprom", _db_idx);
+ }
+
+
+private:
+ //! Used by the RFNOC_LOG_* macros.
+ const std::string _unique_id;
+ std::string get_unique_id() const
+ {
+ return _unique_id;
+ }
+
+ //! Index of this daughterboard
+ const size_t _db_idx;
+
+ //! Prepended for all dboard RPC calls
+ const std::string _rpc_prefix;
+
+ //! Reference to the MB controller
+ uhd::rfnoc::mpmd_mb_controller::sptr _mb_control;
+
+ //! Reference to the RPC client
+ uhd::rpc_client::sptr _rpcc;
+
+ //! Reference to this block's subtree
+ //
+ // It is mutable because _tree->access<>(..).get() is not const, but we
+ // need to do just that in some const contexts
+ mutable uhd::property_tree::sptr _tree;
+
+ std::string _get_tx_path_from_mux(const std::string mux)
+ {
+ if (mux == "DAC0") {
+ return "dac0";
+ } else if (mux == "DAC1") {
+ return "dac1";
+ } else if (mux == "DAC2") {
+ return "dac2";
+ } else if (mux == "DAC3") {
+ return "dac3";
+ } else {
+ throw uhd::value_error(
+ std::string("[RFNOC::IF_TEST_DBOARD] Invalid TX Mux Name: ") + mux);
+ }
+ }
+
+ std::string _get_rx_path_from_mux(const std::string mux)
+ {
+ if (mux == "ADC0") {
+ return "adc0";
+ } else if (mux == "ADC1") {
+ return "adc1";
+ } else if (mux == "ADC2") {
+ return "adc2";
+ } else if (mux == "ADC3") {
+ return "adc3";
+ } else {
+ throw uhd::value_error(
+ std::string("[RFNOC::IF_TEST_DBOARD] Invalid RX Mux Name: ") + mux);
+ }
+ }
+
+ void _init_frontend_subtree()
+ {
+ auto subtree = _tree->subtree(fs_path("dboard"));
+
+ // DB EEPROM
+ subtree->create<eeprom_map_t>("eeprom")
+ .add_coerced_subscriber([this](const eeprom_map_t&) {
+ throw uhd::runtime_error("Attempting to update daughterboard eeprom!");
+ })
+ .set_publisher([this]() { return get_db_eeprom(); });
+
+ static const char IF_TEST_FE_NAME[] = "IF_TEST";
+
+ const fs_path tx_fe_path = fs_path("tx_frontends/0");
+ const fs_path rx_fe_path = fs_path("rx_frontends/0");
+ RFNOC_LOG_TRACE("Adding non-RFNoC block properties"
+ << " to prop tree path " << tx_fe_path << " and " << rx_fe_path);
+
+ subtree->create<std::string>(tx_fe_path / "name").set(IF_TEST_FE_NAME);
+ subtree->create<std::string>(rx_fe_path / "name").set(IF_TEST_FE_NAME);
+
+ // TX Mux
+ subtree->create<std::string>(tx_fe_path / "mux" / "value")
+ .add_coerced_subscriber(
+ [this](const std::string& mux) { this->set_tx_mux(mux); })
+ .set_publisher([this]() { return this->get_tx_mux(); });
+ subtree->create<std::vector<std::string>>(tx_fe_path / "mux" / "options")
+ .set(get_tx_muxes())
+ .add_coerced_subscriber([](const std::vector<std::string>&) {
+ throw uhd::runtime_error("Attempting to update mux options!");
+ });
+
+ // RX Mux
+ subtree->create<std::string>(rx_fe_path / "mux" / "value")
+ .add_coerced_subscriber(
+ [this](const std::string& mux) { this->set_rx_mux(mux); })
+ .set_publisher([this]() { return this->get_rx_mux(); });
+ subtree->create<std::vector<std::string>>(rx_fe_path / "mux" / "options")
+ .set(get_rx_muxes())
+ .add_coerced_subscriber([](const std::vector<std::string>&) {
+ throw uhd::runtime_error("Attempting to update mux options!");
+ });
+
+ for (auto fe_path : {tx_fe_path, rx_fe_path}) {
+ // Antennas
+ const std::vector<std::string> antenna_options = {"SMA"};
+ subtree->create<std::vector<std::string>>(fe_path / "antenna" / "options")
+ .set(antenna_options)
+ .add_coerced_subscriber([](const std::vector<std::string>&) {
+ throw uhd::runtime_error("Attempting to update antenna options!");
+ });
+
+ // Frequency range
+ const uhd::freq_range_t freq_range(0.0, 0.0);
+ subtree->create<meta_range_t>(fe_path / "freq" / "range")
+ .set(freq_range)
+ .add_coerced_subscriber([](const meta_range_t&) {
+ throw uhd::runtime_error("Attempting to update freq range!");
+ });
+
+ // Gains
+ const uhd::gain_range_t gain_range(0.0, 0.0, 1.0);
+ subtree->create<meta_range_t>(fe_path / "gains" / "all" / "range")
+ .set(gain_range)
+ .add_coerced_subscriber([](const meta_range_t&) {
+ throw uhd::runtime_error("Attempting to update gain range!");
+ });
+
+ // Connection
+ subtree->create<std::string>(fe_path / "connection").set("IQ");
+ }
+ }
+};
+
+}} // namespace uhd::rfnoc