diff options
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); +} |