From ae426043df93c4c0255ae05419953645214ff198 Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Wed, 15 Apr 2020 15:08:50 -0700 Subject: b200: Enable power calibration API This lets the B200 transmit and/or receive at given reference power levels. Requirement is that the devices have been separately calibrated with an external calibration device. --- host/lib/usrp/b200/b200_impl.cpp | 114 ++++++++++++++++++++++++++++++++------- host/lib/usrp/b200/b200_impl.hpp | 3 ++ 2 files changed, 98 insertions(+), 19 deletions(-) (limited to 'host/lib') diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index fd8fd6500..23baf44cf 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -974,39 +975,114 @@ void b200_impl::setup_radio(const size_t dspno) //////////////////////////////////////////////////////////////////// // create RF frontend interfacing //////////////////////////////////////////////////////////////////// + // The "calibration serial" is the motherboard serial plus the frontend + // (A or B) separated by colon, e.g. "1234ABC:A". + const std::string cal_serial = + _tree->access(mb_path / "eeprom").get()["serial"] + "#" + + (dspno ? "B" : "A"); + // The "calibration key" is either b2xxmini_power_cal_$dir_$ant, or + // b2xx_power_cal_$dir_$ant, depending on the form factor. + // $dir is either "tx" or "rx", and "ant" is either "tx_rx" or "rx2" (i.e., + // sanitized version of the antenna names that work in filenames. + const std::string cal_key_base = (_product == B200MINI or _product == B205MINI) + ? "b2xxmini_pwr_" + : "b2xx_pwr_"; for (direction_t dir : std::vector{RX_DIRECTION, TX_DIRECTION}) { - const std::string x = (dir == RX_DIRECTION) ? "rx" : "tx"; - const std::string key = std::string(((dir == RX_DIRECTION) ? "RX" : "TX")) + const std::string dir_key = (dir == RX_DIRECTION) ? "rx" : "tx"; + const std::string key = std::string(((dir == RX_DIRECTION) ? "RX" : "TX")) + std::string(((dspno == _fe1) ? "1" : "2")); const fs_path rf_fe_path = - mb_path / "dboards" / "A" / (x + "_frontends") / (dspno ? "B" : "A"); + mb_path / "dboards" / "A" / (dir_key + "_frontends") / (dspno ? "B" : "A"); + const std::vector ants = + (dir == RX_DIRECTION) ? std::vector{"TX/RX", "RX2"} + : std::vector{"TX/RX"}; // This will connect all the AD936x-specific items _codec_mgr->populate_frontend_subtree(_tree->subtree(rf_fe_path), key, dir); - // Now connect all the b200_impl-specific items - _tree->create(rf_fe_path / "sensors" / "lo_locked") - .set_publisher( - std::bind(&b200_impl::get_fe_pll_locked, this, dir == TX_DIRECTION)); - _tree->access(rf_fe_path / "freq" / "value") - .add_coerced_subscriber( - std::bind(&b200_impl::update_bandsel, this, key, std::placeholders::_1)); + // Antenna controls are board-specific, not AD936x specific if (dir == RX_DIRECTION) { - static const std::vector ants{"TX/RX", "RX2"}; - _tree->create>(rf_fe_path / "antenna" / "options") - .set(ants); _tree->create(rf_fe_path / "antenna" / "value") - .add_coerced_subscriber(std::bind( - &b200_impl::update_antenna_sel, this, dspno, std::placeholders::_1)) + .add_coerced_subscriber([this, dspno](const std::string& antenna) { + this->update_antenna_sel(dspno, antenna); + }) .set("RX2"); - } else if (dir == TX_DIRECTION) { - static const std::vector ants(1, "TX/RX"); - _tree->create>(rf_fe_path / "antenna" / "options") - .set(ants); _tree->create(rf_fe_path / "antenna" / "value").set("TX/RX"); } + // We don't add any baseband correction + auto ggroup = uhd::gain_group::make(); + constexpr char HW_GAIN_STAGE[] = "hw"; + ggroup->register_fcns(HW_GAIN_STAGE, + {// Get gain range: + [key]() { return ad9361_ctrl::get_gain_range(key); }, + // Get gain: + [this, rf_fe_path, key]() { + return _tree + ->access(rf_fe_path / "gains" + / ad9361_ctrl::get_gain_names(key).at(0) + / "value") + .get(); + }, + // Set gain: + [this, rf_fe_path, key](const double gain) { + _tree + ->access(rf_fe_path / "gains" + / ad9361_ctrl::get_gain_names(key).at(0) + / "value") + .set(gain); + }}); + // Add power controls + perif.pwr_mgr.insert({dir_key, + pwr_cal_mgr::make( + cal_serial, + "B200-CAL-" + key, + // Frequency getter: + [this, rf_fe_path]() { + return _tree->access(rf_fe_path / "freq" / "value").get(); + }, + // Current key getter (see notes on calibration key above): + [this, rf_fe_path, cal_key_base, dir_key]() { + return cal_key_base + dir_key + "_" + + pwr_cal_mgr::sanitize_antenna_name( + _tree->access( + rf_fe_path / "antenna" / "value") + .get()); + }, + ggroup)}); + perif.pwr_mgr.at(dir_key)->populate_subtree(_tree->subtree(rf_fe_path)); + perif.pwr_mgr.at(dir_key)->set_temperature( + _tree->access(rf_fe_path / "sensors" / "temp") + .get() + .to_int()); + + // Now connect all the b200_impl-specific items + _tree->create(rf_fe_path / "sensors" / "lo_locked") + .set_publisher( + [this, dir]() { return this->get_fe_pll_locked(dir == TX_DIRECTION); }); + _tree->access(rf_fe_path / "freq" / "value") + .add_coerced_subscriber([this, key](const double freq) { + return this->update_bandsel(key, freq); + }) + // Every time we retune, we re-set the power level. + .add_coerced_subscriber([this, pwr_mgr = perif.pwr_mgr.at(dir_key)]( + const double) { pwr_mgr->update_power(); }) + + ; + _tree->create>(rf_fe_path / "antenna" / "options") + .set(ants); + // When we set the gain, we need to disable power tracking. Note that + // the power manager also calls into the gains property, and thus + // clobbers its own tracking mode, but that's OK because set_power() will + // always reset the tracking mode. + _tree + ->access( + rf_fe_path / "gains" / ad9361_ctrl::get_gain_names(key).at(0) / "value") + .add_coerced_subscriber([pwr_mgr = perif.pwr_mgr.at(dir_key)](const double) { + pwr_mgr->set_tracking_mode(pwr_cal_mgr::tracking_mode::TRACK_GAIN); + }); + if (_enable_user_regs) { _tree->create(rf_fe_path / "user_settings/iface") .set(perif.user_settings); diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp index d151bc59d..cb2edea80 100644 --- a/host/lib/usrp/b200/b200_impl.hpp +++ b/host/lib/usrp/b200/b200_impl.hpp @@ -35,9 +35,11 @@ #include #include #include +#include #include #include #include +#include static const uint8_t B200_FW_COMPAT_NUM_MAJOR = 8; static const uint8_t B200_FW_COMPAT_NUM_MINOR = 0; @@ -203,6 +205,7 @@ private: std::weak_ptr tx_streamer; user_settings_core_3000::sptr user_settings; bool ant_rx2; + std::unordered_map pwr_mgr; }; std::vector _radio_perifs; -- cgit v1.2.3