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 /host | |
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>
Diffstat (limited to 'host')
-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 |
8 files changed, 203 insertions, 18 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> |