diff options
Diffstat (limited to 'host/lib/usrp')
| -rw-r--r-- | host/lib/usrp/cores/rx_frontend_core_3000.cpp | 1 | ||||
| -rw-r--r-- | host/lib/usrp/dboard/db_basic_and_lf.cpp | 189 | ||||
| -rw-r--r-- | host/lib/usrp/dboard/db_basic_and_lf.hpp | 35 | ||||
| -rw-r--r-- | host/lib/usrp/x300/x300_radio_control.cpp | 119 | 
4 files changed, 234 insertions, 110 deletions
| diff --git a/host/lib/usrp/cores/rx_frontend_core_3000.cpp b/host/lib/usrp/cores/rx_frontend_core_3000.cpp index 788e222ed..1dc8be745 100644 --- a/host/lib/usrp/cores/rx_frontend_core_3000.cpp +++ b/host/lib/usrp/cores/rx_frontend_core_3000.cpp @@ -193,6 +193,7 @@ public:      {          switch (_fe_conn.get_sampling_mode()) {              case fe_connection_t::REAL: +                return _adc_rate;              case fe_connection_t::HETERODYNE:                  return _adc_rate / 2;              default: diff --git a/host/lib/usrp/dboard/db_basic_and_lf.cpp b/host/lib/usrp/dboard/db_basic_and_lf.cpp index 5e8ac310e..aaeaff2a6 100644 --- a/host/lib/usrp/dboard/db_basic_and_lf.cpp +++ b/host/lib/usrp/dboard/db_basic_and_lf.cpp @@ -5,6 +5,7 @@  // SPDX-License-Identifier: GPL-3.0-or-later  // +#include "db_basic_and_lf.hpp"  #include <uhd/types/dict.hpp>  #include <uhd/types/ranges.hpp>  #include <uhd/usrp/dboard_base.hpp> @@ -17,27 +18,7 @@  using namespace uhd;  using namespace uhd::usrp; - -/*********************************************************************** - * Constants - **********************************************************************/ -namespace { -constexpr uint32_t BASIC_TX_PID = 0x0000; -constexpr uint32_t BASIC_RX_PID = 0x0001; -constexpr uint32_t LF_TX_PID    = 0x000E; -constexpr uint32_t LF_RX_PID    = 0x000F; - -constexpr double BASIC_MAX_BANDWIDTH = 250e6; // Hz -constexpr double LF_MAX_BANDWIDTH    = 32e6; // Hz - - -const std::map<std::string, double> subdev_bandwidth_scalar{ -    {"A", 1.0}, {"B", 1.0}, {"AB", 2.0}, {"BA", 2.0}}; - -const uhd::dict<std::string, std::string> sd_name_to_conn = -    boost::assign::map_list_of("AB", "IQ")("BA", "QI")("A", "I")("B", "Q"); -} // namespace - +using namespace uhd::usrp::dboard::basic_and_lf;  /***********************************************************************   * The basic and lf boards: @@ -50,8 +31,6 @@ public:      virtual ~basic_rx(void);  private: -    void set_rx_ant(const std::string& ant); -      double _max_freq;  }; @@ -91,13 +70,21 @@ static dboard_base::sptr make_lf_tx(dboard_base::ctor_args_t args)  UHD_STATIC_BLOCK(reg_basic_and_lf_dboards)  {      dboard_manager::register_dboard( -        BASIC_TX_PID, &make_basic_tx, "Basic TX", sd_name_to_conn.keys()); +        BASIC_TX_PID, &make_basic_tx, "Basic TX", antenna_mode_to_conn.keys());      dboard_manager::register_dboard( -        BASIC_RX_PID, &make_basic_rx, "Basic RX", sd_name_to_conn.keys()); +        BASIC_RX_PID, &make_basic_rx, "Basic RX", antenna_mode_to_conn.keys());      dboard_manager::register_dboard( -        LF_TX_PID, &make_lf_tx, "LF TX", sd_name_to_conn.keys()); +        LF_TX_PID, &make_lf_tx, "LF TX", antenna_mode_to_conn.keys());      dboard_manager::register_dboard( -        LF_RX_PID, &make_lf_rx, "LF RX", sd_name_to_conn.keys()); +        LF_RX_PID, &make_lf_rx, "LF RX", antenna_mode_to_conn.keys()); +    dboard_manager::register_dboard( +        BASIC_TX_RFNOC_PID, &make_basic_tx, "Basic TX", tx_frontends); +    dboard_manager::register_dboard( +        BASIC_RX_RFNOC_PID, &make_basic_rx, "Basic RX", rx_frontends); +    dboard_manager::register_dboard( +        LF_TX_RFNOC_PID, &make_lf_tx, "LF TX", tx_frontends); +    dboard_manager::register_dboard( +        LF_RX_RFNOC_PID, &make_lf_rx, "LF RX", rx_frontends);  }  /*********************************************************************** @@ -106,20 +93,30 @@ UHD_STATIC_BLOCK(reg_basic_and_lf_dboards)  basic_rx::basic_rx(ctor_args_t args, double max_freq)      : rx_dboard_base(args), _max_freq(max_freq)  { +    // Examine the frontend to use the RFNoC or the N210 implementation +    // (preserves legacy behavior)      const std::string fe_name(get_subdev_name()); -    const std::string fe_conn(sd_name_to_conn[fe_name]); -    const std::string db_name( -        str(boost::format("%s (%s)") -            % ((get_rx_id() == BASIC_RX_PID) ? "BasicRX" : "LFRX") % fe_name)); +    const bool is_rfnoc_dev = std::find(rx_frontends.begin(), rx_frontends.end(), fe_name) +                              != rx_frontends.end(); +    const std::string ant_mode(is_rfnoc_dev ? "AB" : fe_name); +    const std::string fe_conn(antenna_mode_to_conn[ant_mode]); +    const std::string db_name([this]() { +        switch (get_rx_id().to_uint16()) { +            case BASIC_RX_PID: +            case BASIC_RX_RFNOC_PID: +                return str(boost::format("%s (%s)") % "BasicRX" % get_subdev_name()); +            case LF_RX_PID: +            case LF_RX_RFNOC_PID: +                return str(boost::format("%s (%s)") % "LFRX" % get_subdev_name()); +            default: +                UHD_THROW_INVALID_CODE_PATH(); +        } +    }());      UHD_LOG_TRACE("BASICRX", -        "Initializing driver for: " << db_name << " IQ connection type: " << fe_conn); -    const bool has_fe_conn_settings = -        get_iface()->has_set_fe_connection(dboard_iface::UNIT_RX); -    UHD_LOG_TRACE("BASICRX", -        "Access to FE connection settings: " << (has_fe_conn_settings ? "Yes" : "No")); +        "Initializing driver for: " << db_name << " IQ connection type: " << ant_mode); +    UHD_LOG_TRACE("BASICRX", "Is RFNoC Device: " << (is_rfnoc_dev ? "Yes" : "No")); -    std::vector<std::string> antenna_options = -        has_fe_conn_settings ? sd_name_to_conn.keys() : std::vector<std::string>(1, ""); +    std::vector<std::string> antenna_options = antenna_mode_to_conn.keys();      ////////////////////////////////////////////////////////////////////      // Register properties @@ -134,29 +131,43 @@ basic_rx::basic_rx(ctor_args_t args, double max_freq)          .set(freq_range_t(-_max_freq, +_max_freq));      this->get_rx_subtree()          ->create<std::string>("antenna/value") -        .set(has_fe_conn_settings ? fe_name : ""); -    if (has_fe_conn_settings) { -        this->get_rx_subtree() -            ->access<std::string>("antenna/value") -            .add_coerced_subscriber( -                [this](const std::string& ant) { this->set_rx_ant(ant); }); -    } +        .set(is_rfnoc_dev ? ant_mode : "");      this->get_rx_subtree()          ->create<std::vector<std::string>>("antenna/options") -        .set(antenna_options); +        .set(is_rfnoc_dev ? antenna_options : std::vector<std::string>(1, ""));      this->get_rx_subtree()->create<int>("sensors"); // phony property so this dir exists      this->get_rx_subtree()          ->create<std::string>("connection") -        .set(sd_name_to_conn[get_subdev_name()]); +        .set(antenna_mode_to_conn[ant_mode]);      this->get_rx_subtree()->create<bool>("enabled").set(true); // always enabled      this->get_rx_subtree()->create<bool>("use_lo_offset").set(false);      this->get_rx_subtree()          ->create<double>("bandwidth/value") -        .set(subdev_bandwidth_scalar.at(get_subdev_name()) * _max_freq); +        .set(antenna_mode_bandwidth_scalar.at(ant_mode) * _max_freq);      this->get_rx_subtree()          ->create<meta_range_t>("bandwidth/range") -        .set(freq_range_t(subdev_bandwidth_scalar.at(get_subdev_name()) * _max_freq, -            subdev_bandwidth_scalar.at(get_subdev_name()) * _max_freq)); +        .set(freq_range_t(antenna_mode_bandwidth_scalar.at(ant_mode) * _max_freq, +            antenna_mode_bandwidth_scalar.at(ant_mode) * _max_freq)); +    if (is_rfnoc_dev) { +        this->get_rx_subtree() +            ->access<std::string>("antenna/value") +            .add_coerced_subscriber([this](const std::string& ant) { +                this->get_rx_subtree() +                    ->access<std::string>("connection") +                    .set(antenna_mode_to_conn[ant]); +                this->get_rx_subtree() +                    ->access<double>("bandwidth/value") +                    .set(antenna_mode_bandwidth_scalar.at(ant) * _max_freq); +                this->get_rx_subtree() +                    ->access<meta_range_t>("bandwidth/range") +                    .set(freq_range_t(antenna_mode_bandwidth_scalar.at(ant) * _max_freq, +                        antenna_mode_bandwidth_scalar.at(ant) * _max_freq)); +                UHD_LOG_TRACE("BASICRX", +                    "Changing antenna mode on channel: " << get_subdev_name() +                                                         << " IQ connection type: " +                                                         << antenna_mode_to_conn[ant]); +            }); +    }      // disable RX dboard clock by default      this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, false); @@ -172,34 +183,40 @@ basic_rx::~basic_rx(void)      /* NOP */  } -void basic_rx::set_rx_ant(const std::string& ant) -{ -    UHD_ASSERT_THROW(get_iface()->has_set_fe_connection(dboard_iface::UNIT_RX)); -    UHD_LOG_TRACE("BASICRX", "Setting antenna value to: " << ant); -    get_iface()->set_fe_connection(dboard_iface::UNIT_RX, -        get_subdev_name(), -        usrp::fe_connection_t(sd_name_to_conn[ant], 0.0 /* IF */)); -} -  /***********************************************************************   * Basic and LF TX dboard   **********************************************************************/  basic_tx::basic_tx(ctor_args_t args, double max_freq) : tx_dboard_base(args)  { +    // Examine the frontend to use the RFNoC or the N210 implementation +    // (preserves legacy behavior) +    const std::string fe_name(get_subdev_name()); +    const bool is_rfnoc_dev = std::find(tx_frontends.begin(), tx_frontends.end(), fe_name) +                              != tx_frontends.end(); +    const std::string ant_mode(is_rfnoc_dev ? "AB" : fe_name);      _max_freq = max_freq; -    // this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, true); +    const std::string db_name([this]() { +        switch (get_tx_id().to_uint16()) { +            case BASIC_TX_PID: +            case BASIC_TX_RFNOC_PID: +                return str(boost::format("%s (%s)") % "BasicTX" % get_subdev_name()); +            case LF_TX_PID: +            case LF_TX_RFNOC_PID: +                return str(boost::format("%s (%s)") % "LFTX" % get_subdev_name()); +            default: +                UHD_THROW_INVALID_CODE_PATH(); +        } +    }()); +    UHD_LOG_TRACE("BASICTX", +        "Initializing driver for: " << db_name << " IQ connection type: " << ant_mode); +    UHD_LOG_TRACE("BASICTX", "Is RFNoC Device: " << (is_rfnoc_dev ? "Yes" : "No")); + +    std::vector<std::string> antenna_options = antenna_mode_to_conn.keys();      ////////////////////////////////////////////////////////////////////      // Register properties      //////////////////////////////////////////////////////////////////// -    if (get_tx_id() == BASIC_TX_PID) { -        this->get_tx_subtree()->create<std::string>("name").set( -            std::string(str(boost::format("BasicTX (%s)") % get_subdev_name()))); -    } else { -        this->get_tx_subtree()->create<std::string>("name").set( -            std::string(str(boost::format("LFTX (%s)") % get_subdev_name()))); -    } - +    this->get_tx_subtree()->create<std::string>("name").set(db_name);      this->get_tx_subtree()->create<int>("gains"); // phony property so this dir exists      this->get_tx_subtree()->create<double>("freq/value").set_publisher([]() {          return 0.0; @@ -207,21 +224,45 @@ basic_tx::basic_tx(ctor_args_t args, double max_freq) : tx_dboard_base(args)      this->get_tx_subtree()          ->create<meta_range_t>("freq/range")          .set(freq_range_t(-_max_freq, +_max_freq)); -    this->get_tx_subtree()->create<std::string>("antenna/value").set(""); -    this->get_tx_subtree()->create<std::vector<std::string>>("antenna/options").set({""}); +    this->get_tx_subtree() +        ->create<std::string>("antenna/value") +        .set(is_rfnoc_dev ? ant_mode : ""); +    this->get_tx_subtree() +        ->create<std::vector<std::string>>("antenna/options") +        .set(is_rfnoc_dev ? antenna_options : std::vector<std::string>(1, ""));      this->get_tx_subtree()->create<int>("sensors"); // phony property so this dir exists      this->get_tx_subtree()          ->create<std::string>("connection") -        .set(sd_name_to_conn[get_subdev_name()]); +        .set(antenna_mode_to_conn[ant_mode]);      this->get_tx_subtree()->create<bool>("enabled").set(true); // always enabled      this->get_tx_subtree()->create<bool>("use_lo_offset").set(false);      this->get_tx_subtree()          ->create<double>("bandwidth/value") -        .set(subdev_bandwidth_scalar.at(get_subdev_name()) * _max_freq); +        .set(antenna_mode_bandwidth_scalar.at(ant_mode) * _max_freq);      this->get_tx_subtree()          ->create<meta_range_t>("bandwidth/range") -        .set(freq_range_t(subdev_bandwidth_scalar.at(get_subdev_name()) * _max_freq, -            subdev_bandwidth_scalar.at(get_subdev_name()) * _max_freq)); +        .set(freq_range_t(antenna_mode_bandwidth_scalar.at(ant_mode) * _max_freq, +            antenna_mode_bandwidth_scalar.at(ant_mode) * _max_freq)); +    if (is_rfnoc_dev) { +        this->get_tx_subtree() +            ->access<std::string>("antenna/value") +            .add_coerced_subscriber([this](const std::string& ant) { +                this->get_tx_subtree() +                    ->access<std::string>("connection") +                    .set(antenna_mode_to_conn[ant]); +                this->get_tx_subtree() +                    ->access<double>("bandwidth/value") +                    .set(antenna_mode_bandwidth_scalar.at(ant) * _max_freq); +                this->get_tx_subtree() +                    ->access<meta_range_t>("bandwidth/range") +                    .set(freq_range_t(antenna_mode_bandwidth_scalar.at(ant) * _max_freq, +                        antenna_mode_bandwidth_scalar.at(ant) * _max_freq)); +                UHD_LOG_TRACE("BASICTX", +                    "Changing antenna mode for channel: " << get_subdev_name() +                                                          << " IQ connection type: " +                                                          << antenna_mode_to_conn[ant]); +            }); +    }      // disable TX dboard clock by default      this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, false); diff --git a/host/lib/usrp/dboard/db_basic_and_lf.hpp b/host/lib/usrp/dboard/db_basic_and_lf.hpp new file mode 100644 index 000000000..c306926eb --- /dev/null +++ b/host/lib/usrp/dboard/db_basic_and_lf.hpp @@ -0,0 +1,35 @@ +// +// Copyright 2020 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#include <uhd/types/dict.hpp> +#include <boost/assign/list_of.hpp> + +namespace uhd { namespace usrp { namespace dboard { namespace basic_and_lf { +constexpr uint32_t BASIC_TX_PID = 0x0000; +constexpr uint32_t BASIC_RX_PID = 0x0001; +constexpr uint32_t LF_TX_PID    = 0x000E; +constexpr uint32_t LF_RX_PID    = 0x000F; +// The PIDs of these dboards are duplicated to support a new operating mode +// on RFNoC devices, while maintaining legacy for the USRP2 +constexpr uint32_t RFNOC_PID_FLAG     = 0x6300; +constexpr uint32_t BASIC_TX_RFNOC_PID = BASIC_TX_PID | RFNOC_PID_FLAG; // 0x6300 +constexpr uint32_t BASIC_RX_RFNOC_PID = BASIC_RX_PID | RFNOC_PID_FLAG; // 0x6301 +constexpr uint32_t LF_TX_RFNOC_PID    = LF_TX_PID | RFNOC_PID_FLAG; // 0x630E +constexpr uint32_t LF_RX_RFNOC_PID    = LF_RX_PID | RFNOC_PID_FLAG; // 0x630F + +constexpr double BASIC_MAX_BANDWIDTH = 250e6; // Hz +constexpr double LF_MAX_BANDWIDTH    = 32e6; // Hz + + +static const std::vector<std::string> rx_frontends{"0", "1"}; +static const std::vector<std::string> tx_frontends{"0"}; + +static const std::map<std::string, double> antenna_mode_bandwidth_scalar{ +    {"A", 1.0}, {"B", 1.0}, {"AB", 2.0}, {"BA", 2.0}}; + +static const uhd::dict<std::string, std::string> antenna_mode_to_conn = +    boost::assign::map_list_of("AB", "IQ")("BA", "QI")("A", "I")("B", "Q"); +}}}}; // namespace uhd::usrp::dboard::basic_and_lf diff --git a/host/lib/usrp/x300/x300_radio_control.cpp b/host/lib/usrp/x300/x300_radio_control.cpp index 1bd88164a..02a46f0e0 100644 --- a/host/lib/usrp/x300/x300_radio_control.cpp +++ b/host/lib/usrp/x300/x300_radio_control.cpp @@ -4,6 +4,7 @@  // SPDX-License-Identifier: GPL-3.0-or-later  // +#include "../dboard/db_basic_and_lf.hpp"  #include "x300_adc_ctrl.hpp"  #include "x300_dac_ctrl.hpp"  #include "x300_dboard_iface.hpp" @@ -208,10 +209,12 @@ public:          // Properties          for (auto& samp_rate_prop : _samp_rate_in) { -            samp_rate_prop.set(get_rate()); +            set_property( +                samp_rate_prop.get_id(), get_rate(), samp_rate_prop.get_src_info());          }          for (auto& samp_rate_prop : _samp_rate_out) { -            samp_rate_prop.set(get_rate()); +            set_property( +                samp_rate_prop.get_id(), get_rate(), samp_rate_prop.get_src_info());          }      } /* ctor */ @@ -237,6 +240,16 @@ public:      void set_tx_antenna(const std::string& ant, const size_t chan)      { +        // Antenna changes may result in a change of streaming mode for LF/Basic dboards +        if (_basic_lf_tx) { +            if (not uhd::usrp::dboard::basic_and_lf::antenna_mode_to_conn.has_key(ant)) { +                throw uhd::lookup_error( +                    str(boost::format("Invalid antenna mode: %s") % ant)); +            } +            const std::string connection = +                uhd::usrp::dboard::basic_and_lf::antenna_mode_to_conn[ant]; +            _tx_fe_map[chan].core->set_mux(connection); +        }          get_tree()              ->access<std::string>(get_db_path("tx", chan) / "antenna" / "value")              .set(ant); @@ -259,6 +272,18 @@ public:      void set_rx_antenna(const std::string& ant, const size_t chan)      { +        // Antenna changes may result in a change of streaming mode for LF/Basic dboards +        if (_basic_lf_rx) { +            if (not uhd::usrp::dboard::basic_and_lf::antenna_mode_to_conn.has_key(ant)) { +                throw uhd::lookup_error( +                    str(boost::format("Invalid antenna mode: %s") % ant)); +            } +            const std::string connection = +                uhd::usrp::dboard::basic_and_lf::antenna_mode_to_conn[ant]; +            const double if_freq = 0.0; +            _rx_fe_map[chan].core->set_fe_connection( +                usrp::fe_connection_t(connection, if_freq)); +        }          get_tree()              ->access<std::string>(get_db_path("rx", chan) / "antenna" / "value")              .set(ant); @@ -1022,7 +1047,7 @@ public:      }      size_t get_chan_from_dboard_fe( -        const std::string& fe, const direction_t direction) const +        const std::string& fe, const uhd::direction_t direction) const      {          switch (direction) {              case uhd::TX_DIRECTION: @@ -1448,6 +1473,22 @@ private:              const size_t addr = EEPROM_ADDRS[i] + DB_OFFSET;              // Load EEPROM              _db_eeproms[addr].load(*zpu_i2c, BASE_ADDR | addr); +            // Use the RFNoC implementation for Basic/LF dboards +            uint16_t dboard_pid = _db_eeproms[addr].id.to_uint16(); +            switch (dboard_pid) { +                case uhd::usrp::dboard::basic_and_lf::BASIC_RX_PID: +                case uhd::usrp::dboard::basic_and_lf::LF_RX_PID: +                    dboard_pid |= uhd::usrp::dboard::basic_and_lf::RFNOC_PID_FLAG; +                    _db_eeproms[addr].id = dboard_pid; +                    _basic_lf_rx         = true; +                    break; +                case uhd::usrp::dboard::basic_and_lf::BASIC_TX_PID: +                case uhd::usrp::dboard::basic_and_lf::LF_TX_PID: +                    dboard_pid |= uhd::usrp::dboard::basic_and_lf::RFNOC_PID_FLAG; +                    _db_eeproms[addr].id = dboard_pid; +                    _basic_lf_tx         = true; +                    break; +            }              // Add to tree              get_tree()                  ->create<dboard_eeprom_t>(DB_PATH / EEPROM_PATHS[i]) @@ -1489,29 +1530,22 @@ private:          );          RFNOC_LOG_TRACE("DB Manager Initialization complete."); -        // The X3x0 radio block defaults to two ports, but most daughterboards -        // only have one frontend. So we now reduce the number of actual ports -        // based on what is connected. -        // Note: The Basic and LF boards pretend they have four frontends, -        // which a hack from the past. However, they actually only have one -        // frontend, and we select the AB/BA/A/B setting through the antenna. -        // The easiest way to identify those boards is because they're the only -        // ones with four frontends. -        // For all other cases, we reduce the number of frontends to one. +        // The X3x0 radio block defaults to a maximum of two ports, but +        // many daughterboards have fewer possible frontends. So we now +        // reduce the number of actual ports based on what is connected. +        // Note: The Basic and LF boards have two possible frontends on +        // the rx side, and one on the tx side. TwinRX boards have two +        // possible rx frontends, and require up to two ports on the rx side. +        // For all other cases, the number of possible frontends is one for +        // rx and tx.          const size_t num_tx_frontends = _db_manager->get_tx_frontends().size();          const size_t num_rx_frontends = _db_manager->get_rx_frontends().size(); -        if (num_tx_frontends == 4) { -            RFNOC_LOG_TRACE("Found four frontends, inferring BasicTX or LFTX."); -            set_num_input_ports(1); -        } else if (num_tx_frontends == 2 || num_tx_frontends == 1) { +        if (num_tx_frontends == 2 || num_tx_frontends == 1) {              set_num_input_ports(num_tx_frontends);          } else {              throw uhd::runtime_error("Unexpected number of TX frontends!");          } -        if (num_rx_frontends == 4) { -            RFNOC_LOG_TRACE("Found four frontends, inferring BasicRX or LFRX."); -            set_num_output_ports(1); -        } else if (num_rx_frontends == 2 || num_rx_frontends == 1) { +        if (num_rx_frontends == 2 || num_rx_frontends == 1) {              set_num_output_ports(num_rx_frontends);          } else {              throw uhd::runtime_error("Unexpected number of RX frontends!"); @@ -1537,28 +1571,14 @@ private:              if (rx_chan >= get_num_output_ports()) {                  break;              } -            _rx_fe_map[rx_chan].db_fe_name = fe; -            _db_iface->add_rx_fe(fe, _rx_fe_map[rx_chan].core); -            const fs_path fe_path(DB_PATH / "rx_frontends" / fe); -            const std::string conn = -                get_tree()->access<std::string>(fe_path / "connection").get(); -            const double if_freq = -                (get_tree()->exists(fe_path / "if_freq/value")) -                    ? get_tree()->access<double>(fe_path / "if_freq/value").get() -                    : 0.0; -            _rx_fe_map[rx_chan].core->set_fe_connection( -                usrp::fe_connection_t(conn, if_freq)); +            _set_rx_fe(fe, rx_chan);              rx_chan++;          }          for (const std::string& fe : _db_manager->get_tx_frontends()) {              if (tx_chan >= get_num_input_ports()) {                  break;              } -            _tx_fe_map[tx_chan].db_fe_name = fe; -            const fs_path fe_path(DB_PATH / "tx_frontends" / fe); -            const std::string conn = -                get_tree()->access<std::string>(fe_path / "connection").get(); -            _tx_fe_map[tx_chan].core->set_mux(conn); +            _set_tx_fe(fe, tx_chan);              tx_chan++;          }          UHD_ASSERT_THROW(rx_chan or tx_chan); @@ -1689,6 +1709,30 @@ private:          _leds->set_atr_reg(gpio_atr::ATR_REG_FULL_DUPLEX, RX2_RX | TXRX_TX);      } +    void _set_rx_fe(const std::string& fe, const size_t chan) +    { +        _rx_fe_map[chan].db_fe_name = fe; +        _db_iface->add_rx_fe(fe, _rx_fe_map[chan].core); +        const std::string connection = +            get_tree()->access<std::string>(get_db_path("rx", chan) / "connection").get(); +        const double if_freq = +            (get_tree()->exists(get_db_path("rx", chan) / "if_freq" / "value")) +                ? get_tree() +                      ->access<double>(get_db_path("rx", chan) / "if_freq" / "value") +                      .get() +                : 0.0; +        _rx_fe_map[chan].core->set_fe_connection( +            usrp::fe_connection_t(connection, if_freq)); +    } + +    void _set_tx_fe(const std::string& fe, const size_t chan) +    { +        _tx_fe_map[chan].db_fe_name = fe; +        const std::string connection = +            get_tree()->access<std::string>(get_db_path("tx", chan) / "connection").get(); +        _tx_fe_map[chan].core->set_mux(connection); +    } +      void set_rx_fe_corrections(const double lo_freq, const size_t chan)      {          if (not _ignore_cal_file) { @@ -1867,6 +1911,9 @@ private:          tx_frontend_core_200::sptr core;      }; +    bool _basic_lf_rx; +    bool _basic_lf_tx; +      std::unordered_map<size_t, rx_fe_perif> _rx_fe_map;      std::unordered_map<size_t, tx_fe_perif> _tx_fe_map; | 
