diff options
author | Martin Braun <martin.braun@ettus.com> | 2020-04-15 15:08:50 -0700 |
---|---|---|
committer | Aaron Rossetto <aaron.rossetto@ni.com> | 2020-06-03 15:14:01 -0500 |
commit | ae426043df93c4c0255ae05419953645214ff198 (patch) | |
tree | 9ac3abcff1797fbbf32e47c617c3ca810b998d2d /host/lib | |
parent | d4e62f0d9d26107c0b6677308ea83b2f2dfe7da4 (diff) | |
download | uhd-ae426043df93c4c0255ae05419953645214ff198.tar.gz uhd-ae426043df93c4c0255ae05419953645214ff198.tar.bz2 uhd-ae426043df93c4c0255ae05419953645214ff198.zip |
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.
Diffstat (limited to 'host/lib')
-rw-r--r-- | host/lib/usrp/b200/b200_impl.cpp | 114 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_impl.hpp | 3 |
2 files changed, 98 insertions, 19 deletions
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 <uhd/utils/paths.hpp> #include <uhd/utils/safe_call.hpp> #include <uhd/utils/static.hpp> +#include <uhd/cal/database.hpp> #include <boost/filesystem.hpp> #include <boost/format.hpp> #include <boost/functional/hash.hpp> @@ -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<mboard_eeprom_t>(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<direction_t>{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<std::string> ants = + (dir == RX_DIRECTION) ? std::vector<std::string>{"TX/RX", "RX2"} + : std::vector<std::string>{"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<sensor_value_t>(rf_fe_path / "sensors" / "lo_locked") - .set_publisher( - std::bind(&b200_impl::get_fe_pll_locked, this, dir == TX_DIRECTION)); - _tree->access<double>(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<std::string> ants{"TX/RX", "RX2"}; - _tree->create<std::vector<std::string>>(rf_fe_path / "antenna" / "options") - .set(ants); _tree->create<std::string>(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<std::string> ants(1, "TX/RX"); - _tree->create<std::vector<std::string>>(rf_fe_path / "antenna" / "options") - .set(ants); _tree->create<std::string>(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<double>(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<double>(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<double>(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<std::string>( + 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<sensor_value_t>(rf_fe_path / "sensors" / "temp") + .get() + .to_int()); + + // Now connect all the b200_impl-specific items + _tree->create<sensor_value_t>(rf_fe_path / "sensors" / "lo_locked") + .set_publisher( + [this, dir]() { return this->get_fe_pll_locked(dir == TX_DIRECTION); }); + _tree->access<double>(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<std::vector<std::string>>(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<double>( + 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<uhd::wb_iface::sptr>(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 <uhdlib/usrp/cores/tx_dsp_core_3000.hpp> #include <uhdlib/usrp/cores/tx_vita_core_3000.hpp> #include <uhdlib/usrp/cores/user_settings_core_3000.hpp> +#include <uhdlib/usrp/common/pwr_cal_mgr.hpp> #include <boost/assign.hpp> #include <memory> #include <mutex> +#include <unordered_map> 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<uhd::tx_streamer> tx_streamer; user_settings_core_3000::sptr user_settings; bool ant_rx2; + std::unordered_map<std::string, uhd::usrp::pwr_cal_mgr::sptr> pwr_mgr; }; std::vector<radio_perifs_t> _radio_perifs; |