// // Copyright 2019 Ettus Research, a National Instruments Brand // // SPDX-License-Identifier: GPL-3.0-or-later // #pragma once #include #include #include #include #include #include #include #include #include #define RFNOC_RADIO_CONSTRUCTOR(CLASS_NAME) \ CLASS_NAME##_impl(make_args_ptr make_args) : radio_control_impl(std::move(make_args)) namespace uhd { namespace rfnoc { /*! Base class of radio controllers * * All radio control classes should derive from this class (e.g., the X300 radio * controller, etc.) * * Many of the radio_control API calls have virtual (default) implementations * here, but they can be overridden. */ class radio_control_impl : public radio_control, public ::uhd::features::discoverable_feature_registry { public: /************************************************************************** * Structors *************************************************************************/ radio_control_impl(make_args_ptr make_args); virtual void deinit() {} virtual ~radio_control_impl() {} /************************************************************************** * Stream control API calls *************************************************************************/ void issue_stream_cmd(const uhd::stream_cmd_t& stream_cmd, const size_t port); void enable_rx_timestamps(const bool enable, const size_t chan); /************************************************************************** * Rate-Related API Calls *************************************************************************/ virtual double set_rate(const double rate); virtual double get_rate() const; virtual meta_range_t get_rate_range() const; /************************************************************************** * RF-specific API calls *************************************************************************/ // Setters virtual void set_tx_antenna(const std::string& ant, const size_t chan); virtual void set_rx_antenna(const std::string& ant, const size_t chan); virtual double set_tx_frequency(const double freq, const size_t chan); virtual double set_rx_frequency(const double freq, const size_t chan); virtual void set_tx_tune_args(const uhd::device_addr_t&, const size_t chan); virtual void set_rx_tune_args(const uhd::device_addr_t&, const size_t chan); virtual double set_tx_gain(const double gain, const size_t chan); virtual double set_tx_gain( const double gain, const std::string& name, const size_t chan); virtual double set_rx_gain(const double gain, const size_t chan); virtual double set_rx_gain( const double gain, const std::string& name, const size_t chan); virtual void set_rx_agc(const bool enable, const size_t chan); virtual double set_tx_bandwidth(const double bandwidth, const size_t chan); virtual double set_rx_bandwidth(const double bandwidth, const size_t chan); virtual void set_tx_gain_profile(const std::string& profile, const size_t chan); virtual void set_rx_gain_profile(const std::string& profile, const size_t chan); virtual void set_rx_power_reference(const double power_dbm, const size_t chan); virtual void set_tx_power_reference(const double power_dbm, const size_t chan); // Getters virtual std::string get_tx_antenna(const size_t chan) const; virtual std::string get_rx_antenna(const size_t chan) const; virtual std::vector get_tx_antennas(const size_t chan) const; virtual std::vector get_rx_antennas(const size_t chan) const; virtual double get_tx_frequency(const size_t); virtual double get_rx_frequency(const size_t); virtual uhd::freq_range_t get_tx_frequency_range(const size_t chan) const; virtual uhd::freq_range_t get_rx_frequency_range(const size_t chan) const; virtual std::vector get_tx_gain_names(const size_t) const; virtual std::vector get_rx_gain_names(const size_t) const; virtual double get_tx_gain(const size_t); virtual double get_tx_gain(const std::string&, size_t); virtual double get_rx_gain(const size_t); virtual double get_rx_gain(const std::string&, size_t); virtual uhd::gain_range_t get_tx_gain_range(const size_t) const; virtual uhd::gain_range_t get_tx_gain_range(const std::string&, const size_t) const; virtual uhd::gain_range_t get_rx_gain_range(const size_t) const; virtual uhd::gain_range_t get_rx_gain_range(const std::string&, const size_t) const; virtual std::vector get_tx_gain_profile_names(const size_t chan) const; virtual std::vector get_rx_gain_profile_names(const size_t chan) const; virtual std::string get_tx_gain_profile(const size_t chan) const; virtual std::string get_rx_gain_profile(const size_t chan) const; virtual double get_tx_bandwidth(const size_t); virtual double get_rx_bandwidth(const size_t); virtual meta_range_t get_tx_bandwidth_range(size_t chan) const; virtual meta_range_t get_rx_bandwidth_range(size_t chan) const; virtual bool has_rx_power_reference(const size_t chan); virtual bool has_tx_power_reference(const size_t chan); virtual double get_rx_power_reference(const size_t chan); virtual double get_tx_power_reference(const size_t chan); virtual std::vector get_rx_power_ref_keys(const size_t); virtual std::vector get_tx_power_ref_keys(const size_t); virtual meta_range_t get_rx_power_range(const size_t chan); virtual meta_range_t get_tx_power_range(const size_t chan); /************************************************************************** * LO Controls *************************************************************************/ virtual std::vector get_rx_lo_names(const size_t chan) const; virtual std::vector get_rx_lo_sources( const std::string& name, const size_t chan) const; virtual freq_range_t get_rx_lo_freq_range( const std::string& name, const size_t chan) const; virtual void set_rx_lo_source( const std::string& src, const std::string& name, const size_t chan); virtual const std::string get_rx_lo_source( const std::string& name, const size_t chan); virtual void set_rx_lo_export_enabled( bool enabled, const std::string& name, const size_t chan); virtual bool get_rx_lo_export_enabled( const std::string& name, const size_t chan) const; virtual double set_rx_lo_freq( double freq, const std::string& name, const size_t chan); virtual double get_rx_lo_freq(const std::string& name, const size_t chan); virtual std::vector get_tx_lo_names(const size_t chan) const; virtual std::vector get_tx_lo_sources( const std::string& name, const size_t chan); virtual freq_range_t get_tx_lo_freq_range(const std::string& name, const size_t chan); virtual void set_tx_lo_source( const std::string& src, const std::string& name, const size_t chan); virtual const std::string get_tx_lo_source( const std::string& name, const size_t chan); virtual void set_tx_lo_export_enabled( const bool enabled, const std::string& name, const size_t chan); virtual bool get_tx_lo_export_enabled(const std::string& name, const size_t chan); virtual double set_tx_lo_freq( const double freq, const std::string& name, const size_t chan); virtual double get_tx_lo_freq(const std::string& name, const size_t chan); /************************************************************************** * Calibration-Related API Calls *************************************************************************/ virtual void set_tx_dc_offset(const std::complex& offset, size_t chan); virtual meta_range_t get_tx_dc_offset_range(size_t chan) const; virtual void set_tx_iq_balance(const std::complex& correction, size_t chan); virtual void set_rx_dc_offset(const bool enb, size_t chan = ALL_CHANS); virtual void set_rx_dc_offset(const std::complex& offset, size_t chan); virtual meta_range_t get_rx_dc_offset_range(size_t chan) const; virtual void set_rx_iq_balance(const bool enb, size_t chan); virtual void set_rx_iq_balance(const std::complex& correction, size_t chan); /************************************************************************** * GPIO Controls *************************************************************************/ virtual std::vector get_gpio_banks() const; virtual void set_gpio_attr( const std::string& bank, const std::string& attr, const uint32_t value); virtual uint32_t get_gpio_attr(const std::string& bank, const std::string& attr); /************************************************************************** * Sensor API *************************************************************************/ virtual std::vector get_rx_sensor_names(size_t chan) const; virtual uhd::sensor_value_t get_rx_sensor(const std::string& name, size_t chan); virtual std::vector get_tx_sensor_names(size_t chan) const; virtual uhd::sensor_value_t get_tx_sensor(const std::string& name, size_t chan); /************************************************************************** * Identification API *************************************************************************/ virtual std::string get_fe_name( const size_t chan, const uhd::direction_t direction) const { return get_dboard_fe_from_chan(chan, direction); } /************************************************************************** * EEPROM API *************************************************************************/ virtual void set_db_eeprom(const uhd::eeprom_map_t& db_eeprom); virtual uhd::eeprom_map_t get_db_eeprom(); /*********************************************************************** * Reg Map **********************************************************************/ static const uint16_t MAJOR_COMPAT; static const uint16_t MINOR_COMPAT; /*! Register map common to all radios * * See rfnoc_block_radio_regs.vh for details */ struct regmap { static const uint32_t REG_COMPAT_NUM = 0x00; // Compatibility number register offset static const uint32_t REG_RADIO_WIDTH = 0x1000 + 0x04; // Upper 16 bits is sample width, lower 16 bits is NSPC static const uint32_t RADIO_BASE_ADDR = 0x1000; static const uint32_t REG_CHAN_OFFSET = 128; static const uint32_t RADIO_ADDR_W = 7; // Address space size per radio // General Radio Registers static const uint32_t REG_LOOPBACK_EN = 0x00; // Loopback enable (connect Tx output to Rx input) // Note on the RX and TX Control Registers: These are per-channel, // which means the values here are offsets. The base address per // channel is RADIO_BASE_ADDR + i * REG_CHAN_OFFSET, where i is the // channel index. // RX Control Registers static const uint32_t REG_RX_STATUS = 0x10; // Status of Rx radio static const uint32_t REG_RX_CMD = 0x14; // The next radio command to execute static const uint32_t REG_RX_CMD_NUM_WORDS_LO = 0x18; // Number of radio words for the next command (low word) static const uint32_t REG_RX_CMD_NUM_WORDS_HI = 0x1C; // Number of radio words for the next command (high word) static const uint32_t REG_RX_CMD_TIME_LO = 0x20; // Time for the next command (low word) static const uint32_t REG_RX_CMD_TIME_HI = 0x24; // Time for the next command (high word) static const uint32_t REG_RX_MAX_WORDS_PER_PKT = 0x28; // Maximum packet length to build from Rx data static const uint32_t REG_RX_ERR_PORT = 0x2C; // Port ID for error reporting static const uint32_t REG_RX_ERR_REM_PORT = 0x30; // Remote port ID for error reporting static const uint32_t REG_RX_ERR_REM_EPID = 0x34; // Remote EPID (endpoint ID) for error reporting static const uint32_t REG_RX_ERR_ADDR = 0x38; // Offset to which to write error code (ADDR+0) and time (ADDR+8) static const uint32_t REG_RX_DATA = 0x3C; static const uint32_t REG_RX_HAS_TIME = 0x70; // Set to one if radio output packets should have timestamps // TX Control Registers static const uint32_t REG_TX_IDLE_VALUE = 0x40; // Value to output when transmitter is idle static const uint32_t REG_TX_ERROR_POLICY = 0x44; // Tx error policy static const uint32_t REG_TX_ERR_PORT = 0x48; // Port ID for error reporting static const uint32_t REG_TX_ERR_REM_PORT = 0x4C; // Remote port ID for error reporting static const uint32_t REG_TX_ERR_REM_EPID = 0x50; // Remote EPID (endpoint ID) for error reporting static const uint32_t REG_TX_ERR_ADDR = 0x54; // Offset to which to write error code (ADDR+0) and time (ADDR+8) static const uint32_t RX_CMD_STOP = 0; // Stop acquiring at end of next packet static const uint32_t RX_CMD_FINITE = 1; // Acquire NUM_SAMPS then stop static const uint32_t RX_CMD_CONTINUOUS = 2; // Acquire until stopped static const uint32_t RX_CMD_TIMED_POS = 31; static const uint32_t PERIPH_BASE = 0x80000; static const uint32_t PERIPH_REG_OFFSET = 8; static const uint32_t SWREG_TX_ERR = 0x0000; static const uint32_t SWREG_RX_ERR = 0x1000; static const uint32_t SWREG_CHAN_OFFSET = 64; }; struct err_codes { //! Late command (stream command arrived after indicated time) static const uint32_t ERR_RX_LATE_CMD = 1; //! FIFO overflow static const uint32_t ERR_RX_OVERRUN = 2; // FIFO underrun (data not available when needed) static const uint32_t ERR_TX_UNDERRUN = 1; //! Late data (arrived after indicated time) static const uint32_t ERR_TX_LATE_DATA = 2; //! Acknowledge a TX burst with an EOB static const uint32_t EVENT_TX_BURST_ACK = 3; }; //! Tree path to the dboard-specific properties static const uhd::fs_path DB_PATH; //! Tree path to the radio frontends' properties static const uhd::fs_path FE_PATH; protected: /*! Helper function for property propagation: Like set_rate(), but called * during a different context. * * This function is called from the samp_rate property resolver. The * difference to set_rate() is that the latter is a user API, and may * trigger different kinds of warnings or errors. * If the radio supports changing its sampling rate at runtime, it is OK to * call set_rate() within this function. * * Default implementation is to simply return the current rate. */ virtual double coerce_rate(const double /* rate */) { return _rate; } //! Properties for samp_rate (one per port) std::vector> _samp_rate_in; //! Properties for samp_rate (one per port) std::vector> _samp_rate_out; //! Block-specific register interface multichan_register_iface _radio_reg_iface; //! Power manager for RX power cal. If the radio doesn't have a power API, // simply leave these empty. std::vector _rx_pwr_mgr; //! Power manager for TX power cal. If the radio doesn't have a power API, // simply leave these empty. std::vector _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 // // We only know about overruns, underruns, and late commands/packets. bool async_message_validator(uint32_t addr, const std::vector& data); //! Receiver for the async messages // // This block will receive all async messages. The following async messages // are expected to show up: // - Overrun info // - Underrun info // - Late data packets void async_message_handler(uint32_t addr, const std::vector& data, boost::optional timestamp); //! FPGA compat number const uint32_t _fpga_compat; //! Copy of the REG_RADIO_WIDTH register const uint32_t _radio_width; //! Sample width (total width, sc16 == 32 bits per complex sample) const uint32_t _samp_width; //! Samples per cycle const uint32_t _spc; std::vector> _spp_prop; //! Properties for type_in (one per port) std::vector> _type_in; //! Properties for type_out (one per port) std::vector> _type_out; mutable std::mutex _cache_mutex; double _rate = 1.0; std::unordered_map _tx_antenna; std::unordered_map _rx_antenna; std::unordered_map _tx_freq; std::unordered_map _rx_freq; std::unordered_map _tx_gain; std::unordered_map _rx_gain; std::unordered_map _tx_bandwidth; std::unordered_map _rx_bandwidth; std::vector _last_stream_cmd; }; }} // namespace uhd::rfnoc