// // Copyright 2018 Ettus Research, a National Instruments Company // Copyright 2019 Ettus Research, a National Instruments Brand // // SPDX-License-Identifier: GPL-3.0-or-later // #ifndef INCLUDED_LIBUHD_RFNOC_RHODIUM_RADIO_CTRL_IMPL_HPP #define INCLUDED_LIBUHD_RFNOC_RHODIUM_RADIO_CTRL_IMPL_HPP #include "rhodium_constants.hpp" #include "rhodium_cpld_ctrl.hpp" #include "rhodium_cpld_regs.hpp" #include #include #include #include #include #include #include #include #include #include namespace uhd { namespace rfnoc { /*! \brief Provide access to an Rhodium radio. */ class rhodium_radio_control_impl : public radio_control_impl { public: typedef std::shared_ptr sptr; //! Frequency bands for RX. Bands are a function of the analog filter banks enum class rx_band { RX_BAND_INVALID, RX_BAND_0, RX_BAND_1, RX_BAND_2, RX_BAND_3, RX_BAND_4, RX_BAND_5, RX_BAND_6, RX_BAND_7 }; //! Frequency bands for TX. Bands are a function of the analog filter banks enum class tx_band { TX_BAND_INVALID, TX_BAND_0, TX_BAND_1, TX_BAND_2, TX_BAND_3, TX_BAND_4, TX_BAND_5, TX_BAND_6, TX_BAND_7 }; /************************************************************************ * Structors ***********************************************************************/ rhodium_radio_control_impl(make_args_ptr make_args); ~rhodium_radio_control_impl() override; /************************************************************************ * RF API calls ***********************************************************************/ // Note: We use the cached values in radio_ctrl_impl, so most getters are // not reimplemented here double set_rate(double rate) override; // Setters void set_tx_antenna(const std::string& ant, const size_t chan) override; void set_rx_antenna(const std::string& ant, const size_t chan) override; double set_tx_frequency(const double freq, const size_t chan) override; double set_rx_frequency(const double freq, const size_t chan) override; void set_tx_tune_args(const uhd::device_addr_t&, const size_t chan) override; void set_rx_tune_args(const uhd::device_addr_t&, const size_t chan) override; double set_tx_gain(const double gain, const size_t chan) override; double set_rx_gain(const double gain, const size_t chan) override; // Getters std::vector get_tx_antennas(const size_t) const override; std::vector get_rx_antennas(const size_t) const override; uhd::freq_range_t get_tx_frequency_range(const size_t) const override; uhd::freq_range_t get_rx_frequency_range(const size_t) const override; uhd::gain_range_t get_tx_gain_range(const size_t) const override; uhd::gain_range_t get_rx_gain_range(const size_t) const override; uhd::meta_range_t get_tx_bandwidth_range(size_t) const override; uhd::meta_range_t get_rx_bandwidth_range(size_t) const override; /************************************************************************** * LO Controls *************************************************************************/ std::vector get_rx_lo_names(const size_t chan) const override; std::vector get_rx_lo_sources( const std::string& name, const size_t chan) const override; freq_range_t get_rx_lo_freq_range( const std::string& name, const size_t chan) const override; void set_rx_lo_source( const std::string& src, const std::string& name, const size_t chan) override; const std::string get_rx_lo_source( const std::string& name, const size_t chan) override; double set_rx_lo_freq( double freq, const std::string& name, const size_t chan) override; double get_rx_lo_freq(const std::string& name, const size_t chan) override; std::vector get_tx_lo_names(const size_t chan) const override; std::vector get_tx_lo_sources( const std::string& name, const size_t chan) const override; freq_range_t get_tx_lo_freq_range( const std::string& name, const size_t chan) override; void set_tx_lo_source( const std::string& src, const std::string& name, const size_t chan) override; const std::string get_tx_lo_source( const std::string& name, const size_t chan) override; double set_tx_lo_freq( const double freq, const std::string& name, const size_t chan) override; double get_tx_lo_freq(const std::string& name, const size_t chan) override; // LO Export Control void set_tx_lo_export_enabled( const bool enabled, const std::string& name, const size_t chan) override; void set_rx_lo_export_enabled( const bool enabled, const std::string& name, const size_t chan) override; bool get_tx_lo_export_enabled(const std::string& name, const size_t chan) override; bool get_rx_lo_export_enabled(const std::string& name, const size_t chan) override; /************************************************************************** * GPIO Controls *************************************************************************/ std::vector get_gpio_banks() const override; void set_gpio_attr( const std::string& bank, const std::string& attr, const uint32_t value) override; uint32_t get_gpio_attr(const std::string& bank, const std::string& attr) override; /************************************************************************** * EEPROM API *************************************************************************/ void set_db_eeprom(const uhd::eeprom_map_t& db_eeprom) override; uhd::eeprom_map_t get_db_eeprom() override; /************************************************************************** * Sensor API *************************************************************************/ std::vector get_rx_sensor_names(size_t chan) const override; uhd::sensor_value_t get_rx_sensor(const std::string& name, size_t chan) override; std::vector get_tx_sensor_names(size_t chan) const override; uhd::sensor_value_t get_tx_sensor(const std::string& name, size_t chan) override; /************************************************************************** * Radio Identification API Calls *************************************************************************/ std::string get_slot_name() const override { return _radio_slot; } size_t get_chan_from_dboard_fe( const std::string& fe, const uhd::direction_t direction) const override; std::string get_dboard_fe_from_chan( const size_t chan, const uhd::direction_t direction) const override; std::string get_fe_name( const size_t chan, const uhd::direction_t direction) const override; /************************************************************************ * ??? calls ***********************************************************************/ // LO Distribution Control void set_tx_lo_output_enabled( const bool enabled, const std::string& port_name, const size_t chan); void set_rx_lo_output_enabled( const bool enabled, const std::string& port_name, const size_t chan); bool get_tx_lo_output_enabled(const std::string& port_name, const size_t chan); bool get_rx_lo_output_enabled(const std::string& port_name, const size_t chan); // LO Gain Control //! Set the external gain for a TX LO // Out of range values will be coerced double set_tx_lo_gain(const double gain, const std::string& name, const size_t chan); //! Set the external gain for an RX LO // Out of range values will be coerced double set_rx_lo_gain(const double gain, const std::string& name, const size_t chan); double get_tx_lo_gain(const std::string& name, const size_t chan); double get_rx_lo_gain(const std::string& name, const size_t chan); // LO Output Power Control //! Set the output power setting of a TX LO // Out of range values will be coerced double set_tx_lo_power( const double power, const std::string& name, const size_t chan); //! Set the output power setting of a RX LO // Out of range values will be coerced double set_rx_lo_power( const double power, const std::string& name, const size_t chan); double get_tx_lo_power(const std::string& name, const size_t chan); double get_rx_lo_power(const std::string& name, const size_t chan); private: /************************************************************************** * noc_block_base API *************************************************************************/ //! Safely shut down all peripherals // // Reminder: After this is called, no peeks and pokes are allowed! void deinit() override { RFNOC_LOG_TRACE("deinit()"); // Remove access to all peripherals _wb_iface.reset(); _spi.reset(); _tx_lo.reset(); _rx_lo.reset(); _cpld.reset(); _gpio.reset(); _fp_gpio.reset(); _rx_fe_core.reset(); _tx_fe_core.reset(); } /************************************************************************** * Helpers *************************************************************************/ //! Initialize all the peripherals connected to this block void _init_peripherals(); //! Sync up with MPM void _init_mpm(); //! Set state of this class to sensible defaults void _init_defaults(); //! Init a subtree for the RF frontends void _init_frontend_subtree(uhd::property_tree::sptr subtree); //! Initialize property tree void _init_prop_tree(); //! Discover and initialize any mpm sensors void _init_mpm_sensors(const direction_t dir, const size_t chan_idx); //! Get the frequency range for an LO freq_range_t _get_lo_freq_range(const std::string& name) const; //! Get the current lowband intermediate frequency double _get_lowband_lo_freq() const; //! Configure LO1's export void _set_lo1_export_enabled(const bool enabled, const direction_t dir); //! Validate that port_name is valid, and that LO distribution functions // can be called in this instance void _validate_output_port( const std::string& port_name, const std::string& function_name); //! Configure LO Distribution board's termination switches void _set_lo_output_enabled( const bool enabled, const std::string& port_name, const direction_t dir); bool _get_lo_output_enabled(const std::string& port_name, const direction_t dir); //! Configure LO1's output power // Out of range values will be coerced to [0-63] double _set_lo1_power(const double power, const direction_t dir); //! Flash all front end LEDs at 1 Hz for the specified amount of time void _identify_with_leds(double identify_duration); //! Configure ATR registers and update the cached antenna value from the // new antenna value. // ATR registers control SW10 and the frontend LEDs. void _update_atr(const std::string& ant, const direction_t dir); //! Configure DSP core corrections based on current frequency void _update_corrections(const double freq, const direction_t dir, const bool enable); //! Map a frequency in Hz to an rx_band value. Will return // rx_band::INVALID_BAND if the frequency is out of range. static rx_band _map_freq_to_rx_band(const double freq); //! Map a frequency in Hz to an tx_band value. Will return // tx_band::INVALID_BAND if the frequency is out of range. static tx_band _map_freq_to_tx_band(const double freq); //! Return if the given rx frequency is in lowband // NOTE: Returns false if frequency is out of Rh's rx frequency range static bool _is_rx_lowband(const double freq); //! Return if the given tx frequency is in lowband // NOTE: Returns false if frequency is out of Rh's tx frequency range static bool _is_tx_lowband(const double freq); //! Return the gain range of the LMX LO static uhd::gain_range_t _get_lo_gain_range(); //! Return the power setting range of the LMX LO static uhd::gain_range_t _get_lo_power_range(); //! Lookup the LO DSA setting from LO frequency int _get_lo_dsa_setting(const double freq, const direction_t dir); //! Lookup the LO output power setting from LO frequency unsigned int _get_lo_power_setting(const double freq); bool _get_spur_dodging_enabled(const uhd::direction_t dir) const; double _get_spur_dodging_threshold(const uhd::direction_t dir) const; bool _get_highband_spur_reduction_enabled(const uhd::direction_t dir) const; bool _get_timed_command_enabled() const; /************************************************************************** * Sensors *************************************************************************/ //! Return LO lock status. Factors in current band (low/high) and // direction (TX/RX) bool get_lo_lock_status(const direction_t dir) const; /************************************************************************** * Frontend Controls *************************************************************************/ void _set_tx_fe_connection(const std::string& conn); void _set_rx_fe_connection(const std::string& conn); std::string _get_tx_fe_connection() const; std::string _get_rx_fe_connection() const; /************************************************************************** * CPLD Controls (implemented in rhodium_radio_ctrl_cpld.cpp) *************************************************************************/ void _update_rx_freq_switches(const double freq); void _update_tx_freq_switches(const double freq); void _update_rx_input_switches(const std::string& input); void _update_tx_output_switches(const std::string& output); /************************************************************************** * Private attributes *************************************************************************/ //! Locks access to the antenna cached values std::mutex _ant_mutex; //! Letter representation of the radio we're currently running std::string _radio_slot; //! Prepended for all dboard RPC calls std::string _rpc_prefix; //! Daughterboard info from MPM std::map _dboard_info; //! Reference to the MB controller mpmd_mb_controller::sptr _n320_mb_control; //! Reference to the MB timekeeper uhd::rfnoc::mpmd_mb_controller::mpmd_timekeeper::sptr _n3xx_timekeeper; //! Reference to the RPC client uhd::rpc_client::sptr _rpcc; //! Reference to wb_iface compat adapter. This will call into this->regs() uhd::timed_wb_iface::sptr _wb_iface; //! Reference to the SPI core uhd::spi_iface::sptr _spi; //! Reference to the TX LO lmx2592_iface::sptr _tx_lo; //! Reference to the RX LO lmx2592_iface::sptr _rx_lo; //! Reference to the CPLD controls. Even if there's multiple radios, // there's only one CPLD control. std::shared_ptr _cpld; //! ATR controls. These control the external DSA and the AD9371 gain // up/down bits. They do *not* control the ATR state of the CPLD, the // tx/rx run states are hooked up directly to the CPLD. // // Every radio channel gets its own ATR state register. usrp::gpio_atr::gpio_atr_3000::sptr _gpio; //! Front panel GPIO controller. Note that only one radio block per // module can be the FP-GPIO master. usrp::gpio_atr::gpio_atr_3000::sptr _fp_gpio; //! One DSP core per channel rx_frontend_core_3000::sptr _rx_fe_core; tx_frontend_core_200::sptr _tx_fe_core; //! Sampling rate, and also ref clock frequency for the lowband LOs. double _master_clock_rate = 1.0; //! Saved frontend connection for DSP core std::string _rx_fe_connection; std::string _tx_fe_connection; //! Desired RF frequency std::map _desired_rf_freq = { {RX_DIRECTION, 2.44e9}, {TX_DIRECTION, 2.44e9}}; //! Frequency at which gain setting was last applied. The CPLD requires a new gain // control write when switching between lowband and highband frequencies, so save // the frequency when sending a gain control command. double _tx_frequency_at_last_gain_write = 0.0; double _rx_frequency_at_last_gain_write = 0.0; //! LO gain double _lo_rx_gain = 0.0; double _lo_tx_gain = 0.0; //! LO output power double _lo_rx_power = 0.0; double _lo_tx_power = 0.0; //! Gain profile std::map _gain_profile = { {RX_DIRECTION, "default"}, {TX_DIRECTION, "default"}}; //! LO source std::string _rx_lo_source = "internal"; std::string _tx_lo_source = "internal"; //! LO export enabled bool _rx_lo_exported = false; bool _tx_lo_exported = false; //! LO state frequency double _rx_lo_freq = 0.0; double _tx_lo_freq = 0.0; //! LO Distribution board bool _lo_dist_present = false; //! LO Distribution board output status bool _lo_dist_rx_out_enabled[4] = {false, false, false, false}; bool _lo_dist_tx_out_enabled[4] = {false, false, false, false}; std::unordered_map> _tune_args{{uhd::RX_DIRECTION, uhd::device_addr_t()}, {uhd::TX_DIRECTION, uhd::device_addr_t()}}; //! Cache the contents of the DB EEPROM uhd::eeprom_map_t _db_eeprom; //! Cached list of RX sensor names std::vector _rx_sensor_names{"lo_locked"}; //! Cached list of TX sensor names std::vector _tx_sensor_names{"lo_locked"}; property_t _spur_dodging_mode{SPUR_DODGING_PROP_NAME, RHODIUM_DEFAULT_SPUR_DOGING_MODE, {res_source_info::USER}}; property_t _spur_dodging_threshold{SPUR_DODGING_THRESHOLD_PROP_NAME, RHODIUM_DEFAULT_SPUR_DOGING_THRESHOLD, {res_source_info::USER}}; property_t _highband_spur_reduction_mode{ HIGHBAND_SPUR_REDUCTION_PROP_NAME, RHODIUM_DEFAULT_HB_SPUR_REDUCTION_MODE, {res_source_info::USER}}; }; /* class rhodium_radio_control_impl */ }} /* namespace uhd::rfnoc */ #endif /* INCLUDED_LIBUHD_RFNOC_RHODIUM_RADIO_CTRL_IMPL_HPP */