/** * Copyright 2013-2022 Software Radio Systems Limited * * This file is part of srsRAN. * * srsRAN is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. * * srsRAN is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * A copy of the GNU Affero General Public License can be found in * the LICENSE file in the top-level directory of this distribution * and at http://www.gnu.org/licenses/. * */ #include "channel_mapping.h" #include "radio_metrics.h" #include "rf_buffer.h" #include "rf_timestamp.h" #include "srsran/common/interfaces_common.h" #include "srsran/interfaces/radio_interfaces.h" #include "srsran/phy/resampling/resampler.h" #include "srsran/phy/rf/rf.h" #include "srsran/radio/radio_base.h" #include "srsran/srslog/srslog.h" #include "srsran/srsran.h" #include #include #ifndef SRSRAN_RADIO_H #define SRSRAN_RADIO_H namespace srsran { /** * Implementation of the radio interface for the PHY * * It uses the rf C library object to access the underlying radio. This implementation uses a flat array to * transmit/receive samples for all RF channels. The N carriers and P antennas are mapped into M=NP RF channels (M <= * SRSRAN_MAX_CHANNELS). Note that all carriers must have the same number of antennas. * * The underlying radio receives and transmits M RF channels synchronously from possibly multiple radios using the same * rf driver object. In the current implementation, the mapping between N carriers and P antennas is sequentially, eg: * [carrier_0_port_0, carrier_0_port_1, carrier_1_port_0, carrier_1_port_1, ..., carrier_N_port_N] */ class radio : public radio_interface_phy, public srsran::radio_base { public: radio(); ~radio(); int init(const rf_args_t& args_, phy_interface_radio* phy_) final; void stop() final; std::string get_type() override { return "radio"; } // ==== PHY interface === // trx functions void tx_end() override; bool tx(rf_buffer_interface& buffer, const rf_timestamp_interface& tx_time) override; bool rx_now(rf_buffer_interface& buffer, rf_timestamp_interface& rxd_time) override; // setter void set_tx_freq(const uint32_t& carrier_idx, const double& freq) override; void set_rx_freq(const uint32_t& carrier_idx, const double& freq) override; void release_freq(const uint32_t& carrier_idx) override; void set_tx_gain(const float& gain) override; void set_rx_gain_th(const float& gain) override; void set_rx_gain(const float& gain) override; void set_tx_srate(const double& srate) override; void set_rx_srate(const double& srate) override; void set_channel_rx_offset(uint32_t ch, int32_t offset_samples) override; // getter double get_freq_offset() override; float get_rx_gain() override; bool is_continuous_tx() override; bool get_is_start_of_burst() override; bool is_init() override; void reset() override; srsran_rf_info_t* get_info() override; // Other functions bool get_metrics(rf_metrics_t* metrics) final; void handle_rf_msg(srsran_rf_error_t error); static void rf_msg_callback(void* arg, srsran_rf_error_t error); private: std::vector rf_devices = {}; std::vector rf_info = {}; std::vector rx_offset_n = {}; rf_metrics_t rf_metrics = {}; std::mutex metrics_mutex; srslog::basic_logger& logger = srslog::fetch_basic_logger("RF", false); phy_interface_radio* phy = nullptr; std::vector zeros; std::array, SRSRAN_MAX_CHANNELS> dummy_buffers; std::mutex tx_mutex; std::mutex rx_mutex; std::array, SRSRAN_MAX_CHANNELS> tx_buffer; std::array, SRSRAN_MAX_CHANNELS> rx_buffer; std::array interpolators = {}; std::array decimators = {}; std::atomic decimator_busy = {false}; ///< Indicates the decimator is changing the rate rf_timestamp_t end_of_burst_time = {}; std::atomic is_start_of_burst{false}; uint32_t tx_adv_nsamples = 0; double tx_adv_sec = 0.0; // Transmission time advance to compensate for antenna->timestamp delay bool tx_adv_auto = false; bool tx_adv_negative = false; bool is_initialized = false; bool radio_is_streaming = false; bool continuous_tx = false; double freq_offset = 0.0; double cur_tx_srate = 0.0; double cur_rx_srate = 0.0; double fix_srate_hz = 0.0; uint32_t nof_antennas = 0; uint32_t nof_channels = 0; uint32_t nof_channels_x_dev = 0; uint32_t nof_carriers = 0; std::vector cur_tx_freqs = {}; std::vector cur_rx_freqs = {}; constexpr static const uint32_t max_resamp_buf_sz_ms = 5; ///< Maximum buffer size in ms for intermediate resampling ///< buffers constexpr static double tx_max_gap_zeros = 4e-3; ///< Maximum transmission gap to fill with zeros, otherwise the burst ///< shall be stopped // Define default values for known radios constexpr static int uhd_default_tx_adv_samples = 98; constexpr static double uhd_default_tx_adv_offset_sec = 4 * 1e-6; constexpr static int lime_default_tx_adv_samples = 98; constexpr static double lime_default_tx_adv_offset_sec = 4 * 1e-6; constexpr static int blade_default_tx_adv_samples = 27; constexpr static double blade_default_tx_adv_offset_sec = 1e-6; /** * Get device calibrated transmit time in advanced seconds * @param device_name actual device name * @return transmit time in advanced in seconds */ double get_dev_cal_tx_adv_sec(const std::string& device_name); channel_mapping rx_channel_mapping = {}, tx_channel_mapping = {}; /** * Helper method for opening a RF device * * @param device_idx Device index * @param device_name Device name * @param devive_args Device arguments * @return it returns true if the device was opened successful, otherwise it returns false */ bool open_dev(const uint32_t& device_idx, const std::string& device_name, const std::string& devive_args); /** * Helper method for opening a file-based RF device abstraction * * @param device_idx Device index * @param rx_files Array of pre-opened FILE* for rx * @param tx_files Array of pre-opened FILE* for tx * @param nof_channels Number of elements in each array @p rx_files and @p tx_files * @param base_srate Sampling rate in Hz * @return it returns true if the device was opened successful, otherwise it returns false */ bool open_dev(const uint32_t& device_idx, FILE** rx_files, FILE** tx_files, uint32_t nof_channels, uint32_t base_srate); /** * Helper method for transmitting over a single RF device. This function maps automatically the logical transmit * buffers to the physical RF buffers for the given device. * * Also, it takes care internally of transmission gaps and overlaps. So, it applies time compensation per channel * basis. * * @param device_idx Device index * @param buffer Common transmit buffer * @param nof_samples_ number of samples to transmit * @param tx_time_ Timestamp to transmit (read only) * @return it returns true if the transmission was successful, otherwise it returns false */ bool tx_dev(const uint32_t& device_idx, rf_buffer_interface& buffer, const srsran_timestamp_t& tx_time_); // private unprotected tx_end implementation void tx_end_nolock(); /** * Helper method for receiving over a single RF device. This function maps automatically the logical receive buffers * to the physical RF buffers for the given device. * * @param device_idx Device index * @param buffer Common receive buffers * @param rxd_time Points at the receive time (write only) * @return it returns true if the reception was successful, otherwise it returns false */ bool rx_dev(const uint32_t& device_idx, const rf_buffer_interface& buffer, srsran_timestamp_t* rxd_time); /** * Helper method for mapping logical channels into physical radio buffers. * * @param map Channel mapping, it can be either Tx or Rx mapping * @param device_idx RF Device index for the buffer mapping * @param sample_offset The physical radio buffer pointer offset * @param buffer Logical channels buffer * @param radio_buffers Actual physical radio buffer * @return It returns true if the mapping was successful, otherwise it returns false. */ bool map_channels(const channel_mapping& map, uint32_t device_idx, uint32_t sample_offset, const rf_buffer_interface& buffer, void* radio_buffers[SRSRAN_MAX_CHANNELS]); bool start_agc(bool tx_gain_same_rx = false); void set_tx_adv(int nsamples); void set_tx_adv_neg(bool tx_adv_is_neg); bool config_rf_channels(const rf_args_t& args); }; } // namespace srsran #endif // SRSRAN_RADIO_H