aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--host/include/uhd/rfnoc/CMakeLists.txt2
-rw-r--r--host/include/uhd/rfnoc/radio_control.hpp585
-rw-r--r--host/include/uhd/rfnoc/rf_control/CMakeLists.txt13
-rw-r--r--host/include/uhd/rfnoc/rf_control/core_iface.hpp448
-rw-r--r--host/include/uhd/rfnoc/rf_control/power_reference_iface.hpp191
-rw-r--r--host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp5
-rw-r--r--host/lib/include/uhdlib/rfnoc/rf_control/dboard_iface.hpp41
-rw-r--r--host/lib/include/uhdlib/rfnoc/rf_control/gain_profile_iface.hpp86
-rw-r--r--host/lib/rfnoc/CMakeLists.txt1
-rw-r--r--host/lib/rfnoc/radio_control_impl.cpp36
-rw-r--r--host/lib/rfnoc/rf_control/CMakeLists.txt13
-rw-r--r--host/lib/rfnoc/rf_control/gain_profile.cpp68
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_radio_control.cpp48
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_radio_control.hpp9
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_radio_control_gain.cpp2
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_radio_control_init.cpp4
-rw-r--r--host/tests/CMakeLists.txt6
-rw-r--r--host/tests/rf_control_gain_profile_test.cpp40
18 files changed, 940 insertions, 658 deletions
diff --git a/host/include/uhd/rfnoc/CMakeLists.txt b/host/include/uhd/rfnoc/CMakeLists.txt
index 24dfa6645..7b21a02ea 100644
--- a/host/include/uhd/rfnoc/CMakeLists.txt
+++ b/host/include/uhd/rfnoc/CMakeLists.txt
@@ -60,4 +60,4 @@ UHD_INSTALL(FILES
add_subdirectory(blocks)
add_subdirectory(core)
-
+add_subdirectory(rf_control)
diff --git a/host/include/uhd/rfnoc/radio_control.hpp b/host/include/uhd/rfnoc/radio_control.hpp
index 3e05e1b91..097529147 100644
--- a/host/include/uhd/rfnoc/radio_control.hpp
+++ b/host/include/uhd/rfnoc/radio_control.hpp
@@ -9,6 +9,8 @@
#include <uhd/config.hpp>
#include <uhd/features/discoverable_feature_getter_iface.hpp>
#include <uhd/rfnoc/noc_block_base.hpp>
+#include <uhd/rfnoc/rf_control/core_iface.hpp>
+#include <uhd/rfnoc/rf_control/power_reference_iface.hpp>
#include <uhd/types/device_addr.hpp>
#include <uhd/types/direction.hpp>
#include <uhd/types/eeprom.hpp>
@@ -21,6 +23,8 @@ namespace uhd { namespace rfnoc {
/*! Parent class for radio block controllers
*/
class radio_control : public noc_block_base,
+ public rf_control::core_iface,
+ public rf_control::power_reference_iface,
public virtual ::uhd::features::discoverable_feature_getter_iface
{
public:
@@ -47,362 +51,6 @@ public:
/**************************************************************************
* RF-Related API Calls
*************************************************************************/
- /*! Return the selected TX antenna for channel \p chan.
- *
- * \return The selected antenna.
- */
- virtual std::string get_tx_antenna(const size_t chan) const = 0;
-
- /*! Return a list of valid TX antenna for channel \p chan.
- *
- * \return The selected antenna.
- */
- virtual std::vector<std::string> get_tx_antennas(const size_t chan) const = 0;
-
- /*! Select RX antenna \p for channel \p chan.
- *
- * \throws uhd::value_error if \p ant is not a valid value.
- */
- virtual void set_tx_antenna(const std::string& ant, const size_t chan) = 0;
-
- /*! Return the selected RX antenna for channel \p chan.
- *
- * \return The selected antenna.
- */
- virtual std::string get_rx_antenna(const size_t chan) const = 0;
-
- /*! Return a list of valid RX antenna for channel \p chan.
- *
- * \return The selected antenna.
- */
- virtual std::vector<std::string> get_rx_antennas(const size_t chan) const = 0;
-
- /*! Select RX antenna \p for channel \p chan.
- *
- * \throws uhd::value_error if \p ant is not a valid value.
- */
- virtual void set_rx_antenna(const std::string& ant, const size_t chan) = 0;
-
- /*! Return the current transmit LO frequency on channel \p chan.
- *
- * \return The current LO frequency.
- */
- virtual double get_tx_frequency(const size_t chan) = 0;
-
- /*! Tune the TX frequency for channel \p chan.
- *
- * This function will attempt to tune as close as possible, and return a
- * coerced value of the actual tuning result.
- *
- * If there is a single LO in this radio, and we're doing direct conversion,
- * then this is the LO frequency.
- *
- * \param freq Frequency in Hz
- * \param chan Channel to tune
- *
- * \return The actual frequency.
- */
- virtual double set_tx_frequency(const double freq, size_t chan) = 0;
-
- /*! Set the TX tune args, if supported by the hardware.
- */
- virtual void set_tx_tune_args(const uhd::device_addr_t& args, const size_t chan) = 0;
-
- /*! Return the range of frequencies that \p chan can be tuned to.
- *
- * \return The range of frequencies that we can tune the TX chan to
- */
- virtual uhd::freq_range_t get_tx_frequency_range(const size_t chan) const = 0;
-
- /*! Return the current receive LO frequency on channel \p chan.
- *
- * \return The current LO frequency.
- */
- virtual double get_rx_frequency(const size_t chan) = 0;
-
- /*! Tune the RX frequency for channel \p chan.
- *
- * This function will attempt to tune as close as possible, and return a
- * coerced value of the actual tuning result.
- *
- * If there is a single LO in this radio, and we're doing direct conversion,
- * then this is the LO frequency.
- *
- * \param freq Requested frequency
- * \param chan Channel number.
- * \return The actual frequency.
- */
- virtual double set_rx_frequency(const double freq, const size_t chan) = 0;
-
- /*! Set the TX tune args, if supported by the hardware.
- */
- virtual void set_rx_tune_args(const uhd::device_addr_t& args, const size_t chan) = 0;
-
- /*! Return the range of frequencies that \p chan can be tuned to.
- *
- * \return The range of frequencies that we can tune the RX chan to
- */
- virtual uhd::freq_range_t get_rx_frequency_range(const size_t chan) const = 0;
-
- /*! Return a list of valid TX gain names
- */
- virtual std::vector<std::string> get_tx_gain_names(const size_t chan) const = 0;
-
- /*! Return a range of valid TX gains
- */
- virtual uhd::gain_range_t get_tx_gain_range(const size_t chan) const = 0;
-
- /*! Return a range of valid TX gains
- */
- virtual uhd::gain_range_t get_tx_gain_range(
- const std::string& name, const size_t chan) const = 0;
-
- /*! Return the overall transmit gain on channel \p chan
- *
- * \return The actual gain value
- */
- virtual double get_tx_gain(const size_t chan) = 0;
-
- /*! Return the transmit gain \p name on channel \p chan
- *
- * \return The actual gain value
- */
- virtual double get_tx_gain(const std::string& name, const size_t chan) = 0;
-
- /*! Set the transmit gain on channel \p chan
- *
- * This function will attempt to set the gain as close as possible,
- * and return a coerced value of the actual gain value.
- *
- * This method will set the overall gain. To set a specific gain, use
- * set_tx_gain(const double, const std::string&, const size_t).
- *
- * \return The actual gain value
- */
- virtual double set_tx_gain(const double gain, const size_t chan) = 0;
-
- /*! Set the transmit gain \p name on channel \p chan
- *
- * This function will attempt to set the gain as close as possible,
- * and return a coerced value of the actual gain value.
- *
- * \return The actual gain value
- */
- virtual double set_tx_gain(
- const double gain, const std::string& name, const size_t chan) = 0;
-
- /*! Return true if this channel has a reference power API enabled
- *
- * Many devices either don't have a built-in reference power API, or they
- * require calibration data for it to work. This means that it is not clear,
- * even when the device type is known, if a device supports setting a power
- * reference level. Use this method to query the availability of
- * set_tx_power_reference() and get_tx_power_reference(), which will throw
- * a uhd::not_implemented_error or uhd::runtime_error if they cannot be used.
- *
- * See \ref page_power for more information, or query the specific device's
- * manual page to see if a power API is available, and how to enable it.
- *
- * \param chan The channel for which this feature is queried
- *
- * \returns true if this channel has a TX power API available
- */
- virtual bool has_tx_power_reference(const size_t chan) = 0;
-
- /*! Set the reference TX power level for a given channel
- *
- * Note: This functionality is not supported for most devices, and will
- * cause a uhd::not_implemented_error exception to be thrown on devices that
- * do not have this functionality.
- *
- * For more information on how to use this API, see \ref page_power.
- *
- * \param power_dbm The reference power level in dBm
- * \param chan The channel for which this setting applies
- *
- * \throws uhd::not_implemented_error if this functionality does not exist
- * for this device
- */
- virtual void set_tx_power_reference(
- const double power_dbm, const size_t chan) = 0;
-
- /*! Return the actual reference TX power level.
- *
- * Note: This functionality is not supported for most devices, and will
- * cause a uhd::not_implemented_error exception to be thrown on devices that
- * do not have this functionality.
- *
- * For more information on how to use this API, see \ref page_power.
- *
- * \param chan The channel for which this setting is queried
- * \throws uhd::not_implemented_error if this functionality does not exist
- * for this device
- */
- virtual double get_tx_power_reference(const size_t chan) = 0;
-
- /*! Return the keys by which the power calibration data is referenced for this
- * channel.
- *
- * The first entry is the key, the second the serial. These are the same
- * arguments that can be used for uhd::usrp::cal::database::read_cal_data()
- * and friends. See also \ref cal_db_serial.
- *
- * Note that the key can change at runtime, e.g., when the antenna port is
- * switched.
- *
- * The difference between this and has_tx_power_reference() is that the
- * latter requires both device support as well as calibration data, whereas
- * this function will never throw, and will always return a non-empty vector
- * if device support is there, even if the device does not have calbration
- * data loaded.
- *
- * \returns an empty vector if no power calibration is supported, or a
- * vector of length 2 with key and serial if it does.
- */
- virtual std::vector<std::string> get_tx_power_ref_keys(const size_t chan = 0) = 0;
-
- /*! Return the available TX power range given the current configuration
- *
- * This will return the range of available power levels given the current
- * frequency, gain profile, antenna, and whatever other settings may affect
- * the available power ranges. Note that the available power range may
- * change frequently, so don't assume an immutable range.
- *
- * \param chan The channel index
- */
- virtual meta_range_t get_tx_power_range(const size_t chan) = 0;
-
- /*! Return a list of valid RX gain names
- */
- virtual std::vector<std::string> get_rx_gain_names(const size_t chan) const = 0;
-
- /*! Return a range of valid RX gains
- */
- virtual uhd::gain_range_t get_rx_gain_range(const size_t chan) const = 0;
-
- /*! Return a range of valid RX gains
- */
- virtual uhd::gain_range_t get_rx_gain_range(
- const std::string& name, const size_t chan) const = 0;
-
- /*! Return the overall receive gain on channel \p chan
- *
- * \return The actual gain value
- */
- virtual double get_rx_gain(const size_t chan) = 0;
-
- /*! Return the receive gain \p name on channel \p chan
- *
- * \return The actual gain value
- */
- virtual double get_rx_gain(const std::string& name, const size_t chan) = 0;
-
- /*! Set the overall receive gain on channel \p chan
- *
- * This function will attempt to set the gain as close as possible,
- * and return a coerced value of the actual gain value.
- *
- * \return The actual gain value
- */
- virtual double set_rx_gain(const double gain, const size_t chan) = 0;
-
- /*! Set the receive gain \p on channel \p chan
- *
- * This function will attempt to set the gain as close as possible,
- * and return a coerced value of the actual gain value.
- *
- * \return The actual gain value
- */
- virtual double set_rx_gain(
- const double gain, const std::string& name, const size_t chan) = 0;
-
- /*! Enable RX AGC on this radio
- *
- * \throws uhd::not_implemented_error if this radio doesn't support RX AGC
- */
- virtual void set_rx_agc(const bool enable, const size_t chan) = 0;
-
- /*! Return true if this channel has a reference power API enabled
- *
- * Many devices either don't have a built-in reference power API, or they
- * require calibration data for it to work. This means that it is not clear,
- * even when the device type is known, if a device supports setting a power
- * reference level. Use this method to query the availability of
- * set_rx_power_reference() and get_rx_power_reference(), which will throw
- * a uhd::not_implemented_error or uhd::runtime_error if they cannot be used.
- *
- * See \ref page_power for more information, or query the specific device's
- * manual page to see if a power API is available, and how to enable it.
- *
- * \param chan The channel for which this feature is queried
- *
- * \returns true if this channel has an RX power API available
- */
- virtual bool has_rx_power_reference(const size_t chan) = 0;
-
- /*! Set the reference RX power level for a given channel
- *
- * Note: This functionality is not supported for most devices, and will
- * cause a uhd::not_implemented_error exception to be thrown on devices that
- * do not have this functionality.
- *
- * For more information on how to use this API, see \ref page_power.
- *
- * \param power_dbm The reference power level in dBm
- * \param chan The channel for which this setting applies
- *
- * \throws uhd::not_implemented_error if this functionality does not exist
- * for this device
- */
- virtual void set_rx_power_reference(
- const double power_dbm, const size_t chan) = 0;
-
- /*! Return the actual reference RX power level.
- *
- * Note: This functionality is not supported for most devices, and will
- * cause a uhd::not_implemented_error exception to be thrown on devices that
- * do not have this functionality.
- *
- * For more information on how to use this API, see \ref page_power.
- *
- * \param chan The channel for which this setting is queried
- * \throws uhd::not_implemented_error if this functionality does not exist
- * for this device
- */
- virtual double get_rx_power_reference(const size_t chan) = 0;
-
- /*! Return the keys by which the power calibration data is referenced for this
- * channel.
- *
- * The first entry is the key, the second the serial. These are the same
- * arguments that can be used for uhd::usrp::cal::database::read_cal_data()
- * and friends. See also \ref cal_db_serial.
- *
- * Note that the key can change at runtime, e.g., when the antenna port is
- * switched.
- *
- * The difference between this and has_rx_power_reference() is that the
- * latter requires both device support as well as calibration data, whereas
- * this function will never throw, and will always return a non-empty vector
- * if device support is there, even if the device does not have calbration
- * data loaded.
- *
- * \returns an empty vector if no power calibration is supported, or a
- * vector of length 2 with key and serial if it does.
- */
- virtual std::vector<std::string> get_rx_power_ref_keys(const size_t chan = 0) = 0;
-
- /*! Return the available RX power range given the current configuration
- *
- * This will return the range of available power levels given the current
- * frequency, gain profile, antenna, and whatever other settings may affect
- * the available power ranges. Note that the available power range may
- * change frequently, so don't assume an immutable range.
- *
- * \param chan The channel index
- */
- virtual meta_range_t get_rx_power_range(const size_t chan) = 0;
-
/*! Return a list of TX gain profiles for this radio
*/
virtual std::vector<std::string> get_tx_gain_profile_names(
@@ -429,231 +77,6 @@ public:
*/
virtual std::string get_rx_gain_profile(const size_t chan) const = 0;
- /*! Return a range of valid TX bandwidths
- */
- virtual meta_range_t get_tx_bandwidth_range(size_t chan) const = 0;
-
- /*! Return the analog filter bandwidth channel \p chan
- *
- * \return The actual bandwidth value
- */
- virtual double get_tx_bandwidth(const size_t chan) = 0;
-
- /*! Set the analog filter bandwidth channel \p chan
- *
- * This function will attempt to set the analog bandwidth.
- *
- * \return The actual bandwidth value
- */
- virtual double set_tx_bandwidth(const double bandwidth, const size_t chan) = 0;
-
- /*! Return a range of valid RX bandwidths
- */
- virtual meta_range_t get_rx_bandwidth_range(size_t chan) const = 0;
-
- /*! Return the analog filter bandwidth channel \p chan
- *
- * \return The actual bandwidth value
- */
- virtual double get_rx_bandwidth(const size_t chan) = 0;
-
- /*! Set the analog filter bandwidth channel \p chan
- *
- * This function will attempt to set the analog bandwidth.
- *
- * \return The actual bandwidth value
- */
- virtual double set_rx_bandwidth(const double bandwidth, const size_t chan) = 0;
-
- /**************************************************************************
- * LO Controls
- *************************************************************************/
- /*! Get a list of possible LO stage names
- *
- * \param chan the channel index 0 to N-1
- * \return a vector of strings for possible LO names
- */
- virtual std::vector<std::string> get_rx_lo_names(const size_t chan) const = 0;
-
- /*! Get a list of possible LO sources.
- *
- * Channels which do not have controllable LO sources
- * will return "internal".
- * \param name the name of the LO stage to query
- * \param chan the channel index 0 to N-1
- * \return a vector of strings for possible settings
- */
- virtual std::vector<std::string> get_rx_lo_sources(
- const std::string& name, const size_t chan) const = 0;
-
- /*!
- * Get the LO frequency range of the RX LO.
- * If the channel does not have independently configurable LOs
- * the rf frequency range will be returned.
- * \param name the name of the LO stage to query
- * \param chan the channel index 0 to N-1
- * \return a frequency range object
- */
- virtual freq_range_t get_rx_lo_freq_range(
- const std::string& name, const size_t chan) const = 0;
-
- /*!
- * Set the LO source for a channel.
- * For usrps that support selectable LOs, this function
- * allows switching between them.
- * Typical options for source: internal, external.
- * \param src a string representing the LO source
- * \param name the name of the LO stage to update
- * \param chan the channel index 0 to N-1
- */
- virtual void set_rx_lo_source(
- const std::string& src, const std::string& name, const size_t chan) = 0;
-
- /*!
- * Get the currently set LO source.
- * Channels without controllable LO sources will return
- * "internal"
- * \param name the name of the LO stage to query
- * \param chan the channel index 0 to N-1
- * \return the configured LO source
- */
- virtual const std::string get_rx_lo_source(
- const std::string& name, const size_t chan) = 0;
-
- /*!
- * Set whether the LO used by the usrp device is exported
- * For usrps that support exportable LOs, this function
- * configures if the LO used by chan is exported or not.
- * \param enabled if true then export the LO
- * \param name the name of the LO stage to update
- * \param chan the channel index 0 to N-1 for the source channel
- */
- virtual void set_rx_lo_export_enabled(
- bool enabled, const std::string& name, const size_t chan) = 0;
-
- /*!
- * Returns true if the currently selected LO is being exported.
- * \param name the name of the LO stage to query
- * \param chan the channel index 0 to N-1
- */
- virtual bool get_rx_lo_export_enabled(
- const std::string& name, const size_t chan) const = 0;
-
- /*!
- * Set the RX LO frequency (Advanced).
- * \param freq the frequency to set the LO to
- * \param name the name of the LO stage to update
- * \param chan the channel index 0 to N-1
- * \return a coerced LO frequency
- */
- virtual double set_rx_lo_freq(
- double freq, const std::string& name, const size_t chan) = 0;
-
- /*!
- * Get the current RX LO frequency (Advanced).
- * If the channel does not have independently configurable LOs
- * the current rf frequency will be returned.
- * \param name the name of the LO stage to query
- * \param chan the channel index 0 to N-1
- * \return the configured LO frequency
- */
- virtual double get_rx_lo_freq(const std::string& name, const size_t chan) = 0;
-
- /*! Get a list of possible LO stage names
- *
- * \param chan the channel index 0 to N-1
- * \return a vector of strings for possible LO names
- */
- virtual std::vector<std::string> get_tx_lo_names(const size_t chan) const = 0;
-
- /*! Get a list of possible LO sources.
- *
- * Channels which do not have controllable LO sources
- * will return "internal".
- * \param name the name of the LO stage to query
- * \param chan the channel index 0 to N-1
- * \return a vector of strings for possible settings
- */
- virtual std::vector<std::string> get_tx_lo_sources(
- const std::string& name, const size_t chan) = 0;
-
- /*!
- * Get the LO frequency range of the tx LO.
- * If the channel does not have independently configurable LOs
- * the rf frequency range will be returned.
- * \param name the name of the LO stage to query
- * \param chan the channel index 0 to N-1
- * \return a frequency range object
- */
- virtual freq_range_t get_tx_lo_freq_range(
- const std::string& name, const size_t chan) = 0;
-
- /*!
- * Set the LO source for a channel.
- * For usrps that support selectable LOs, this function
- * allows switching between them.
- * Typical options for source: internal, external.
- * \param src a string representing the LO source
- * \param name the name of the LO stage to update
- * \param chan the channel index 0 to N-1
- */
- virtual void set_tx_lo_source(
- const std::string& src, const std::string& name, const size_t chan) = 0;
-
- /*!
- * Get the currently set LO source.
- * Channels without controllable LO sources will return
- * "internal"
- * \param name the name of the LO stage to query
- * \param chan the channel index 0 to N-1
- * \return the configured LO source
- */
- virtual const std::string get_tx_lo_source(
- const std::string& name, const size_t chan) = 0;
-
- /*!
- * Set whether the LO used by the usrp device is exported
- * For usrps that support exportable LOs, this function
- * configures if the LO used by chan is exported or not.
- * \param enabled if true then export the LO
- * \param name the name of the LO stage to update
- * \param chan the channel index 0 to N-1 for the source channel
- */
- virtual void set_tx_lo_export_enabled(
- const bool enabled, const std::string& name, const size_t chan) = 0;
-
- /*!
- * Returns true if the currently selected LO is being exported.
- * \param name the name of the LO stage to query
- * \param chan the channel index 0 to N-1
- */
- virtual bool get_tx_lo_export_enabled(const std::string& name, const size_t chan) = 0;
-
- /*! Set the tx LO frequency (Advanced).
- *
- * See also multi_usrp::set_tx_lo_freq().
- *
- * \param freq the frequency to set the LO to
- * \param name the name of the LO stage to update
- * \param chan the channel index 0 to N-1
- * \return a coerced LO frequency
- */
- virtual double set_tx_lo_freq(
- const double freq, const std::string& name, const size_t chan) = 0;
-
- /*! Get the current TX LO frequency (Advanced).
- *
- * See also multi_usrp::get_tx_lo_freq()
- *
- * If the channel does not have independently configurable LOs
- * the current RF frequency will be returned.
- *
- * \param name the name of the LO stage to query
- * \param chan the channel index 0 to N-1
- * \return the configured LO frequency
- */
- virtual double get_tx_lo_freq(const std::string& name, const size_t chan) = 0;
-
/**************************************************************************
* Calibration-Related API Calls
*************************************************************************/
diff --git a/host/include/uhd/rfnoc/rf_control/CMakeLists.txt b/host/include/uhd/rfnoc/rf_control/CMakeLists.txt
new file mode 100644
index 000000000..02009ebd6
--- /dev/null
+++ b/host/include/uhd/rfnoc/rf_control/CMakeLists.txt
@@ -0,0 +1,13 @@
+#
+# Copyright 2020 Ettus Research, a National Instruments Brand
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+UHD_INSTALL(FILES
+ core_iface.hpp
+ power_reference_iface.hpp
+
+ DESTINATION ${INCLUDE_DIR}/uhd/rfnoc/rf_control
+ COMPONENT headers
+)
diff --git a/host/include/uhd/rfnoc/rf_control/core_iface.hpp b/host/include/uhd/rfnoc/rf_control/core_iface.hpp
new file mode 100644
index 000000000..9b780b3c8
--- /dev/null
+++ b/host/include/uhd/rfnoc/rf_control/core_iface.hpp
@@ -0,0 +1,448 @@
+//
+// Copyright 2020 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#pragma once
+
+#include <uhd/types/ranges.hpp>
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+namespace uhd { namespace rfnoc { namespace rf_control {
+
+/*! Interface for generic RF control functions
+ *
+ * This interface contains all methods related directly to RF control which
+ * aren't contained in a different rf_control class. These methods are not
+ * usually accessed via this interface, but are usually accessed via an
+ * instance of radio_control, which implements this class.
+ */
+class core_iface
+{
+public:
+ virtual ~core_iface() = default;
+
+ /*! Return the selected TX antenna for channel \p chan.
+ *
+ * \return The selected antenna.
+ */
+ virtual std::string get_tx_antenna(const size_t chan) const = 0;
+
+ /*! Return a list of valid TX antenna for channel \p chan.
+ *
+ * \return The selected antenna.
+ */
+ virtual std::vector<std::string> get_tx_antennas(const size_t chan) const = 0;
+
+ /*! Select RX antenna \p for channel \p chan.
+ *
+ * \throws uhd::value_error if \p ant is not a valid value.
+ */
+ virtual void set_tx_antenna(const std::string& ant, const size_t chan) = 0;
+
+ /*! Return the selected RX antenna for channel \p chan.
+ *
+ * \return The selected antenna.
+ */
+ virtual std::string get_rx_antenna(const size_t chan) const = 0;
+
+ /*! Return a list of valid RX antenna for channel \p chan.
+ *
+ * \return The selected antenna.
+ */
+ virtual std::vector<std::string> get_rx_antennas(const size_t chan) const = 0;
+
+ /*! Select RX antenna \p for channel \p chan.
+ *
+ * \throws uhd::value_error if \p ant is not a valid value.
+ */
+ virtual void set_rx_antenna(const std::string& ant, const size_t chan) = 0;
+
+ /*! Return the current transmit LO frequency on channel \p chan.
+ *
+ * \return The current LO frequency.
+ */
+ virtual double get_tx_frequency(const size_t chan) = 0;
+
+ /*! Tune the TX frequency for channel \p chan.
+ *
+ * This function will attempt to tune as close as possible, and return a
+ * coerced value of the actual tuning result.
+ *
+ * If there is a single LO in this radio, and we're doing direct conversion,
+ * then this is the LO frequency.
+ *
+ * \param freq Frequency in Hz
+ * \param chan Channel to tune
+ *
+ * \return The actual frequency.
+ */
+ virtual double set_tx_frequency(const double freq, size_t chan) = 0;
+
+ /*! Set the TX tune args, if supported by the hardware.
+ */
+ virtual void set_tx_tune_args(const uhd::device_addr_t& args, const size_t chan) = 0;
+
+ /*! Return the range of frequencies that \p chan can be tuned to.
+ *
+ * \return The range of frequencies that we can tune the TX chan to
+ */
+ virtual uhd::freq_range_t get_tx_frequency_range(const size_t chan) const = 0;
+
+ /*! Return the current receive LO frequency on channel \p chan.
+ *
+ * \return The current LO frequency.
+ */
+ virtual double get_rx_frequency(const size_t chan) = 0;
+
+ /*! Tune the RX frequency for channel \p chan.
+ *
+ * This function will attempt to tune as close as possible, and return a
+ * coerced value of the actual tuning result.
+ *
+ * If there is a single LO in this radio, and we're doing direct conversion,
+ * then this is the LO frequency.
+ *
+ * \param freq Requested frequency
+ * \param chan Channel number.
+ * \return The actual frequency.
+ */
+ virtual double set_rx_frequency(const double freq, const size_t chan) = 0;
+
+ /*! Set the TX tune args, if supported by the hardware.
+ */
+ virtual void set_rx_tune_args(const uhd::device_addr_t& args, const size_t chan) = 0;
+
+ /*! Return the range of frequencies that \p chan can be tuned to.
+ *
+ * \return The range of frequencies that we can tune the RX chan to
+ */
+ virtual uhd::freq_range_t get_rx_frequency_range(const size_t chan) const = 0;
+
+ /*! Return a list of valid TX gain names
+ */
+ virtual std::vector<std::string> get_tx_gain_names(const size_t chan) const = 0;
+
+ /*! Return a range of valid TX gains
+ */
+ virtual uhd::gain_range_t get_tx_gain_range(const size_t chan) const = 0;
+
+ /*! Return a range of valid TX gains
+ */
+ virtual uhd::gain_range_t get_tx_gain_range(
+ const std::string& name, const size_t chan) const = 0;
+
+ /*! Return the overall transmit gain on channel \p chan
+ *
+ * \return The actual gain value
+ */
+ virtual double get_tx_gain(const size_t chan) = 0;
+
+ /*! Return the transmit gain \p name on channel \p chan
+ *
+ * \return The actual gain value
+ */
+ virtual double get_tx_gain(const std::string& name, const size_t chan) = 0;
+
+ /*! Set the transmit gain on channel \p chan
+ *
+ * This function will attempt to set the gain as close as possible,
+ * and return a coerced value of the actual gain value.
+ *
+ * This method will set the overall gain. To set a specific gain, use
+ * set_tx_gain(const double, const std::string&, const size_t).
+ *
+ * \return The actual gain value
+ */
+ virtual double set_tx_gain(const double gain, const size_t chan) = 0;
+
+ /*! Set the transmit gain \p name on channel \p chan
+ *
+ * This function will attempt to set the gain as close as possible,
+ * and return a coerced value of the actual gain value.
+ *
+ * \return The actual gain value
+ */
+ virtual double set_tx_gain(
+ const double gain, const std::string& name, const size_t chan) = 0;
+
+ /*! Return a list of valid RX gain names
+ */
+ virtual std::vector<std::string> get_rx_gain_names(const size_t chan) const = 0;
+
+ /*! Return a range of valid RX gains
+ */
+ virtual uhd::gain_range_t get_rx_gain_range(const size_t chan) const = 0;
+
+ /*! Return a range of valid RX gains
+ */
+ virtual uhd::gain_range_t get_rx_gain_range(
+ const std::string& name, const size_t chan) const = 0;
+
+ /*! Return the overall receive gain on channel \p chan
+ *
+ * \return The actual gain value
+ */
+ virtual double get_rx_gain(const size_t chan) = 0;
+
+ /*! Return the receive gain \p name on channel \p chan
+ *
+ * \return The actual gain value
+ */
+ virtual double get_rx_gain(const std::string& name, const size_t chan) = 0;
+
+ /*! Set the overall receive gain on channel \p chan
+ *
+ * This function will attempt to set the gain as close as possible,
+ * and return a coerced value of the actual gain value.
+ *
+ * \return The actual gain value
+ */
+ virtual double set_rx_gain(const double gain, const size_t chan) = 0;
+
+ /*! Set the receive gain \p on channel \p chan
+ *
+ * This function will attempt to set the gain as close as possible,
+ * and return a coerced value of the actual gain value.
+ *
+ * \return The actual gain value
+ */
+ virtual double set_rx_gain(
+ const double gain, const std::string& name, const size_t chan) = 0;
+
+ /*! Enable RX AGC on this radio
+ *
+ * \throws uhd::not_implemented_error if this radio doesn't support RX AGC
+ */
+ virtual void set_rx_agc(const bool enable, const size_t chan) = 0;
+
+ /*! Return a range of valid TX bandwidths
+ */
+ virtual meta_range_t get_tx_bandwidth_range(size_t chan) const = 0;
+
+ /*! Return the analog filter bandwidth channel \p chan
+ *
+ * \return The actual bandwidth value
+ */
+ virtual double get_tx_bandwidth(const size_t chan) = 0;
+
+ /*! Set the analog filter bandwidth channel \p chan
+ *
+ * This function will attempt to set the analog bandwidth.
+ *
+ * \return The actual bandwidth value
+ */
+ virtual double set_tx_bandwidth(const double bandwidth, const size_t chan) = 0;
+
+ /*! Return a range of valid RX bandwidths
+ */
+ virtual meta_range_t get_rx_bandwidth_range(size_t chan) const = 0;
+
+ /*! Return the analog filter bandwidth channel \p chan
+ *
+ * \return The actual bandwidth value
+ */
+ virtual double get_rx_bandwidth(const size_t chan) = 0;
+
+ /*! Set the analog filter bandwidth channel \p chan
+ *
+ * This function will attempt to set the analog bandwidth.
+ *
+ * \return The actual bandwidth value
+ */
+ virtual double set_rx_bandwidth(const double bandwidth, const size_t chan) = 0;
+
+ /**************************************************************************
+ * LO Controls
+ *************************************************************************/
+ /*! Get a list of possible LO stage names
+ *
+ * \param chan the channel index 0 to N-1
+ * \return a vector of strings for possible LO names
+ */
+ virtual std::vector<std::string> get_rx_lo_names(const size_t chan) const = 0;
+
+ /*! Get a list of possible LO sources.
+ *
+ * Channels which do not have controllable LO sources
+ * will return "internal".
+ * \param name the name of the LO stage to query
+ * \param chan the channel index 0 to N-1
+ * \return a vector of strings for possible settings
+ */
+ virtual std::vector<std::string> get_rx_lo_sources(
+ const std::string& name, const size_t chan) const = 0;
+
+ /*!
+ * Get the LO frequency range of the RX LO.
+ * If the channel does not have independently configurable LOs
+ * the rf frequency range will be returned.
+ * \param name the name of the LO stage to query
+ * \param chan the channel index 0 to N-1
+ * \return a frequency range object
+ */
+ virtual freq_range_t get_rx_lo_freq_range(
+ const std::string& name, const size_t chan) const = 0;
+
+ /*!
+ * Set the LO source for a channel.
+ * For usrps that support selectable LOs, this function
+ * allows switching between them.
+ * Typical options for source: internal, external.
+ * \param src a string representing the LO source
+ * \param name the name of the LO stage to update
+ * \param chan the channel index 0 to N-1
+ */
+ virtual void set_rx_lo_source(
+ const std::string& src, const std::string& name, const size_t chan) = 0;
+
+ /*!
+ * Get the currently set LO source.
+ * Channels without controllable LO sources will return
+ * "internal"
+ * \param name the name of the LO stage to query
+ * \param chan the channel index 0 to N-1
+ * \return the configured LO source
+ */
+ virtual const std::string get_rx_lo_source(
+ const std::string& name, const size_t chan) = 0;
+
+ /*!
+ * Set whether the LO used by the usrp device is exported
+ * For usrps that support exportable LOs, this function
+ * configures if the LO used by chan is exported or not.
+ * \param enabled if true then export the LO
+ * \param name the name of the LO stage to update
+ * \param chan the channel index 0 to N-1 for the source channel
+ */
+ virtual void set_rx_lo_export_enabled(
+ bool enabled, const std::string& name, const size_t chan) = 0;
+
+ /*!
+ * Returns true if the currently selected LO is being exported.
+ * \param name the name of the LO stage to query
+ * \param chan the channel index 0 to N-1
+ */
+ virtual bool get_rx_lo_export_enabled(
+ const std::string& name, const size_t chan) const = 0;
+
+ /*!
+ * Set the RX LO frequency (Advanced).
+ * \param freq the frequency to set the LO to
+ * \param name the name of the LO stage to update
+ * \param chan the channel index 0 to N-1
+ * \return a coerced LO frequency
+ */
+ virtual double set_rx_lo_freq(
+ double freq, const std::string& name, const size_t chan) = 0;
+
+ /*!
+ * Get the current RX LO frequency (Advanced).
+ * If the channel does not have independently configurable LOs
+ * the current rf frequency will be returned.
+ * \param name the name of the LO stage to query
+ * \param chan the channel index 0 to N-1
+ * \return the configured LO frequency
+ */
+ virtual double get_rx_lo_freq(const std::string& name, const size_t chan) = 0;
+
+ /*! Get a list of possible LO stage names
+ *
+ * \param chan the channel index 0 to N-1
+ * \return a vector of strings for possible LO names
+ */
+ virtual std::vector<std::string> get_tx_lo_names(const size_t chan) const = 0;
+
+ /*! Get a list of possible LO sources.
+ *
+ * Channels which do not have controllable LO sources
+ * will return "internal".
+ * \param name the name of the LO stage to query
+ * \param chan the channel index 0 to N-1
+ * \return a vector of strings for possible settings
+ */
+ virtual std::vector<std::string> get_tx_lo_sources(
+ const std::string& name, const size_t chan) = 0;
+
+ /*!
+ * Get the LO frequency range of the tx LO.
+ * If the channel does not have independently configurable LOs
+ * the rf frequency range will be returned.
+ * \param name the name of the LO stage to query
+ * \param chan the channel index 0 to N-1
+ * \return a frequency range object
+ */
+ virtual freq_range_t get_tx_lo_freq_range(
+ const std::string& name, const size_t chan) = 0;
+
+ /*!
+ * Set the LO source for a channel.
+ * For usrps that support selectable LOs, this function
+ * allows switching between them.
+ * Typical options for source: internal, external.
+ * \param src a string representing the LO source
+ * \param name the name of the LO stage to update
+ * \param chan the channel index 0 to N-1
+ */
+ virtual void set_tx_lo_source(
+ const std::string& src, const std::string& name, const size_t chan) = 0;
+
+ /*!
+ * Get the currently set LO source.
+ * Channels without controllable LO sources will return
+ * "internal"
+ * \param name the name of the LO stage to query
+ * \param chan the channel index 0 to N-1
+ * \return the configured LO source
+ */
+ virtual const std::string get_tx_lo_source(
+ const std::string& name, const size_t chan) = 0;
+
+ /*!
+ * Set whether the LO used by the usrp device is exported
+ * For usrps that support exportable LOs, this function
+ * configures if the LO used by chan is exported or not.
+ * \param enabled if true then export the LO
+ * \param name the name of the LO stage to update
+ * \param chan the channel index 0 to N-1 for the source channel
+ */
+ virtual void set_tx_lo_export_enabled(
+ const bool enabled, const std::string& name, const size_t chan) = 0;
+
+ /*!
+ * Returns true if the currently selected LO is being exported.
+ * \param name the name of the LO stage to query
+ * \param chan the channel index 0 to N-1
+ */
+ virtual bool get_tx_lo_export_enabled(const std::string& name, const size_t chan) = 0;
+
+ /*! Set the tx LO frequency (Advanced).
+ *
+ * See also multi_usrp::set_tx_lo_freq().
+ *
+ * \param freq the frequency to set the LO to
+ * \param name the name of the LO stage to update
+ * \param chan the channel index 0 to N-1
+ * \return a coerced LO frequency
+ */
+ virtual double set_tx_lo_freq(
+ const double freq, const std::string& name, const size_t chan) = 0;
+
+ /*! Get the current TX LO frequency (Advanced).
+ *
+ * See also multi_usrp::get_tx_lo_freq()
+ *
+ * If the channel does not have independently configurable LOs
+ * the current RF frequency will be returned.
+ *
+ * \param name the name of the LO stage to query
+ * \param chan the channel index 0 to N-1
+ * \return the configured LO frequency
+ */
+ virtual double get_tx_lo_freq(const std::string& name, const size_t chan) = 0;
+};
+
+}}} // namespace uhd::rfnoc::rf_control
diff --git a/host/include/uhd/rfnoc/rf_control/power_reference_iface.hpp b/host/include/uhd/rfnoc/rf_control/power_reference_iface.hpp
new file mode 100644
index 000000000..84f0a1805
--- /dev/null
+++ b/host/include/uhd/rfnoc/rf_control/power_reference_iface.hpp
@@ -0,0 +1,191 @@
+//
+// Copyright 2020 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#pragma once
+
+#include <uhd/types/direction.hpp>
+#include <uhd/types/ranges.hpp>
+#include <uhd/utils/assert_has.hpp>
+#include <string>
+#include <vector>
+
+namespace uhd { namespace rfnoc { namespace rf_control {
+
+/*! Interface for reference power API commands
+ *
+ * This interface contains all methods related to the reference power API,
+ * and is usually only accessed directly via the radio_control class.
+ */
+class power_reference_iface
+{
+public:
+ virtual ~power_reference_iface() = default;
+
+ /*! Return true if this channel has a reference power API enabled
+ *
+ * Many devices either don't have a built-in reference power API, or they
+ * require calibration data for it to work. This means that it is not clear,
+ * even when the device type is known, if a device supports setting a power
+ * reference level. Use this method to query the availability of
+ * set_rx_power_reference() and get_rx_power_reference(), which will throw
+ * a uhd::not_implemented_error or uhd::runtime_error if they cannot be used.
+ *
+ * See \ref page_power for more information, or query the specific device's
+ * manual page to see if a power API is available, and how to enable it.
+ *
+ * \param chan The channel for which this feature is queried
+ *
+ * \returns true if this channel has an RX power API available
+ */
+ virtual bool has_rx_power_reference(const size_t chan = 0) = 0;
+
+ /*! Set the reference RX power level for a given channel
+ *
+ * Note: This functionality is not supported for most devices, and will
+ * cause a uhd::not_implemented_error exception to be thrown on devices that
+ * do not have this functionality.
+ *
+ * For more information on how to use this API, see \ref page_power.
+ *
+ * \param power_dbm The reference power level in dBm
+ * \param chan The channel for which this setting applies
+ *
+ * \throws uhd::not_implemented_error if this functionality does not exist
+ * for this device
+ */
+ virtual void set_rx_power_reference(
+ const double power_dbm, const size_t chan = 0) = 0;
+
+ /*! Return the actual reference RX power level.
+ *
+ * Note: This functionality is not supported for most devices, and will
+ * cause a uhd::not_implemented_error exception to be thrown on devices that
+ * do not have this functionality.
+ *
+ * For more information on how to use this API, see \ref page_power.
+ *
+ * \param chan The channel for which this setting is queried
+ * \throws uhd::not_implemented_error if this functionality does not exist
+ * for this device
+ */
+ virtual double get_rx_power_reference(const size_t chan = 0) = 0;
+
+ /*! Return the keys by which the power calibration data is referenced for this
+ * channel.
+ *
+ * The first entry is the key, the second the serial. These are the same
+ * arguments that can be used for uhd::usrp::cal::database::read_cal_data()
+ * and friends. See also \ref cal_db_serial.
+ *
+ * Note that the key can change at runtime, e.g., when the antenna port is
+ * switched.
+ *
+ * The difference between this and has_rx_power_reference() is that the
+ * latter requires both device support as well as calibration data, whereas
+ * this function will never throw, and will always return a non-empty vector
+ * if device support is there, even if the device does not have calbration
+ * data loaded.
+ *
+ * \returns an empty vector if no power calibration is supported, or a
+ * vector of length 2 with key and serial if it does.
+ */
+ virtual std::vector<std::string> get_rx_power_ref_keys(const size_t chan = 0) = 0;
+
+ /*! Return the available RX power range given the current configuration
+ *
+ * This will return the range of available power levels given the current
+ * frequency, gain profile, antenna, and whatever other settings may affect
+ * the available power ranges. Note that the available power range may
+ * change frequently, so don't assume an immutable range.
+ *
+ * \param chan The channel index
+ */
+ virtual meta_range_t get_rx_power_range(const size_t chan) = 0;
+
+ /*! Return true if this channel has a reference power API enabled
+ *
+ * Many devices either don't have a built-in reference power API, or they
+ * require calibration data for it to work. This means that it is not clear,
+ * even when the device type is known, if a device supports setting a power
+ * reference level. Use this method to query the availability of
+ * set_tx_power_reference() and get_tx_power_reference(), which will throw
+ * a uhd::not_implemented_error or uhd::runtime_error if they cannot be used.
+ *
+ * See \ref page_power for more information, or query the specific device's
+ * manual page to see if a power API is available, and how to enable it.
+ *
+ * \param chan The channel for which this feature is queried
+ *
+ * \returns true if this channel has a TX power API available
+ */
+ virtual bool has_tx_power_reference(const size_t chan = 0) = 0;
+
+ /*! Set the reference TX power level for a given channel
+ *
+ * Note: This functionality is not supported for most devices, and will
+ * cause a uhd::not_implemented_error exception to be thrown on devices that
+ * do not have this functionality.
+ *
+ * For more information on how to use this API, see \ref page_power.
+ *
+ * \param power_dbm The reference power level in dBm
+ * \param chan The channel for which this setting applies
+ *
+ * \throws uhd::not_implemented_error if this functionality does not exist
+ * for this device
+ */
+ virtual void set_tx_power_reference(
+ const double power_dbm, const size_t chan = 0) = 0;
+
+ /*! Return the actual reference TX power level.
+ *
+ * Note: This functionality is not supported for most devices, and will
+ * cause a uhd::not_implemented_error exception to be thrown on devices that
+ * do not have this functionality.
+ *
+ * For more information on how to use this API, see \ref page_power.
+ *
+ * \param chan The channel for which this setting is queried
+ * \throws uhd::not_implemented_error if this functionality does not exist
+ * for this device
+ */
+ virtual double get_tx_power_reference(const size_t chan = 0) = 0;
+
+ /*! Return the keys by which the power calibration data is referenced for this
+ * channel.
+ *
+ * The first entry is the key, the second the serial. These are the same
+ * arguments that can be used for uhd::usrp::cal::database::read_cal_data()
+ * and friends. See also \ref cal_db_serial.
+ *
+ * Note that the key can change at runtime, e.g., when the antenna port is
+ * switched.
+ *
+ * The difference between this and has_tx_power_reference() is that the
+ * latter requires both device support as well as calibration data, whereas
+ * this function will never throw, and will always return a non-empty vector
+ * if device support is there, even if the device does not have calbration
+ * data loaded.
+ *
+ * \returns an empty vector if no power calibration is supported, or a
+ * vector of length 2 with key and serial if it does.
+ */
+ virtual std::vector<std::string> get_tx_power_ref_keys(const size_t chan = 0) = 0;
+
+ /*! Return the available TX power range given the current configuration
+ *
+ * This will return the range of available power levels given the current
+ * frequency, gain profile, antenna, and whatever other settings may affect
+ * the available power ranges. Note that the available power range may
+ * change frequently, so don't assume an immutable range.
+ *
+ * \param chan The channel index
+ */
+ virtual meta_range_t get_tx_power_range(const size_t chan) = 0;
+
+};
+
+}}} // namespace uhd::rfnoc::rf_control
diff --git a/host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp b/host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp
index f60319d32..2a93fbfa5 100644
--- a/host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp
+++ b/host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp
@@ -11,6 +11,8 @@
#include <uhd/rfnoc/radio_control.hpp>
#include <uhdlib/features/discoverable_feature_registry.hpp>
#include <uhdlib/usrp/common/pwr_cal_mgr.hpp>
+#include <uhd/rfnoc/rf_control/core_iface.hpp>
+#include <uhdlib/rfnoc/rf_control/gain_profile_iface.hpp>
#include <unordered_map>
#include <mutex>
@@ -322,6 +324,9 @@ protected:
// simply leave these empty.
std::vector<uhd::usrp::pwr_cal_mgr::sptr> _tx_pwr_mgr;
+ rf_control::gain_profile_iface::sptr _tx_gain_profile_api;
+ rf_control::gain_profile_iface::sptr _rx_gain_profile_api;
+
private:
//! Validator for the async messages
//
diff --git a/host/lib/include/uhdlib/rfnoc/rf_control/dboard_iface.hpp b/host/lib/include/uhdlib/rfnoc/rf_control/dboard_iface.hpp
new file mode 100644
index 000000000..1651a1580
--- /dev/null
+++ b/host/lib/include/uhdlib/rfnoc/rf_control/dboard_iface.hpp
@@ -0,0 +1,41 @@
+//
+// Copyright 2020 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#pragma once
+
+#include <uhd/rfnoc/rf_control/core_iface.hpp>
+#include <uhdlib/rfnoc/rf_control/gain_profile_iface.hpp>
+#include <uhdlib/usrp/common/pwr_cal_mgr.hpp>
+#include <memory>
+
+namespace uhd { namespace rfnoc { namespace rf_control {
+
+/*! Interface that daughterboards expose to the motherboard radio_control
+ *
+ * This interface contains everything required for a daughterboard to implement
+ * all the methods required for radio_control. For the most part, this class
+ * just includes accessors to objects which implement the required functionality.
+ * This class also directly implements core_iface for the remainder.
+ */
+class dboard_iface : public core_iface
+{
+public:
+ using sptr = std::shared_ptr<dboard_iface>;
+
+ virtual ~dboard_iface() = default;
+
+ virtual gain_profile_iface::sptr get_tx_gain_profile_api() = 0;
+ virtual gain_profile_iface::sptr get_rx_gain_profile_api() = 0;
+
+ virtual size_t get_chan_from_dboard_fe(
+ const std::string&, uhd::direction_t) const = 0;
+ virtual std::string get_dboard_fe_from_chan(size_t chan, uhd::direction_t) const = 0;
+
+ virtual std::vector<uhd::usrp::pwr_cal_mgr::sptr>& get_pwr_mgr(
+ uhd::direction_t trx) = 0;
+};
+
+}}} // namespace uhd::rfnoc::rf_control
diff --git a/host/lib/include/uhdlib/rfnoc/rf_control/gain_profile_iface.hpp b/host/lib/include/uhdlib/rfnoc/rf_control/gain_profile_iface.hpp
new file mode 100644
index 000000000..f93a42936
--- /dev/null
+++ b/host/lib/include/uhdlib/rfnoc/rf_control/gain_profile_iface.hpp
@@ -0,0 +1,86 @@
+//
+// Copyright 2020 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#pragma once
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace uhd { namespace rfnoc { namespace rf_control {
+
+/*! Interface for gain profile API commands
+ *
+ * This interface contains methods to configure the current gain profile of the
+ * device. Note that this interface is RX/TX agnostic, it does not provide
+ * specialized methods for RX and TX.
+ */
+class gain_profile_iface
+{
+public:
+ using sptr = std::shared_ptr<gain_profile_iface>;
+
+ virtual ~gain_profile_iface() = default;
+
+ /*! Return a list of TX gain profiles for this radio
+ */
+ virtual std::vector<std::string> get_gain_profile_names(const size_t chan) const = 0;
+
+ /*! Set the gain profile
+ */
+ virtual void set_gain_profile(const std::string& profile, const size_t chan) = 0;
+
+ /*! Return the gain profile
+ */
+ virtual std::string get_gain_profile(const size_t chan) const = 0;
+};
+
+/*! "Default" implementation for gain_profile_iface
+ *
+ * This class implements gain_profile_iface such that the device is always
+ * and can only be configured using a single "default" gain profile. Setting
+ * a gain profile which is not the default profile is an error, and getting the
+ * gain profile will always return the default profile.
+ */
+class default_gain_profile : public gain_profile_iface
+{
+public:
+ std::vector<std::string> get_gain_profile_names(const size_t chan) const override;
+
+ void set_gain_profile(const std::string& profile, const size_t chan) override;
+ std::string get_gain_profile(const size_t chan) const override;
+
+private:
+ static const std::string DEFAULT_GAIN_PROFILE;
+};
+
+/*! "Enumerated" implementation for gain_profile_iface
+ *
+ * This class implements gain_profile_iface so that the gain profile can only be
+ * one of several different enumerated values. Setting an invalid gain profile
+ * is an error. Retrieving a gain profile will always return one of the
+ * enumerated gain profiles.
+ */
+class enumerated_gain_profile : public gain_profile_iface
+{
+public:
+ enumerated_gain_profile(const std::vector<std::string>& possible_profiles,
+ const std::string& default_profile,
+ size_t num_channels);
+
+ void set_gain_profile(const std::string& profile, const size_t chan) override;
+
+ std::string get_gain_profile(const size_t chan) const override;
+
+ std::vector<std::string> get_gain_profile_names(const size_t) const override;
+
+private:
+ std::vector<std::string> _possible_profiles;
+
+ std::vector<std::string> _gain_profile;
+};
+
+}}} // namespace uhd::rfnoc::rf_control
diff --git a/host/lib/rfnoc/CMakeLists.txt b/host/lib/rfnoc/CMakeLists.txt
index 33da287fe..53bca9b45 100644
--- a/host/lib/rfnoc/CMakeLists.txt
+++ b/host/lib/rfnoc/CMakeLists.txt
@@ -61,3 +61,4 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/window_block_control.cpp
)
+INCLUDE_SUBDIRECTORY(rf_control)
diff --git a/host/lib/rfnoc/radio_control_impl.cpp b/host/lib/rfnoc/radio_control_impl.cpp
index f9347b9e7..e20f5d4f6 100644
--- a/host/lib/rfnoc/radio_control_impl.cpp
+++ b/host/lib/rfnoc/radio_control_impl.cpp
@@ -253,6 +253,10 @@ radio_control_impl::radio_control_impl(make_args_ptr make_args)
boost::optional<uint64_t> timestamp) {
this->async_message_handler(addr, data, timestamp);
});
+
+ // Set the default gain profiles
+ _rx_gain_profile_api = std::make_shared<rf_control::default_gain_profile>();
+ _tx_gain_profile_api = std::make_shared<rf_control::default_gain_profile>();
} /* ctor */
/******************************************************************************
@@ -436,42 +440,34 @@ void radio_control_impl::set_rx_agc(const bool, const size_t)
throw uhd::not_implemented_error("set_rx_agc() is not supported on this radio!");
}
-void radio_control_impl::set_tx_gain_profile(const std::string& profile, const size_t)
+void radio_control_impl::set_tx_gain_profile(const std::string& profile, const size_t chan)
{
- if (profile != DEFAULT_GAIN_PROFILE) {
- throw uhd::value_error(
- std::string("set_tx_gain_profile(): Unknown gain profile: `") + profile
- + "'");
- }
+ _tx_gain_profile_api->set_gain_profile(profile, chan);
}
-void radio_control_impl::set_rx_gain_profile(const std::string& profile, const size_t)
+void radio_control_impl::set_rx_gain_profile(const std::string& profile, const size_t chan)
{
- if (profile != DEFAULT_GAIN_PROFILE) {
- throw uhd::value_error(
- std::string("set_rx_gain_profile(): Unknown gain profile: `") + profile
- + "'");
- }
+ _rx_gain_profile_api->set_gain_profile(profile, chan);
}
-std::vector<std::string> radio_control_impl::get_tx_gain_profile_names(const size_t) const
+std::vector<std::string> radio_control_impl::get_tx_gain_profile_names(const size_t chan) const
{
- return {DEFAULT_GAIN_PROFILE};
+ return _tx_gain_profile_api->get_gain_profile_names(chan);
}
-std::vector<std::string> radio_control_impl::get_rx_gain_profile_names(const size_t) const
+std::vector<std::string> radio_control_impl::get_rx_gain_profile_names(const size_t chan) const
{
- return {DEFAULT_GAIN_PROFILE};
+ return _rx_gain_profile_api->get_gain_profile_names(chan);
}
-std::string radio_control_impl::get_tx_gain_profile(const size_t) const
+std::string radio_control_impl::get_tx_gain_profile(const size_t chan) const
{
- return DEFAULT_GAIN_PROFILE;
+ return _tx_gain_profile_api->get_gain_profile(chan);
}
-std::string radio_control_impl::get_rx_gain_profile(const size_t) const
+std::string radio_control_impl::get_rx_gain_profile(const size_t chan) const
{
- return DEFAULT_GAIN_PROFILE;
+ return _rx_gain_profile_api->get_gain_profile(chan);
}
double radio_control_impl::set_tx_bandwidth(const double bandwidth, const size_t chan)
diff --git a/host/lib/rfnoc/rf_control/CMakeLists.txt b/host/lib/rfnoc/rf_control/CMakeLists.txt
new file mode 100644
index 000000000..11c7e57ef
--- /dev/null
+++ b/host/lib/rfnoc/rf_control/CMakeLists.txt
@@ -0,0 +1,13 @@
+#
+# Copyright 2020 Ettus Research, a National Instruments Brand
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+########################################################################
+# This file included, use CMake directory variables
+########################################################################
+
+LIBUHD_APPEND_SOURCES(
+ ${CMAKE_CURRENT_SOURCE_DIR}/gain_profile.cpp
+)
diff --git a/host/lib/rfnoc/rf_control/gain_profile.cpp b/host/lib/rfnoc/rf_control/gain_profile.cpp
new file mode 100644
index 000000000..54ccb9006
--- /dev/null
+++ b/host/lib/rfnoc/rf_control/gain_profile.cpp
@@ -0,0 +1,68 @@
+//
+// Copyright 2020 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#include <uhd/exception.hpp>
+#include <uhd/utils/assert_has.hpp>
+#include <uhd/utils/log.hpp>
+#include <uhdlib/rfnoc/rf_control/gain_profile_iface.hpp>
+#include <stddef.h>
+#include <string>
+#include <vector>
+
+namespace uhd { namespace rfnoc { namespace rf_control {
+
+const std::string default_gain_profile::DEFAULT_GAIN_PROFILE = "default";
+
+std::vector<std::string> default_gain_profile::get_gain_profile_names(const size_t) const
+{
+ return {DEFAULT_GAIN_PROFILE};
+}
+
+void default_gain_profile::set_gain_profile(const std::string& profile, const size_t)
+{
+ if (profile != DEFAULT_GAIN_PROFILE) {
+ throw uhd::value_error(
+ std::string("set_tx_gain_profile(): Unknown gain profile: `") + profile
+ + "'");
+ }
+}
+
+std::string default_gain_profile::get_gain_profile(const size_t) const
+{
+ return DEFAULT_GAIN_PROFILE;
+}
+
+enumerated_gain_profile::enumerated_gain_profile(
+ const std::vector<std::string>& possible_profiles,
+ const std::string& default_profile,
+ size_t num_channels)
+ : _possible_profiles(possible_profiles), _gain_profile(num_channels, default_profile)
+{
+}
+
+void enumerated_gain_profile::set_gain_profile(
+ const std::string& profile, const size_t chan)
+{
+ if (!uhd::has(_possible_profiles, profile)) {
+ const std::string err_msg = ("Invalid gain profile provided: " + profile);
+ UHD_LOG_ERROR("gain_profile", err_msg);
+ throw uhd::key_error(err_msg);
+ }
+ _gain_profile.at(chan) = profile;
+}
+
+std::string enumerated_gain_profile::get_gain_profile(const size_t chan) const
+{
+ return _gain_profile.at(chan);
+}
+
+std::vector<std::string> enumerated_gain_profile::get_gain_profile_names(
+ const size_t) const
+{
+ return _possible_profiles;
+}
+
+}}} // namespace uhd::rfnoc::rf_control
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_control.cpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_control.cpp
index 5eb0f63a5..879885640 100644
--- a/host/lib/usrp/dboard/magnesium/magnesium_radio_control.cpp
+++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_control.cpp
@@ -103,6 +103,10 @@ magnesium_radio_control_impl::magnesium_radio_control_impl(make_args_ptr make_ar
{
RFNOC_LOG_TRACE("Entering magnesium_radio_control_impl ctor...");
UHD_ASSERT_THROW(get_block_id().get_block_count() < 2);
+
+ _tx_gain_profile_api = std::make_shared<rf_control::enumerated_gain_profile>(MAGNESIUM_GP_OPTIONS, "default", MAGNESIUM_NUM_CHANS);
+ _rx_gain_profile_api = std::make_shared<rf_control::enumerated_gain_profile>(MAGNESIUM_GP_OPTIONS, "default", MAGNESIUM_NUM_CHANS);
+
const char radio_slot_name[2] = {'A', 'B'};
_radio_slot = radio_slot_name[get_block_id().get_block_count()];
RFNOC_LOG_TRACE("Radio slot: " << _radio_slot);
@@ -363,28 +367,6 @@ double magnesium_radio_control_impl::set_tx_bandwidth(
return AD9371_TX_MAX_BANDWIDTH;
}
-void magnesium_radio_control_impl::set_tx_gain_profile(
- const std::string& profile, const size_t)
-{
- if (std::find(MAGNESIUM_GP_OPTIONS.begin(), MAGNESIUM_GP_OPTIONS.end(), profile)
- == MAGNESIUM_GP_OPTIONS.end()) {
- RFNOC_LOG_ERROR("Invalid TX gain profile: " << profile);
- throw uhd::key_error("Invalid TX gain profile!");
- }
- _gain_profile[TX_DIRECTION] = profile;
-}
-
-void magnesium_radio_control_impl::set_rx_gain_profile(
- const std::string& profile, const size_t)
-{
- if (std::find(MAGNESIUM_GP_OPTIONS.begin(), MAGNESIUM_GP_OPTIONS.end(), profile)
- == MAGNESIUM_GP_OPTIONS.end()) {
- RFNOC_LOG_ERROR("Invalid RX gain profile: " << profile);
- throw uhd::key_error("Invalid RX gain profile!");
- }
- _gain_profile[RX_DIRECTION] = profile;
-}
-
double magnesium_radio_control_impl::set_tx_gain(const double gain, const size_t chan)
{
std::lock_guard<std::recursive_mutex> l(_set_lock);
@@ -716,28 +698,6 @@ uhd::gain_range_t magnesium_radio_control_impl::get_rx_gain_range(
throw uhd::key_error("Invalid RX gain name!");
}
-std::vector<std::string> magnesium_radio_control_impl::get_tx_gain_profile_names(
- const size_t) const
-{
- return MAGNESIUM_GP_OPTIONS;
-}
-
-std::vector<std::string> magnesium_radio_control_impl::get_rx_gain_profile_names(
- const size_t) const
-{
- return MAGNESIUM_GP_OPTIONS;
-}
-
-std::string magnesium_radio_control_impl::get_tx_gain_profile(const size_t) const
-{
- return _gain_profile.at(TX_DIRECTION);
-}
-
-std::string magnesium_radio_control_impl::get_rx_gain_profile(const size_t) const
-{
- return _gain_profile.at(RX_DIRECTION);
-}
-
meta_range_t magnesium_radio_control_impl::get_tx_bandwidth_range(size_t) const
{
return meta_range_t(AD9371_TX_MIN_BANDWIDTH, AD9371_TX_MAX_BANDWIDTH);
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_control.hpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_control.hpp
index fc8c79b5a..e8c252605 100644
--- a/host/lib/usrp/dboard/magnesium/magnesium_radio_control.hpp
+++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_control.hpp
@@ -87,8 +87,6 @@ public:
double set_rx_gain(const double gain, const std::string& name, const size_t chan);
double set_tx_bandwidth(const double bandwidth, const size_t chan);
double set_rx_bandwidth(const double bandwidth, const size_t chan);
- void set_tx_gain_profile(const std::string& profile, const size_t chan);
- void set_rx_gain_profile(const std::string& profile, const size_t chan);
// Getters
std::vector<std::string> get_tx_antennas(const size_t chan) const;
@@ -103,10 +101,6 @@ public:
uhd::gain_range_t get_tx_gain_range(const std::string&, const size_t) const;
uhd::gain_range_t get_rx_gain_range(const size_t) const;
uhd::gain_range_t get_rx_gain_range(const std::string&, const size_t) const;
- std::vector<std::string> get_tx_gain_profile_names(const size_t chan) const;
- std::vector<std::string> get_rx_gain_profile_names(const size_t chan) const;
- std::string get_tx_gain_profile(const size_t chan) const;
- std::string get_rx_gain_profile(const size_t chan) const;
uhd::meta_range_t get_tx_bandwidth_range(size_t chan) const;
uhd::meta_range_t get_rx_bandwidth_range(size_t chan) const;
@@ -351,9 +345,6 @@ private:
//! All gain
double _all_rx_gain = 0.0;
double _all_tx_gain = 0.0;
- //! Gain profile
- std::map<direction_t, std::string> _gain_profile = {
- {RX_DIRECTION, "default"}, {TX_DIRECTION, "default"}};
bool _rx_bypass_lnas = true;
bool _tx_bypass_amp = true;
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_control_gain.cpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_control_gain.cpp
index b06222205..72d8d564c 100644
--- a/host/lib/usrp/dboard/magnesium/magnesium_radio_control_gain.cpp
+++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_control_gain.cpp
@@ -31,7 +31,7 @@ double magnesium_radio_control_impl::_set_all_gain(
const size_t ad9371_chan = chan;
auto chan_sel = static_cast<magnesium_cpld_ctrl::chan_sel_t>(chan);
gain_tuple_t gain_tuple;
- std::string gp = _gain_profile[dir];
+ std::string gp = dir == RX_DIRECTION ? get_rx_gain_profile(0) : get_tx_gain_profile(0);
RFNOC_LOG_TRACE("Gain profile: " << gp);
if (gp == "manual") {
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_control_init.cpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_control_init.cpp
index d9bf5c3d2..82da7ec75 100644
--- a/host/lib/usrp/dboard/magnesium/magnesium_radio_control_init.cpp
+++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_control_init.cpp
@@ -51,13 +51,13 @@ void magnesium_radio_control_impl::_init_defaults()
if (block_args.has_key("tx_gain_profile")) {
RFNOC_LOG_INFO("Using user specified TX gain profile: " << block_args.get(
"tx_gain_profile"));
- _gain_profile[TX_DIRECTION] = block_args.get("tx_gain_profile");
+ set_tx_gain_profile(block_args.get("tx_gain_profile"), 0);
}
if (block_args.has_key("rx_gain_profile")) {
RFNOC_LOG_INFO("Using user specified RX gain profile: " << block_args.get(
"rx_gain_profile"));
- _gain_profile[RX_DIRECTION] = block_args.get("rx_gain_profile");
+ set_rx_gain_profile(block_args.get("rx_gain_profile"), 0);
}
if (block_args.has_key("rx_band_map")) {
diff --git a/host/tests/CMakeLists.txt b/host/tests/CMakeLists.txt
index e2d192796..980f87d75 100644
--- a/host/tests/CMakeLists.txt
+++ b/host/tests/CMakeLists.txt
@@ -376,6 +376,12 @@ UHD_ADD_NONAPI_TEST(
${CMAKE_SOURCE_DIR}/lib/features/discoverable_feature_registry.cpp
)
+UHD_ADD_NONAPI_TEST(
+ TARGET "rf_control_gain_profile_test.cpp"
+ EXTRA_SOURCES
+ ${CMAKE_SOURCE_DIR}/lib/rfnoc/rf_control/gain_profile.cpp
+)
+
########################################################################
# demo of a loadable module
########################################################################
diff --git a/host/tests/rf_control_gain_profile_test.cpp b/host/tests/rf_control_gain_profile_test.cpp
new file mode 100644
index 000000000..d68f4b378
--- /dev/null
+++ b/host/tests/rf_control_gain_profile_test.cpp
@@ -0,0 +1,40 @@
+//
+// Copyright 2020 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#include <uhdlib/rfnoc/rf_control/gain_profile_iface.hpp>
+#include <uhd/types/ranges.hpp>
+#include <boost/test/unit_test.hpp>
+#include <iostream>
+
+using namespace uhd::rfnoc::rf_control;
+
+static const double tolerance = 0.001; // %
+
+void test_profile_invariant(gain_profile_iface& gain_profile)
+{
+ BOOST_CHECK(gain_profile.get_gain_profile_names(0).size() > 0);
+ for (auto& profile : gain_profile.get_gain_profile_names(0))
+ {
+ gain_profile.set_gain_profile(profile, 0);
+ BOOST_CHECK(gain_profile.get_gain_profile(0) == profile);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_default_profile_get_set)
+{
+ default_gain_profile gain_profile;
+ test_profile_invariant(gain_profile);
+}
+
+BOOST_AUTO_TEST_CASE(test_enumerated_profile_get_set)
+{
+ enumerated_gain_profile gain_profile(
+ {"ProfileA", "ProfileB", "ProfileC", "ProfileD"},
+ "ProfileD",
+ 1
+ );
+ test_profile_invariant(gain_profile);
+}