diff options
author | mattprost <matt.prost@ni.com> | 2021-12-16 13:48:26 -0600 |
---|---|---|
committer | Aaron Rossetto <aaron.rossetto@ni.com> | 2022-04-07 13:28:02 -0700 |
commit | b8acf58798018f5fb4d84d470badadce5dd3a08d (patch) | |
tree | 137db7eeff0d3bbc202b228fd4bee4f143b1b467 | |
parent | a8ad4917d331258e163e1786c0325a4b7e7d2e3e (diff) | |
download | uhd-b8acf58798018f5fb4d84d470badadce5dd3a08d.tar.gz uhd-b8acf58798018f5fb4d84d470badadce5dd3a08d.tar.bz2 uhd-b8acf58798018f5fb4d84d470badadce5dd3a08d.zip |
n310: Add Filter API to n310
Add the Filter API to n3xx specifically for the AD937x device. The TX
filter is limited to 32 taps, and the RX filter is limited to 48 taps.
This feature requires MPM version 4.2 or later on the device.
Co-authored-by: bpadalino <bpadalino@gmail.com>
Signed-off-by: mattprost <matt.prost@ni.com>
-rw-r--r-- | host/lib/usrp/common/ad9361_driver/ad9361_device.cpp | 2 | ||||
-rw-r--r-- | host/lib/usrp/dboard/magnesium/magnesium_ad9371_iface.cpp | 12 | ||||
-rw-r--r-- | host/lib/usrp/dboard/magnesium/magnesium_ad9371_iface.hpp | 5 | ||||
-rw-r--r-- | host/lib/usrp/dboard/magnesium/magnesium_constants.hpp | 3 | ||||
-rw-r--r-- | host/lib/usrp/dboard/magnesium/magnesium_radio_control.cpp | 139 | ||||
-rw-r--r-- | host/lib/usrp/dboard/magnesium/magnesium_radio_control.hpp | 21 | ||||
-rw-r--r-- | host/lib/usrp/multi_usrp_rfnoc.cpp | 38 | ||||
-rw-r--r-- | host/python/pyuhd.cpp | 1 | ||||
-rw-r--r-- | mpm/include/mpm/ad937x/ad937x_ctrl.hpp | 2 | ||||
-rw-r--r-- | mpm/lib/mykonos/ad937x_ctrl.cpp | 9 | ||||
-rw-r--r-- | mpm/lib/mykonos/ad937x_device.cpp | 71 | ||||
-rw-r--r-- | mpm/lib/mykonos/ad937x_device.hpp | 7 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/dboard_manager/magnesium.py | 9 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/rpc_server.py | 2 |
14 files changed, 284 insertions, 37 deletions
diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp index 6d687f80e..e53903c49 100644 --- a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp +++ b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp @@ -2946,7 +2946,7 @@ filter_info_base::sptr ad9361_device_t::_get_filter_fir( max_num_taps = _get_num_fir_taps(direction); filter_info_base::sptr fir( - new digital_filter_fir<int16_t>(filter_info_base::DIGITAL_FIR_I16, + std::make_shared<digital_filter_fir<int16_t>>(filter_info_base::DIGITAL_FIR_I16, (enable == 0) ? true : false, 5, rate, diff --git a/host/lib/usrp/dboard/magnesium/magnesium_ad9371_iface.cpp b/host/lib/usrp/dboard/magnesium/magnesium_ad9371_iface.cpp index 3bb0aeea6..e5bb87216 100644 --- a/host/lib/usrp/dboard/magnesium/magnesium_ad9371_iface.cpp +++ b/host/lib/usrp/dboard/magnesium/magnesium_ad9371_iface.cpp @@ -135,3 +135,15 @@ std::string magnesium_ad9371_iface::get_lo_source(const uhd::direction_t dir) UHD_LOG_TRACE(_log_prefix, _rpc_prefix << "get_lo_source returned " << retval); return retval; } + +void magnesium_ad9371_iface::set_fir( + const std::string& name, const int8_t gain, const std::vector<int16_t>& coeffs) +{ + request<void>("set_fir", name, gain, coeffs); +} + +std::pair<int8_t, std::vector<int16_t>> magnesium_ad9371_iface::get_fir( + const std::string& name) +{ + return request<std::pair<int8_t, std::vector<int16_t>>>("get_fir", name); +} diff --git a/host/lib/usrp/dboard/magnesium/magnesium_ad9371_iface.hpp b/host/lib/usrp/dboard/magnesium/magnesium_ad9371_iface.hpp index 83381f114..0c1012fd5 100644 --- a/host/lib/usrp/dboard/magnesium/magnesium_ad9371_iface.hpp +++ b/host/lib/usrp/dboard/magnesium/magnesium_ad9371_iface.hpp @@ -37,6 +37,11 @@ public: std::string get_lo_source(const uhd::direction_t dir); + void set_fir( + const std::string& name, const int8_t gain, const std::vector<int16_t>& coeffs); + + std::pair<int8_t, std::vector<int16_t>> get_fir(const std::string& name); + private: /*! Shorthand to perform an RPC request. Saves some typing. */ diff --git a/host/lib/usrp/dboard/magnesium/magnesium_constants.hpp b/host/lib/usrp/dboard/magnesium/magnesium_constants.hpp index 8de62743d..9eaea8027 100644 --- a/host/lib/usrp/dboard/magnesium/magnesium_constants.hpp +++ b/host/lib/usrp/dboard/magnesium/magnesium_constants.hpp @@ -22,6 +22,9 @@ static constexpr double AD9371_TX_MAX_BANDWIDTH = 100.0e6; // HZ static constexpr double AD9371_MIN_FREQ = 300.0e6; // Hz static constexpr double AD9371_MAX_FREQ = 6.0e9; // Hz +static constexpr size_t AD9371_RX_MAX_FIR_TAPS = 48; // Coefficients +static constexpr size_t AD9371_TX_MAX_FIR_TAPS = 32; // Coefficients + static constexpr double ADF4351_MIN_FREQ = 35.0e6; static constexpr double ADF4351_MAX_FREQ = 4.4e9; diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_control.cpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_control.cpp index 8e2463721..249833ddf 100644 --- a/host/lib/usrp/dboard/magnesium/magnesium_radio_control.cpp +++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_control.cpp @@ -1175,6 +1175,145 @@ sensor_value_t magnesium_radio_control_impl::get_tx_sensor( } /************************************************************************** + * Filter API + *************************************************************************/ +std::vector<std::string> magnesium_radio_control_impl::get_rx_filter_names( + const size_t chan) const +{ + UHD_ASSERT_THROW(chan < TOTAL_RADIO_PORTS); + if (chan % 2 == 0) { + return {"RX1_FIR", "RX1RX2_FIR"}; + } else { + return {"RX2_FIR", "RX1RX2_FIR"}; + } +} + +uhd::filter_info_base::sptr magnesium_radio_control_impl::get_rx_filter( + const std::string& name, const size_t) +{ + if (_mpm_compat_num[0] < 4 || (_mpm_compat_num[0] == 4 && _mpm_compat_num[1] < 2)) { + RFNOC_LOG_WARNING("Getting rx filter not supported. Please upgrade MPM to a " + "minimum version of 4.2."); + return std::make_shared<uhd::digital_filter_fir<int16_t>>( + uhd::filter_info_base::filter_type::DIGITAL_FIR_I16, + false, + 0, + 1.0, + 1, + 1, + 32767, + AD9371_RX_MAX_FIR_TAPS, + std::vector<int16_t>(AD9371_RX_MAX_FIR_TAPS, 0)); + } + + const auto rv = _ad9371->get_fir(name); + const auto coeffs = rv.second; + // TODO: Put gain in the digital_filter_fir + return std::make_shared<uhd::digital_filter_fir<int16_t>>( + uhd::filter_info_base::filter_type::DIGITAL_FIR_I16, + false, + 0, + 1.0, + 1, + 1, + 32767, + AD9371_RX_MAX_FIR_TAPS, + coeffs); +} + +void magnesium_radio_control_impl::set_rx_filter( + const std::string& name, uhd::filter_info_base::sptr filter, const size_t) +{ + std::lock_guard<std::recursive_mutex> l(_set_lock); + + if (_mpm_compat_num[0] < 4 || (_mpm_compat_num[0] == 4 && _mpm_compat_num[1] < 2)) { + RFNOC_LOG_WARNING("Setting rx filter not supported. Please upgrade MPM to a " + "minimum version of 4.2."); + return; + } + + auto fir = std::dynamic_pointer_cast<uhd::digital_filter_fir<int16_t>>(filter); + if (fir == nullptr) { + throw uhd::runtime_error("Invalid Filter Type for RX Filter"); + } + if (fir->get_taps().size() != AD9371_RX_MAX_FIR_TAPS) { + throw uhd::runtime_error("AD937x RX Filter Taps must be " + + std::to_string(AD9371_RX_MAX_FIR_TAPS) + + " taps long!"); + } + // TODO: Use gain in the digital_filter_fir + _ad9371->set_fir(name, 6, fir->get_taps()); +} + +std::vector<std::string> magnesium_radio_control_impl::get_tx_filter_names( + const size_t chan) const +{ + UHD_ASSERT_THROW(chan < TOTAL_RADIO_PORTS); + if (chan % 2 == 0) { + return {"TX1_FIR", "TX1TX2_FIR"}; + } else { + return {"TX2_FIR", "TX1TX2_FIR"}; + } +} + +uhd::filter_info_base::sptr magnesium_radio_control_impl::get_tx_filter( + const std::string& name, const size_t) +{ + if (_mpm_compat_num[0] < 4 || (_mpm_compat_num[0] == 4 && _mpm_compat_num[1] < 2)) { + RFNOC_LOG_WARNING("Getting tx filter not supported. Please upgrade MPM to a " + "minimum version of 4.2."); + return std::make_shared<uhd::digital_filter_fir<int16_t>>( + uhd::filter_info_base::filter_type::DIGITAL_FIR_I16, + false, + 0, + 1.0, + 1, + 1, + 32767, + AD9371_TX_MAX_FIR_TAPS, + std::vector<int16_t>(AD9371_TX_MAX_FIR_TAPS, 0)); + } + + const auto rv = _ad9371->get_fir(name); + const auto taps = rv.second; + // TODO: Use gain in the digital_filter_fir + return std::make_shared<uhd::digital_filter_fir<int16_t>>( + uhd::filter_info_base::filter_type::DIGITAL_FIR_I16, + false, + 0, + 1.0, + 1, + 1, + 32767, + AD9371_TX_MAX_FIR_TAPS, + taps); +} + +void magnesium_radio_control_impl::set_tx_filter( + const std::string& name, uhd::filter_info_base::sptr filter, const size_t) +{ + std::lock_guard<std::recursive_mutex> l(_set_lock); + + if (_mpm_compat_num[0] < 4 || (_mpm_compat_num[0] == 4 && _mpm_compat_num[1] < 2)) { + RFNOC_LOG_WARNING("Setting tx filter not supported. Please upgrade MPM to a " + "minimum version of 4.2."); + return; + } + + auto fir = std::dynamic_pointer_cast<uhd::digital_filter_fir<int16_t>>(filter); + if (fir == nullptr) { + throw uhd::runtime_error("Invalid Filter Type for TX Filter"); + } + if (fir->get_taps().size() != AD9371_TX_MAX_FIR_TAPS) { + throw uhd::runtime_error("AD937x TX Filter Taps must be " + + std::to_string(AD9371_TX_MAX_FIR_TAPS) + + " taps long!"); + } + // TODO: Use gain in the digital_filter_fir + _ad9371->set_fir(name, 6, fir->get_taps()); +} + +/************************************************************************** * Radio Identification API Calls *************************************************************************/ size_t magnesium_radio_control_impl::get_chan_from_dboard_fe( diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_control.hpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_control.hpp index 5ac1ca245..814fbecf1 100644 --- a/host/lib/usrp/dboard/magnesium/magnesium_radio_control.hpp +++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_control.hpp @@ -14,6 +14,7 @@ #include "magnesium_ad9371_iface.hpp" #include "magnesium_cpld_ctrl.hpp" #include "magnesium_cpld_regs.hpp" +#include <uhd/rfnoc/filter_node.hpp> #include <uhd/types/eeprom.hpp> #include <uhd/types/serial.hpp> #include <uhd/usrp/dboard_manager.hpp> @@ -31,7 +32,8 @@ namespace uhd { namespace rfnoc { * * This daughterboard is used on the USRP N310 and N300. */ -class magnesium_radio_control_impl : public radio_control_impl +class magnesium_radio_control_impl : public radio_control_impl, + public uhd::rfnoc::detail::filter_node { public: //! Frequency bands for RX. Bands are a function of the analog filter banks @@ -173,6 +175,23 @@ public: std::string get_fe_name( const size_t chan, const uhd::direction_t direction) const override; + /************************************************************************** + * Filter API + *************************************************************************/ + std::vector<std::string> get_rx_filter_names(const size_t chan) const override; + uhd::filter_info_base::sptr get_rx_filter( + const std::string& name, const size_t chan) override; + void set_rx_filter(const std::string& name, + uhd::filter_info_base::sptr filter, + const size_t chan) override; + + std::vector<std::string> get_tx_filter_names(const size_t chan) const override; + uhd::filter_info_base::sptr get_tx_filter( + const std::string& name, const size_t chan) override; + void set_tx_filter(const std::string& name, + uhd::filter_info_base::sptr filter, + const size_t chan) override; + private: /************************************************************************** * Helpers diff --git a/host/lib/usrp/multi_usrp_rfnoc.cpp b/host/lib/usrp/multi_usrp_rfnoc.cpp index 00e386b71..270e86ca4 100644 --- a/host/lib/usrp/multi_usrp_rfnoc.cpp +++ b/host/lib/usrp/multi_usrp_rfnoc.cpp @@ -17,6 +17,7 @@ #include <uhd/usrp/multi_usrp.hpp> #include <uhd/utils/graph_utils.hpp> #include <uhd/utils/math.hpp> +#include <uhd/utils/string.hpp> #include <uhdlib/rfnoc/rfnoc_device.hpp> #include <uhdlib/rfnoc/rfnoc_rx_streamer.hpp> #include <uhdlib/rfnoc/rfnoc_tx_streamer.hpp> @@ -2229,11 +2230,13 @@ public: const std::string& name, const size_t chan) override { try { + // Get the blockid and filtername separated from the name string + const auto names = string::split(name, ":"); + const auto& blockid = names.first; + const auto& filter_name = names.second; // The block_id_t constructor is pretty smart; let it handle the parsing. - block_id_t block_id(name); - auto rx_chan = _get_rx_chan(chan); - // The filter name is the `name` after the BLOCK_ID and a `:` - std::string filter_name = name.substr(block_id.to_string().size() + 1); + block_id_t block_id(blockid); + const auto rx_chan = _get_rx_chan(chan); // Try to dynamic cast either the radio or the DDC to a filter_node, and call // its filter function auto block_ctrl = [rx_chan, block_id, chan]() -> noc_block_base::sptr { @@ -2270,11 +2273,12 @@ public: { MUX_RX_API_CALL(set_rx_filter, name, filter); try { + const auto names = string::split(name, ":"); + const auto& blockid = names.first; + const auto& filter_name = names.second; // The block_id_t constructor is pretty smart; let it handle the parsing. - block_id_t block_id(name); - auto rx_chan = _get_rx_chan(chan); - // The filter name is the `name` after the BLOCK_ID and a `:` - std::string filter_name = name.substr(block_id.to_string().size() + 1); + block_id_t block_id(blockid); + const auto rx_chan = _get_rx_chan(chan); // Try to dynamic cast either the radio or the DDC to a filter_node, and call // its filter function auto block_ctrl = [rx_chan, block_id, chan]() -> noc_block_base::sptr { @@ -2352,11 +2356,12 @@ public: const std::string& name, const size_t chan) override { try { + const auto names = string::split(name, ":"); + const auto& blockid = names.first; + const auto& filter_name = names.second; // The block_id_t constructor is pretty smart; let it handle the parsing. - block_id_t block_id(name); - auto tx_chan = _get_tx_chan(chan); - // The filter name is the `name` after the BLOCK_ID and a `:` - std::string filter_name = name.substr(block_id.to_string().size() + 1); + block_id_t block_id(blockid); + const auto tx_chan = _get_tx_chan(chan); // Try to dynamic cast either the radio or the DUC to a filter_node, and call // its filter function auto block_ctrl = [tx_chan, block_id, chan]() -> noc_block_base::sptr { @@ -2393,11 +2398,12 @@ public: { MUX_TX_API_CALL(set_tx_filter, name, filter); try { + const auto names = string::split(name, ":"); + const auto& blockid = names.first; + const auto& filter_name = names.second; // The block_id_t constructor is pretty smart; let it handle the parsing. - block_id_t block_id(name); - auto tx_chan = _get_tx_chan(chan); - // The filter name is the `name` after the BLOCK_ID and a `:` - std::string filter_name = name.substr(block_id.to_string().size() + 1); + block_id_t block_id(blockid); + const auto tx_chan = _get_tx_chan(chan); // Try to dynamic cast either the radio or the DUC to a filter_node, and call // its filter function auto block_ctrl = [tx_chan, block_id, chan]() -> noc_block_base::sptr { diff --git a/host/python/pyuhd.cpp b/host/python/pyuhd.cpp index ca06f2d97..7022a5287 100644 --- a/host/python/pyuhd.cpp +++ b/host/python/pyuhd.cpp @@ -7,6 +7,7 @@ #include <pybind11/complex.h> #include <pybind11/pybind11.h> +#include <pybind11/stl.h> #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION #include <numpy/arrayobject.h> diff --git a/mpm/include/mpm/ad937x/ad937x_ctrl.hpp b/mpm/include/mpm/ad937x/ad937x_ctrl.hpp index 936655405..57840b9f3 100644 --- a/mpm/include/mpm/ad937x/ad937x_ctrl.hpp +++ b/mpm/include/mpm/ad937x/ad937x_ctrl.hpp @@ -259,7 +259,7 @@ public: const std::string& which, const int8_t gain, const std::vector<int16_t>& fir) = 0; //! get the FIR filter for the frontend which - virtual std::vector<int16_t> get_fir(const std::string& which, int8_t& gain) = 0; + virtual std::pair<int8_t, std::vector<int16_t>> get_fir(const std::string& which) = 0; // TODO: update docstring with temperature unit and calibration information //! get the device temperature diff --git a/mpm/lib/mykonos/ad937x_ctrl.cpp b/mpm/lib/mykonos/ad937x_ctrl.cpp index 7cd5c1d98..2a4bfbc87 100644 --- a/mpm/lib/mykonos/ad937x_ctrl.cpp +++ b/mpm/lib/mykonos/ad937x_ctrl.cpp @@ -430,7 +430,6 @@ public: virtual void set_fir( const std::string& which, const int8_t gain, const std::vector<int16_t>& fir) { - const auto dir = _get_direction_from_antenna(which); const auto lengths = _get_valid_fir_lengths(which); if (std::find(lengths.begin(), lengths.end(), fir.size()) == lengths.end()) { @@ -438,15 +437,13 @@ public: } std::lock_guard<std::mutex> lock(*spi_mutex); - device.set_fir(dir, gain, fir); + device.set_fir(which, gain, fir); } - virtual std::vector<int16_t> get_fir(const std::string& which, int8_t& gain) + virtual std::pair<int8_t, std::vector<int16_t>> get_fir(const std::string& which) { - auto dir = _get_direction_from_antenna(which); - std::lock_guard<std::mutex> lock(*spi_mutex); - return device.get_fir(dir, gain); + return device.get_fir(which); } virtual int16_t get_temperature() diff --git a/mpm/lib/mykonos/ad937x_device.cpp b/mpm/lib/mykonos/ad937x_device.cpp index fba065983..1a1905004 100644 --- a/mpm/lib/mykonos/ad937x_device.cpp +++ b/mpm/lib/mykonos/ad937x_device.cpp @@ -10,6 +10,7 @@ #include "adi/mykonos_gpio.h" #include "config/ad937x_config_t.hpp" #include "config/ad937x_default_config.hpp" +#include "mpm/ad937x/ad937x_ctrl.hpp" #include <uhd/utils/algorithm.hpp> #include <boost/format.hpp> #include <cmath> @@ -20,6 +21,7 @@ using namespace mpm::ad937x::device; using namespace mpm::ad937x::gpio; +using namespace mpm::chips; using namespace uhd; const double ad937x_device::MIN_FREQ = 300e6; @@ -59,6 +61,20 @@ static constexpr double AD9371_TX_DAC_FILT_MAX_CORNER = 187.0e6; // Hz static const uint32_t PLL_LOCK_TIMEOUT_MS = 200; +const std::map<std::string, mykonosfirName_t> ad937x_device::_tx_filter_map{ + {"TX1_FIR", TX1_FIR}, + {"TX2_FIR", TX2_FIR}, + {"TX1TX2_FIR", TX1TX2_FIR}, +}; + +const std::map<std::string, mykonosfirName_t> ad937x_device::_rx_filter_map{ + {"RX1_FIR", RX1_FIR}, + {"RX2_FIR", RX2_FIR}, + {"RX1RX2_FIR", RX1RX2_FIR}, + {"OBSRX_A_FIR", OBSRX_A_FIR}, + {"OBSRX_B_FIR", OBSRX_B_FIR}, +}; + // Amount of time to average samples for RX DC offset // A larger averaging window will result in: // Longer latency to correct DC offset changes @@ -667,6 +683,28 @@ void ad937x_device::set_agc_mode(const direction_t direction, const gain_mode_t } void ad937x_device::set_fir( + const std::string& name, int8_t gain, const std::vector<int16_t>& fir) +{ + mykonosfirName_t filter_name; + if (_rx_filter_map.count(name) == 1) { + filter_name = _rx_filter_map.at(name); + mykonos_config.rx_fir_config.set_fir(gain, fir); + } else if (_tx_filter_map.count(name) == 1) { + filter_name = _tx_filter_map.at(name); + mykonos_config.tx_fir_config.set_fir(gain, fir); + } else { + throw mpm::runtime_error("set_fir invalid name: " + name); + } + mykonosFir_t filter{.gain_dB = gain, + .numFirCoefs = static_cast<uint8_t>(fir.size()), + .coefs = const_cast<int16_t*>(fir.data())}; + const auto state = _move_to_config_state(); + CALL_API(MYKONOS_programFir(mykonos_config.device, filter_name, &filter)); + _restore_from_config_state(state); +} + + +void ad937x_device::set_fir( const direction_t direction, int8_t gain, const std::vector<int16_t>& fir) { switch (direction) { @@ -679,8 +717,13 @@ void ad937x_device::set_fir( default: MPM_THROW_INVALID_CODE_PATH(); } - - // TODO: reload this on device + mykonosfirName_t filter_name = (direction == TX_DIRECTION) ? TX1TX2_FIR : RX1RX2_FIR; + mykonosFir_t filter{.gain_dB = gain, + .numFirCoefs = static_cast<uint8_t>(fir.size()), + .coefs = const_cast<int16_t*>(fir.data())}; + const auto state = _move_to_config_state(); + CALL_API(MYKONOS_programFir(mykonos_config.device, filter_name, &filter)); + _restore_from_config_state(state); } void ad937x_device::set_gain_pin_step_sizes(const direction_t direction, @@ -795,16 +838,24 @@ double ad937x_device::get_gain(const direction_t direction, const chain_t chain) } } -std::vector<int16_t> ad937x_device::get_fir(const direction_t direction, int8_t& gain) +std::pair<int8_t, std::vector<int16_t>> ad937x_device::get_fir(const std::string& name) { - switch (direction) { - case TX_DIRECTION: - return mykonos_config.tx_fir_config.get_fir(gain); - case RX_DIRECTION: - return mykonos_config.rx_fir_config.get_fir(gain); - default: - MPM_THROW_INVALID_CODE_PATH(); + mykonosfirName_t filter_name; + if (_rx_filter_map.count(name) == 1) { + filter_name = _rx_filter_map.at(name); + } else if (_tx_filter_map.count(name) == 1) { + filter_name = _tx_filter_map.at(name); + } else { + throw mpm::runtime_error("get_fir invalid name: " + name); } + mykonosFir_t fir; + std::vector<int16_t> rv(96, 0); + fir.coefs = rv.data(); + const auto state = _move_to_config_state(); + CALL_API(MYKONOS_readFir(mykonos_config.device, filter_name, &fir)); + _restore_from_config_state(state); + rv.resize(fir.numFirCoefs); + return std::pair<int8_t, std::vector<int16_t>>(fir.gain_dB, rv); } int16_t ad937x_device::get_temperature() diff --git a/mpm/lib/mykonos/ad937x_device.hpp b/mpm/lib/mykonos/ad937x_device.hpp index 8ee77db54..4b4503eb3 100644 --- a/mpm/lib/mykonos/ad937x_device.hpp +++ b/mpm/lib/mykonos/ad937x_device.hpp @@ -20,6 +20,7 @@ #include <boost/filesystem.hpp> #include <boost/noncopyable.hpp> #include <functional> +#include <map> #include <memory> class ad937x_device : public boost::noncopyable @@ -82,9 +83,10 @@ public: bool get_pll_lock_status(const uint8_t pll, const bool wait_for_lock = false); + void set_fir(const std::string& name, int8_t gain, const std::vector<int16_t>& fir); void set_fir( const uhd::direction_t direction, int8_t gain, const std::vector<int16_t>& fir); - std::vector<int16_t> get_fir(const uhd::direction_t direction, int8_t& gain); + std::pair<int8_t, std::vector<int16_t>> get_fir(const std::string& name); int16_t get_temperature(); @@ -136,4 +138,7 @@ private: static double _convert_rx_gain_from_mykonos(const uint8_t gain); static uint16_t _convert_tx_gain_to_mykonos(const double gain); static double _convert_tx_gain_from_mykonos(const uint16_t gain); + + const static std::map<std::string, mykonosfirName_t> _tx_filter_map; + const static std::map<std::string, mykonosfirName_t> _rx_filter_map; }; diff --git a/mpm/python/usrp_mpm/dboard_manager/magnesium.py b/mpm/python/usrp_mpm/dboard_manager/magnesium.py index d5cc525dc..1ffbc6f16 100644 --- a/mpm/python/usrp_mpm/dboard_manager/magnesium.py +++ b/mpm/python/usrp_mpm/dboard_manager/magnesium.py @@ -493,6 +493,15 @@ class Magnesium(BfrfsEEPROM, DboardManagerBase): self._reinit(self.master_clock_rate) return bw + def set_fir(self, name, gain, coeffs): + self.log.debug("ad9371 set_fir name: {} gain: {} coeffs: {}".format(name, gain, coeffs)) + self.mykonos.set_fir(name, gain, coeffs) + return + + def get_fir(self, name): + self.log.debug("ad9371 get_fir name: {}".format(name)) + return self.mykonos.get_fir(name) + ########################################################################## # Debug ########################################################################## diff --git a/mpm/python/usrp_mpm/rpc_server.py b/mpm/python/usrp_mpm/rpc_server.py index 78b76ab19..c0779ab77 100644 --- a/mpm/python/usrp_mpm/rpc_server.py +++ b/mpm/python/usrp_mpm/rpc_server.py @@ -32,7 +32,7 @@ from usrp_mpm.sys_utils import net TIMEOUT_INTERVAL = 5.0 # Seconds before claim expires (default value) TOKEN_LEN = 16 # Length of the token string # Compatibility number for MPM -MPM_COMPAT_NUM = (4, 1) +MPM_COMPAT_NUM = (4, 2) def no_claim(func): " Decorator for functions that require no token check " |