From 4e12405fffa4e089ed7c657bd0f92f463b30ef35 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Fri, 6 Mar 2020 15:26:48 +0100 Subject: [PATCH] Remove radio_multi class and organize channels, ports and carrier buffers (#1019) --- lib/examples/pdsch_ue.c | 2 +- lib/include/srslte/common/interfaces_common.h | 9 +- .../srslte/interfaces/common_interfaces.h | 83 --- .../srslte/interfaces/radio_interfaces.h | 173 +++++ lib/include/srslte/interfaces/ue_interfaces.h | 8 - lib/include/srslte/phy/channel/channel.h | 10 +- lib/include/srslte/phy/common/phy_common.h | 2 +- lib/include/srslte/phy/rf/rf.h | 8 +- lib/include/srslte/phy/rf/rf_utils.h | 6 +- lib/include/srslte/phy/ue/ue_cell_search.h | 15 +- .../srslte/phy/ue/ue_cell_search_nbiot.h | 4 +- lib/include/srslte/phy/ue/ue_mib.h | 21 +- lib/include/srslte/phy/ue/ue_sync.h | 51 +- lib/include/srslte/radio/radio.h | 303 +++++---- lib/include/srslte/radio/radio_base.h | 53 -- lib/include/srslte/radio/radio_multi.h | 154 ----- lib/src/phy/channel/channel.cc | 27 +- lib/src/phy/rf/rf_blade_imp.c | 14 +- lib/src/phy/rf/rf_blade_imp.h | 2 +- lib/src/phy/rf/rf_dev.h | 4 +- lib/src/phy/rf/rf_imp.c | 8 +- lib/src/phy/rf/rf_soapy_imp.c | 14 +- lib/src/phy/rf/rf_soapy_imp.h | 2 +- lib/src/phy/rf/rf_uhd_imp.c | 69 +- lib/src/phy/rf/rf_uhd_imp.h | 4 +- lib/src/phy/rf/rf_utils.c | 23 +- lib/src/phy/rf/rf_zmq_imp.c | 20 +- lib/src/phy/rf/rf_zmq_imp.h | 2 +- lib/src/phy/ue/ue_cell_search.c | 15 +- lib/src/phy/ue/ue_mib.c | 36 +- lib/src/phy/ue/ue_sync.c | 43 +- lib/src/radio/CMakeLists.txt | 2 +- lib/src/radio/radio.cc | 384 ++++++----- lib/src/radio/radio_multi.cc | 178 ----- lib/src/radio/test/benchmark_radio.cc | 27 +- srsenb/enb.conf.example | 5 +- srsenb/hdr/enb.h | 4 +- srsenb/hdr/phy/phy.h | 2 +- srsenb/hdr/phy/phy_common.h | 4 +- srsenb/hdr/radio/enb_radio_multi.h | 49 -- srsenb/src/CMakeLists.txt | 4 +- srsenb/src/enb.cc | 5 +- srsenb/src/enb_cfg_parser.cc | 5 +- srsenb/src/main.cc | 5 +- srsenb/src/phy/phy_common.cc | 12 +- srsenb/src/phy/sf_worker.cc | 10 +- srsenb/src/phy/txrx.cc | 36 +- srsenb/src/radio/CMakeLists.txt | 22 - srsenb/src/radio/enb_radio_multi.cc | 36 - srsenb/test/phy/enb_phy_test.cc | 36 +- srsue/hdr/phy/phy.h | 6 +- srsue/hdr/phy/phy_common.h | 9 +- srsue/hdr/phy/sf_worker.h | 8 +- srsue/hdr/phy/sync.h | 63 +- srsue/hdr/phy/ue_lte_phy_base.h | 2 +- srsue/hdr/ue.h | 4 +- srsue/src/CMakeLists.txt | 2 + srsue/src/main.cc | 22 +- srsue/src/phy/phy.cc | 83 +-- srsue/src/phy/phy_common.cc | 62 +- srsue/src/phy/scell/async_scell_recv.cc | 621 ------------------ srsue/src/phy/sf_worker.cc | 38 +- srsue/src/phy/sync.cc | 188 ++---- srsue/src/ue.cc | 33 +- srsue/test/phy/scell_search_test.cc | 12 +- srsue/test/phy/ue_phy_test.cc | 48 +- srsue/ue.conf.example | 12 +- 67 files changed, 1122 insertions(+), 2102 deletions(-) delete mode 100644 lib/include/srslte/interfaces/common_interfaces.h create mode 100644 lib/include/srslte/interfaces/radio_interfaces.h delete mode 100644 lib/include/srslte/radio/radio_base.h delete mode 100644 lib/include/srslte/radio/radio_multi.h delete mode 100644 lib/src/radio/radio_multi.cc delete mode 100644 srsenb/hdr/radio/enb_radio_multi.h delete mode 100644 srsenb/src/radio/CMakeLists.txt delete mode 100644 srsenb/src/radio/enb_radio_multi.cc delete mode 100644 srsue/src/phy/scell/async_scell_recv.cc diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index 794850854..9bbf20b63 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -569,7 +569,7 @@ int main(int argc, char** argv) sf_buffer[i] = srslte_vec_cf_malloc(max_num_samples); } srslte_ue_mib_t ue_mib; - if (srslte_ue_mib_init(&ue_mib, sf_buffer, cell.nof_prb)) { + if (srslte_ue_mib_init(&ue_mib, sf_buffer[0], cell.nof_prb)) { ERROR("Error initaiting UE MIB decoder\n"); exit(-1); } diff --git a/lib/include/srslte/common/interfaces_common.h b/lib/include/srslte/common/interfaces_common.h index b4b7c9353..50329ed2b 100644 --- a/lib/include/srslte/common/interfaces_common.h +++ b/lib/include/srslte/common/interfaces_common.h @@ -46,14 +46,11 @@ typedef struct { float tx_max_power; float tx_gain_offset; float rx_gain_offset; - uint32_t nof_radios; - uint32_t nof_rf_channels; // Number of RF channels per radio - uint32_t nof_rx_ant; // Number of RF channels for MIMO - uint32_t nof_tx_ports; // Number of Tx ports for MIMO + uint32_t nof_carriers; // Number of RF channels + uint32_t nof_antennas; // Number of antennas per RF channel std::string device_name; - std::string device_args[SRSLTE_MAX_RADIOS]; + std::string device_args; std::string time_adv_nsamples; - std::string burst_preamble; std::string continuous_tx; } rf_args_t; diff --git a/lib/include/srslte/interfaces/common_interfaces.h b/lib/include/srslte/interfaces/common_interfaces.h deleted file mode 100644 index 6b037b485..000000000 --- a/lib/include/srslte/interfaces/common_interfaces.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2013-2019 Software Radio Systems Limited - * - * This file is part of srsLTE. - * - * srsLTE 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. - * - * srsLTE 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/. - * - */ - -/****************************************************************************** - * File: common_interfaces.h - * Description: Common interface for eNB/UE for PHY and radio - *****************************************************************************/ - -#ifndef SRSLTE_COMMON_INTERFACES_H -#define SRSLTE_COMMON_INTERFACES_H - -#include "srslte/phy/common/phy_common.h" -#include "srslte/phy/common/timestamp.h" -#include "srslte/phy/rf/rf.h" - -namespace srslte { - -class radio_interface_phy -{ -public: - // trx functions - virtual bool tx(const uint32_t& radio_idx, - cf_t* buffer[SRSLTE_MAX_PORTS], - const uint32_t& nof_samples, - const srslte_timestamp_t& tx_time) = 0; - virtual void tx_end() = 0; - virtual bool rx_now(const uint32_t& radio_idx, - cf_t* buffer[SRSLTE_MAX_PORTS], - const uint32_t& nof_samples, - srslte_timestamp_t* rxd_time) = 0; - - // setter - virtual void set_tx_freq(const uint32_t& radio_idx, const uint32_t& channel_idx, const double& freq) = 0; - virtual void set_rx_freq(const uint32_t& radio_idx, const uint32_t& channel_idx, const double& freq) = 0; - - virtual void set_rx_gain_th(const float& gain) = 0; - virtual void set_rx_gain(const uint32_t& radio_idx, const float& gain) = 0; - virtual void set_tx_srate(const uint32_t& radio_idx, const double& srate) = 0; - virtual void set_rx_srate(const uint32_t& radio_idx, const double& srate) = 0; - - // getter - virtual float get_rx_gain(const uint32_t& radio_idx) = 0; - virtual double get_freq_offset() = 0; - virtual double get_tx_freq(const uint32_t& radio_idx) = 0; - virtual double get_rx_freq(const uint32_t& radio_idx) = 0; - virtual float get_max_tx_power() = 0; - virtual float get_tx_gain_offset() = 0; - virtual float get_rx_gain_offset() = 0; - virtual bool is_continuous_tx() = 0; - virtual bool get_is_start_of_burst(const uint32_t& radio_idx) = 0; - virtual bool is_init() = 0; - virtual void reset() = 0; - virtual srslte_rf_info_t* get_info(const uint32_t& radio_idx) = 0; -}; - -class phy_interface_radio -{ -public: - virtual void radio_overflow() = 0; - virtual void radio_failure() = 0; -}; - -} // namespace srslte - -#endif // SRSLTE_COMMON_INTERFACES_H diff --git a/lib/include/srslte/interfaces/radio_interfaces.h b/lib/include/srslte/interfaces/radio_interfaces.h new file mode 100644 index 000000000..46a4eeb70 --- /dev/null +++ b/lib/include/srslte/interfaces/radio_interfaces.h @@ -0,0 +1,173 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE 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. + * + * srsLTE 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/. + * + */ + +/****************************************************************************** + * File: radio_interfaces.h + * Description: Common interface for eNB/UE for PHY and radio + *****************************************************************************/ + +#ifndef SRSLTE_RADIO_INTERFACES_H +#define SRSLTE_RADIO_INTERFACES_H + +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/common/timestamp.h" +#include "srslte/phy/rf/rf.h" +#include "srslte/phy/utils/vector.h" +#include + +namespace srslte { + +/** + * Class used to pass buffers for all channels and antennas to the radio + * + * The class provides an abstraction to map carriers and antennas to the underlying + * RF channels. It provides getters and setters to access the raw pointers where the signal + * is stored. + * + * It can automatically allocate and deallocate memory for the buffers if + * a non-zero number of subframes is passed to the constructor. + * + */ +class rf_buffer_interface +{ +public: + virtual cf_t* get(uint32_t channel_idx) const = 0; + virtual void set(uint32_t channel_idx, cf_t* ptr) = 0; + virtual cf_t* get(uint32_t cc_idx, uint32_t port_idx, uint32_t nof_antennas) const = 0; + virtual void set(uint32_t cc_idx, uint32_t port_idx, uint32_t nof_antennas, cf_t* ptr) = 0; + virtual void** to_void() = 0; + virtual cf_t** to_cf_t() = 0; + virtual uint32_t size() = 0; +}; + +/** + * Radio interface for the PHY. + * + * The main functionality is to allow TX and RX of samples to the radio. + * It also provides functions to change the radio settings such as carrier frequency, + * sampling rate, gains, etc. + * + * The radio interface supports multiple carriers and multiple antennas per carrier. This interface presents an + * abstract access to carries and ports to the PHY, regardless of the mapping to RF channels in the underlying radio. + * number of carriers <= SRSLTE_MAX_CARRIERS + * number of ports <= SRSLTE_MAX_PORTS + * + * Changing the tx/rx frequency is done on a carrier level and the underlying implementation + * will set it for all ports when necessary. + * + * Samples are passed and received to/from the radio using rf_buffer_t object + * @see rf_buffer_t + * @see radio + */ +class radio_interface_phy +{ +public: + /** + * Indicates the end of a burst in the current TX stream. Usually called after a call to tx() if + * no more samples are needed to be transmitted. + */ + virtual void tx_end() = 0; + /** + * Indicates the radio to transmit on all antennas and carriers synchronously the samples contained in + * the buffer object. + * + * @param buffer Is the object that contains the pointers to all RF channels + * @param nof_samples Number of samples to transmit on all carriers and antennas + * @param tx_time Time to transmit all signals + * @return + */ + virtual bool tx(rf_buffer_interface& buffer, const uint32_t& nof_samples, const srslte_timestamp_t& tx_time) = 0; + + /** + * Indicates the radio to receive from all antennas and carriers synchronously and store the samples + * in the buffer object + * + * @param buffer Is the object where the samples will be stored + * @param nof_samples Number of samples to receive from all carriers and antennas + * @param tx_time Time at which the samples were received. Note the time is the same for all carriers + * @return + */ + virtual bool rx_now(rf_buffer_interface& buffer, const uint32_t& nof_samples, srslte_timestamp_t* rxd_time) = 0; + + /** + * Sets the TX frequency for all antennas in the provided carrier index + * @param carrier_idx Index of the carrier to change the frequency + * @param freq Frequency to set to in Hz + */ + virtual void set_tx_freq(const uint32_t& carrier_idx, const double& freq) = 0; + + /** + * Sets the RX frequency for all antennas in the provided carrier index + * @param carrier_idx Index of the carrier to change the frequency + * @param freq Frequency to set to in Hz + */ + virtual void set_rx_freq(const uint32_t& carrier_idx, const double& freq) = 0; + + /** + * Sets the transmit gain for all carriers and antennas + * @param gain Gain in dB + */ + virtual void set_tx_gain(const float& gain) = 0; + + /** + * Sets the receive gain for all carriers and antennas in a background + * @param gain Gain in dB + */ + virtual void set_rx_gain_th(const float& gain) = 0; + + /** + * Sets the receive gain for all carriers and antennas + * @param gain Gain in dB + */ + virtual void set_rx_gain(const float& gain) = 0; + + /** + * Sets the sampling rate of the D/A converter simultaneously for all carriers and antennas + * @param srate Sampling rate in Hz + */ + virtual void set_tx_srate(const double& srate) = 0; + + /** + * Sets the sampling rate of the A/D converter simultaneously for all carriers and antennas + * @param srate Sampling rate in Hz + */ + virtual void set_rx_srate(const double& srate) = 0; + + // getter + virtual double get_freq_offset() = 0; + virtual float get_rx_gain() = 0; + virtual bool is_continuous_tx() = 0; + virtual bool get_is_start_of_burst() = 0; + virtual bool is_init() = 0; + virtual void reset() = 0; + virtual srslte_rf_info_t* get_info() = 0; +}; + +class phy_interface_radio +{ +public: + virtual void radio_overflow() = 0; + virtual void radio_failure() = 0; +}; + +} // namespace srslte + +#endif // SRSLTE_RADIO_INTERFACES_H diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index 198e03905..d6b5a96c3 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -468,11 +468,6 @@ public: * */ -typedef struct { - uint32_t radio_idx; - uint32_t channel_idx; -} carrier_map_t; - typedef struct { std::string type = "lte"; srslte::phy_log_args_t log; @@ -492,10 +487,7 @@ typedef struct { int sync_cpu_affinity = -1; uint32_t nof_carriers = 1; - uint32_t nof_radios = 1; uint32_t nof_rx_ant = 1; - uint32_t nof_rf_channels = 1; - carrier_map_t carrier_map[SRSLTE_MAX_CARRIERS] = {}; std::string equalizer_mode = "mmse"; int cqi_max = 15; int cqi_fixed = -1; diff --git a/lib/include/srslte/phy/channel/channel.h b/lib/include/srslte/phy/channel/channel.h index 6bc15ad5d..5811a1b88 100644 --- a/lib/include/srslte/phy/channel/channel.h +++ b/lib/include/srslte/phy/channel/channel.h @@ -62,21 +62,21 @@ public: uint32_t rlf_t_off_ms = 2000; } args_t; - channel(const args_t& channel_args, uint32_t _nof_ports); + channel(const args_t& channel_args, uint32_t _nof_channels); ~channel(); void set_logger(log_filter* _log_h); void set_srate(uint32_t srate); - void run(cf_t* in[SRSLTE_MAX_PORTS], cf_t* out[SRSLTE_MAX_PORTS], uint32_t len, const srslte_timestamp_t& t); + void run(cf_t* in[SRSLTE_MAX_CHANNELS], cf_t* out[SRSLTE_MAX_CHANNELS], uint32_t len, const srslte_timestamp_t& t); private: - srslte_channel_fading_t* fading[SRSLTE_MAX_PORTS] = {}; - srslte_channel_delay_t* delay[SRSLTE_MAX_PORTS] = {}; + srslte_channel_fading_t* fading[SRSLTE_MAX_CHANNELS] = {}; + srslte_channel_delay_t* delay[SRSLTE_MAX_CHANNELS] = {}; srslte_channel_hst_t* hst = nullptr; // HST has no buffers / no multiple instance is required srslte_channel_rlf_t* rlf = nullptr; // RLF has no buffers / no multiple instance is required cf_t* buffer_in = nullptr; cf_t* buffer_out = nullptr; log_filter* log_h = nullptr; - uint32_t nof_ports = 0; + uint32_t nof_channels = 0; uint32_t current_srate = 0; args_t args = {}; }; diff --git a/lib/include/srslte/phy/common/phy_common.h b/lib/include/srslte/phy/common/phy_common.h index 3ef21d2ab..dac51722f 100644 --- a/lib/include/srslte/phy/common/phy_common.h +++ b/lib/include/srslte/phy/common/phy_common.h @@ -53,9 +53,9 @@ extern "C" { #define SRSLTE_NOF_NID_2 (3) #define SRSLTE_NUM_PCI (SRSLTE_NOF_NID_1 * SRSLTE_NOF_NID_2) -#define SRSLTE_MAX_RADIOS 3 // Maximum number of supported RF devices #define SRSLTE_MAX_CARRIERS 5 // Maximum number of supported simultaneous carriers #define SRSLTE_MAX_PORTS 4 +#define SRSLTE_MAX_CHANNELS (SRSLTE_MAX_CARRIERS * SRSLTE_MAX_PORTS) #define SRSLTE_MAX_LAYERS 4 #define SRSLTE_MAX_CODEWORDS 2 #define SRSLTE_MAX_TB SRSLTE_MAX_CODEWORDS diff --git a/lib/include/srslte/phy/rf/rf.h b/lib/include/srslte/phy/rf/rf.h index a9b0d93c6..e0b284b4a 100644 --- a/lib/include/srslte/phy/rf/rf.h +++ b/lib/include/srslte/phy/rf/rf.h @@ -63,7 +63,7 @@ typedef struct { const char* msg; } srslte_rf_error_t; -typedef void (*srslte_rf_error_handler_t)(srslte_rf_error_t error); +typedef void (*srslte_rf_error_handler_t)(void* arg, srslte_rf_error_t error); SRSLTE_API int srslte_rf_open(srslte_rf_t* h, char* args); @@ -103,7 +103,7 @@ SRSLTE_API srslte_rf_info_t* srslte_rf_get_info(srslte_rf_t* h); SRSLTE_API void srslte_rf_suppress_stdout(srslte_rf_t* h); -SRSLTE_API void srslte_rf_register_error_handler(srslte_rf_t* h, srslte_rf_error_handler_t error_handler); +SRSLTE_API void srslte_rf_register_error_handler(srslte_rf_t* h, srslte_rf_error_handler_t error_handler, void* arg); SRSLTE_API double srslte_rf_set_rx_freq(srslte_rf_t* h, uint32_t ch, double freq); @@ -147,7 +147,7 @@ SRSLTE_API int srslte_rf_send_timed2(srslte_rf_t* h, bool is_end_of_burst); SRSLTE_API int srslte_rf_send_timed_multi(srslte_rf_t* rf, - void* data[4], + void** data, int nsamples, time_t secs, double frac_secs, @@ -156,7 +156,7 @@ SRSLTE_API int srslte_rf_send_timed_multi(srslte_rf_t* rf, bool is_end_of_burst); SRSLTE_API int srslte_rf_send_multi(srslte_rf_t* rf, - void* data[4], + void** data, int nsamples, bool blocking, bool is_start_of_burst, diff --git a/lib/include/srslte/phy/rf/rf_utils.h b/lib/include/srslte/phy/rf/rf_utils.h index a38777328..a6873a532 100644 --- a/lib/include/srslte/phy/rf/rf_utils.h +++ b/lib/include/srslte/phy/rf/rf_utils.h @@ -36,17 +36,17 @@ typedef struct SRSLTE_API { SRSLTE_API int rf_rssi_scan(srslte_rf_t* rf, float* freqs, float* rssi, int nof_bands, double fs, int nsamp); SRSLTE_API int -rf_mib_decoder(srslte_rf_t* rf, uint32_t nof_rx_antennas, cell_search_cfg_t* config, srslte_cell_t* cell, float* cfo); +rf_mib_decoder(srslte_rf_t* rf, uint32_t nof_rf_channels, cell_search_cfg_t* config, srslte_cell_t* cell, float* cfo); SRSLTE_API int rf_cell_search(srslte_rf_t* rf, - uint32_t nof_rx_antennas, + uint32_t nof_rf_channels, cell_search_cfg_t* config, int force_N_id_2, srslte_cell_t* cell, float* cfo); SRSLTE_API int rf_search_and_decode_mib(srslte_rf_t* rf, - uint32_t nof_rx_antennas, + uint32_t nof_rf_channels, cell_search_cfg_t* config, int force_N_id_2, srslte_cell_t* cell, diff --git a/lib/include/srslte/phy/ue/ue_cell_search.h b/lib/include/srslte/phy/ue/ue_cell_search.h index d0b8a99f5..5dc0ac3f8 100644 --- a/lib/include/srslte/phy/ue/ue_cell_search.h +++ b/lib/include/srslte/phy/ue/ue_cell_search.h @@ -64,8 +64,8 @@ typedef struct SRSLTE_API { typedef struct SRSLTE_API { srslte_ue_sync_t ue_sync; - - cf_t *sf_buffer[SRSLTE_MAX_PORTS]; + + cf_t* sf_buffer[SRSLTE_MAX_CHANNELS]; uint32_t nof_rx_antennas; uint32_t max_frames; @@ -82,11 +82,12 @@ SRSLTE_API int srslte_ue_cellsearch_init(srslte_ue_cellsearch_t *q, int (recv_callback)(void*, void*, uint32_t,srslte_timestamp_t*), void *stream_handler); -SRSLTE_API int srslte_ue_cellsearch_init_multi(srslte_ue_cellsearch_t *q, - uint32_t max_frames_total, - int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t,srslte_timestamp_t*), - uint32_t nof_rx_antennas, - void *stream_handler); +SRSLTE_API int +srslte_ue_cellsearch_init_multi(srslte_ue_cellsearch_t* q, + uint32_t max_frames_total, + int(recv_callback)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*), + uint32_t nof_rx_antennas, + void* stream_handler); SRSLTE_API void srslte_ue_cellsearch_free(srslte_ue_cellsearch_t *q); diff --git a/lib/include/srslte/phy/ue/ue_cell_search_nbiot.h b/lib/include/srslte/phy/ue/ue_cell_search_nbiot.h index 539595477..516f227b2 100644 --- a/lib/include/srslte/phy/ue/ue_cell_search_nbiot.h +++ b/lib/include/srslte/phy/ue/ue_cell_search_nbiot.h @@ -54,7 +54,7 @@ typedef struct SRSLTE_API { typedef struct SRSLTE_API { srslte_nbiot_ue_sync_t ue_sync; - cf_t* rx_buffer[SRSLTE_MAX_PORTS]; + cf_t* rx_buffer[SRSLTE_MAX_CHANNELS]; cf_t* nsss_buffer; int nsss_sf_counter; @@ -65,7 +65,7 @@ typedef struct SRSLTE_API { SRSLTE_API int srslte_ue_cellsearch_nbiot_init(srslte_ue_cellsearch_nbiot_t* q, uint32_t max_frames_total, - int(recv_callback)(void*, cf_t* [SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*), + int(recv_callback)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*), void* stream_handler); SRSLTE_API void srslte_ue_cellsearch_nbiot_free(srslte_ue_cellsearch_nbiot_t* q); diff --git a/lib/include/srslte/phy/ue/ue_mib.h b/lib/include/srslte/phy/ue/ue_mib.h index 59153d873..0f9f0f752 100644 --- a/lib/include/srslte/phy/ue/ue_mib.h +++ b/lib/include/srslte/phy/ue/ue_mib.h @@ -58,7 +58,7 @@ typedef struct SRSLTE_API { srslte_sync_t sfind; - cf_t* sf_symbols[SRSLTE_MAX_PORTS]; + cf_t* sf_symbols; srslte_ofdm_t fft; srslte_pbch_t pbch; @@ -73,9 +73,7 @@ typedef struct SRSLTE_API { uint32_t frame_cnt; } srslte_ue_mib_t; -SRSLTE_API int srslte_ue_mib_init(srslte_ue_mib_t *q, - cf_t *in_buffer[SRSLTE_MAX_PORTS], - uint32_t max_prb); +SRSLTE_API int srslte_ue_mib_init(srslte_ue_mib_t* q, cf_t* in_buffer, uint32_t max_prb); SRSLTE_API void srslte_ue_mib_free(srslte_ue_mib_t *q); @@ -97,15 +95,16 @@ SRSLTE_API int srslte_ue_mib_decode(srslte_ue_mib_t * q, */ typedef struct { srslte_ue_mib_t ue_mib; - srslte_ue_sync_t ue_sync; - cf_t *sf_buffer[SRSLTE_MAX_PORTS]; - uint32_t nof_rx_antennas; + srslte_ue_sync_t ue_sync; + cf_t* sf_buffer[SRSLTE_MAX_CHANNELS]; + uint32_t nof_rx_channels; } srslte_ue_mib_sync_t; -SRSLTE_API int srslte_ue_mib_sync_init_multi(srslte_ue_mib_sync_t *q, - int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t *), - uint32_t nof_rx_antennas, - void *stream_handler); +SRSLTE_API int +srslte_ue_mib_sync_init_multi(srslte_ue_mib_sync_t* q, + int(recv_callback)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*), + uint32_t nof_rx_channels, + void* stream_handler); SRSLTE_API void srslte_ue_mib_sync_free(srslte_ue_mib_sync_t *q); diff --git a/lib/include/srslte/phy/ue/ue_sync.h b/lib/include/srslte/phy/ue/ue_sync.h index d8a731345..5c1348f1c 100644 --- a/lib/include/srslte/phy/ue/ue_sync.h +++ b/lib/include/srslte/phy/ue/ue_sync.h @@ -74,7 +74,7 @@ typedef enum SRSLTE_API { SF_FIND, SF_TRACK} srslte_ue_sync_state_t; //#define MEASURE_EXEC_TIME -typedef int(ue_sync_recv_callback_t)(void*, cf_t * [SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*); +typedef int(ue_sync_recv_callback_t)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*); typedef struct SRSLTE_API { srslte_ue_sync_mode_t mode; @@ -88,8 +88,8 @@ typedef struct SRSLTE_API { uint32_t agc_period; int decimate; void *stream; - void *stream_single; - int (*recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*); + void *stream_single; + int (*recv_callback)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*); int (*recv_callback_single)(void*, void*, uint32_t, srslte_timestamp_t*); srslte_timestamp_t last_timestamp; @@ -159,27 +159,28 @@ SRSLTE_API int srslte_ue_sync_init_multi(srslte_ue_sync_t* q, uint32_t max_prb, bool search_cell, - int(recv_callback)(void*, cf_t * [SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*), + int(recv_callback)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*), uint32_t nof_rx_antennas, void* stream_handler); -SRSLTE_API int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, - uint32_t max_prb, - bool search_cell, - int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*), - uint32_t nof_rx_antennas, - void *stream_handler, - int decimate); - SRSLTE_API int -srslte_ue_sync_init_multi_decim_mode(srslte_ue_sync_t* q, - uint32_t max_prb, - bool search_cell, - int(recv_callback)(void*, cf_t* [SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*), - uint32_t nof_rx_antennas, - void* stream_handler, - int decimate, - srslte_ue_sync_mode_t mode); +srslte_ue_sync_init_multi_decim(srslte_ue_sync_t* q, + uint32_t max_prb, + bool search_cell, + int(recv_callback)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*), + uint32_t nof_rx_antennas, + void* stream_handler, + int decimate); + +SRSLTE_API int srslte_ue_sync_init_multi_decim_mode( + srslte_ue_sync_t* q, + uint32_t max_prb, + bool search_cell, + int(recv_callback)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*), + uint32_t nof_rx_antennas, + void* stream_handler, + int decimate, + srslte_ue_sync_mode_t mode); SRSLTE_API int srslte_ue_sync_init_file(srslte_ue_sync_t *q, uint32_t nof_prb, @@ -223,7 +224,7 @@ SRSLTE_API uint32_t srslte_ue_sync_sf_len(srslte_ue_sync_t* q); SRSLTE_API void srslte_ue_sync_set_agc_period(srslte_ue_sync_t* q, uint32_t period); SRSLTE_API int -srslte_ue_sync_zerocopy(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PORTS], const uint32_t max_num_samples); +srslte_ue_sync_zerocopy(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_CHANNELS], const uint32_t max_num_samples); SRSLTE_API void srslte_ue_sync_set_cfo_tol(srslte_ue_sync_t* q, float tol); @@ -268,15 +269,15 @@ SRSLTE_API void srslte_ue_sync_set_sfo_ema(srslte_ue_sync_t *q, SRSLTE_API void srslte_ue_sync_get_last_timestamp(srslte_ue_sync_t *q, srslte_timestamp_t *timestamp); -SRSLTE_API int srslte_ue_sync_run_find_pss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PORTS]); +SRSLTE_API int srslte_ue_sync_run_find_pss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_CHANNELS]); -SRSLTE_API int srslte_ue_sync_run_track_pss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PORTS]); +SRSLTE_API int srslte_ue_sync_run_track_pss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_CHANNELS]); SRSLTE_API int srslte_ue_sync_run_find_gnss_mode(srslte_ue_sync_t* q, - cf_t* input_buffer[SRSLTE_MAX_PORTS], + cf_t* input_buffer[SRSLTE_MAX_CHANNELS], const uint32_t max_num_samples); -SRSLTE_API int srslte_ue_sync_run_track_gnss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PORTS]); +SRSLTE_API int srslte_ue_sync_run_track_gnss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_CHANNELS]); SRSLTE_API int srslte_ue_sync_set_tti_from_timestamp(srslte_ue_sync_t* q, srslte_timestamp_t* rx_timestamp); diff --git a/lib/include/srslte/radio/radio.h b/lib/include/srslte/radio/radio.h index 674aaffd8..3c20c4186 100644 --- a/lib/include/srslte/radio/radio.h +++ b/lib/include/srslte/radio/radio.h @@ -21,8 +21,11 @@ #include +#include "radio_metrics.h" +#include "srslte/common/interfaces_common.h" #include "srslte/common/log_filter.h" #include "srslte/common/trace.h" +#include "srslte/interfaces/radio_interfaces.h" #include "srslte/phy/rf/rf.h" #include "srslte/srslte.h" @@ -31,146 +34,202 @@ namespace srslte { -/* Interface to the RF frontend. +/** + * Implemenation of the rf_buffer_interface for the current radio implementation which uses flat arrays. + * @see rf_buffer_interface + * @see radio + * */ -class radio +class rf_buffer_t : public rf_buffer_interface { public: - radio() : tr_local_time(1024 * 10), tr_usrp_time(1024 * 10), tr_tx_time(1024 * 10), tr_is_eob(1024 * 10), zeros(NULL) + /** + * Creates an object and allocates memory for nof_subframes_ assuming the + * largest system bandwidth + * @param nof_subframes_ Number of subframes to allocate + */ + rf_buffer_t(uint32_t nof_subframes_) + { + if (nof_subframes_ > 0) { + // Allocate buffers for an integer number of subframes + for (uint32_t i = 0; i < SRSLTE_MAX_CHANNELS; i++) { + sample_buffer[i] = srslte_vec_cf_malloc(nof_subframes_ * SRSLTE_SF_LEN_MAX); + srslte_vec_cf_zero(sample_buffer[i], SRSLTE_SF_LEN_MAX); + } + allocated = true; + nof_subframes = nof_subframes_; + } + } + /** + * Creates an object and sets the buffers to the flat array pointed by data. Note that data must + * contain up to SRSLTE_MAX_CHANNELS pointers + * @param data Flat array to use as initializer for the internal buffer pointers + */ + rf_buffer_t(cf_t* data[SRSLTE_MAX_CHANNELS]) { - bzero(&rf_device, sizeof(srslte_rf_t)); - bzero(&end_of_burst_time, sizeof(srslte_timestamp_t)); - zeros = (cf_t*)srslte_vec_malloc(burst_preamble_max_samples * sizeof(cf_t)); - bzero(zeros, burst_preamble_max_samples * sizeof(cf_t)); - - log_h = NULL; - - burst_preamble_sec = 0; - is_start_of_burst = false; - burst_preamble_samples = 0; - burst_preamble_time_rounded = 0; - - cur_tx_srate = 0; - tx_adv_sec = 0; - tx_adv_nsamples = 0; - tx_adv_auto = false; - tx_adv_negative = false; - tx_freq = 0; - rx_freq = 0; - freq_offset = 0; - trace_enabled = false; - tti = 0; - agc_enabled = false; - radio_is_streaming = false; - is_initialized = false; - continuous_tx = false; - }; - - ~radio() + for (uint32_t i = 0; i < SRSLTE_MAX_CHANNELS; i++) { + sample_buffer[i] = data[i]; + } + } + /** + * Creates an object from a single array pointer. The rest of the channel pointers will be left to NULL + * @param data Flat array to use as initializer for the internal buffer pointers + */ + rf_buffer_t(cf_t* data) { sample_buffer[0] = data; } + /** + * Default constructor leaves the internal pointers to NULL + */ + rf_buffer_t() {} + + /** + * The destructor will deallocate memory only if it was allocated passing nof_subframes > 0 + */ + ~rf_buffer_t() { - if (zeros) { - free(zeros); - zeros = NULL; + if (allocated) { + free_all(); + } + } + /** + * Overrides the = operator such that the lvalue internal buffers point to the pointers inside rvalue. + * If memory has already been allocated in the lvalue object, it will free it before pointing the + * buffers to the lvalue. + * After this operator, when the lvalue is destroyed no memory will be freed. + * @param other rvalue + * @return lvalue + */ + rf_buffer_t& operator=(const rf_buffer_t& other) + { + if (this == &other) { + return *this; + } + if (this->allocated) { + free_all(); + this->allocated = false; + } + for (int i = 0; i < SRSLTE_MAX_CHANNELS; i++) { + this->sample_buffer[i] = other.sample_buffer[i]; } + return *this; } + cf_t* get(uint32_t channel_idx) const override { return sample_buffer.at(channel_idx); } + void set(uint32_t channel_idx, cf_t* ptr) override { sample_buffer.at(channel_idx) = ptr; } + cf_t* get(uint32_t cc_idx, uint32_t port_idx, uint32_t nof_antennas) const override + { + return sample_buffer.at(cc_idx * nof_antennas + port_idx); + } + void set(uint32_t cc_idx, uint32_t port_idx, uint32_t nof_antennas, cf_t* ptr) override + { + sample_buffer.at(cc_idx * nof_antennas + port_idx) = ptr; + } + void** to_void() override { return (void**)sample_buffer.data(); } + cf_t** to_cf_t() override { return sample_buffer.data(); } + uint32_t size() override { return nof_subframes * SRSLTE_SF_LEN_MAX; } + +private: + std::array sample_buffer = {}; + bool allocated = false; + uint32_t nof_subframes = 0; + void free_all() + { + for (uint32_t i = 0; i < SRSLTE_MAX_CHANNELS; i++) { + if (sample_buffer[i]) { + free(sample_buffer[i]); + } + } + } +}; - bool init(log_filter* _log_h, const char* args = NULL, char* devname = NULL, uint32_t nof_channels = 1); - void stop(); - void reset(); - bool start_agc(bool tx_gain_same_rx = false); +/** + * 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 <= + * SRSLTE_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: + radio(srslte::log_filter* log_h); + radio(srslte::logger* logger_h); + virtual ~radio(); - void set_burst_preamble(double preamble_us); - void set_tx_adv(int nsamples); - void set_tx_adv_neg(bool tx_adv_is_neg); + int init(const rf_args_t& args_, phy_interface_radio* phy_); + void stop(); - bool is_continuous_tx(); - void set_continuous_tx(bool enable); - - void get_time(srslte_timestamp_t* now); - int synch_wait(); - void synch_issue(); - bool tx_single(cf_t* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); - bool tx(cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time); - void tx_end(); - bool get_is_start_of_burst(); - bool rx_now(cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t* rxd_time); - bool rx_at(cf_t* buffer, uint32_t nof_samples, srslte_timestamp_t rx_time); - - void set_tx_gain(float gain); - void set_rx_gain(float gain); - void set_tx_rx_gain_offset(float offset); - void set_rx_gain_th(float gain); - - void set_freq_offset(double freq); - void set_tx_freq(uint32_t chan, double freq); - void set_rx_freq(uint32_t chan, double freq); - - double get_freq_offset(); - double get_tx_freq(); - double get_rx_freq(); - - void set_tx_srate(double srate); - void set_rx_srate(double srate); - - float get_tx_gain(); - float get_rx_gain(); - srslte_rf_info_t* get_info(); - - float get_max_tx_power(); - float set_tx_power(float power); + // ==== PHY interface === + + // trx functions + void tx_end() override; + bool tx(rf_buffer_interface& buffer, const uint32_t& nof_samples, const srslte_timestamp_t& tx_time) override; + bool rx_now(rf_buffer_interface& buffer, const uint32_t& nof_samples, srslte_timestamp_t* 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 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; + + // 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; + srslte_rf_info_t* get_info() override; + + // Other functions + bool get_metrics(rf_metrics_t* metrics); float get_rssi(); bool has_rssi(); - - bool is_first_of_burst(); - - bool is_init(); - - void register_error_handler(srslte_rf_error_handler_t h); - -protected: - srslte_rf_t rf_device; - log_filter* log_h; - - const static uint32_t burst_preamble_max_samples = 13824; - double burst_preamble_sec; // Start of burst preamble time (off->on RF transition time) - srslte_timestamp_t end_of_burst_time; - bool is_start_of_burst; - uint32_t burst_preamble_samples; - double burst_preamble_time_rounded; // preamble time rounded to sample time - cf_t* zeros; - double cur_tx_srate; - - double tx_adv_sec; // Transmission time advance to compensate for antenna->timestamp delay - int tx_adv_nsamples; // Transmision time advance in number of samples + void get_time(srslte_timestamp_t* now); + + void handle_rf_msg(srslte_rf_error_t error); + static void rf_msg_callback(void* arg, srslte_rf_error_t error); + +private: + srslte_rf_t rf_device = {}; + srslte_rf_info_t rf_info = {}; + rf_metrics_t rf_metrics = {}; + log_filter log_local = {}; + log_filter* log_h = nullptr; + srslte::logger* logger = nullptr; + phy_interface_radio* phy = nullptr; + cf_t* zeros = nullptr; + + srslte_timestamp_t end_of_burst_time = {}; + bool is_start_of_burst = 0; + uint32_t tx_adv_nsamples = 0; + double tx_adv_sec = 0.0f; // 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.0f; + double cur_tx_srate = 0.0f; + uint32_t nof_antennas = 0; + uint32_t nof_channels = 0; // Define default values for known radios - bool tx_adv_auto; - bool tx_adv_negative; - constexpr static double uhd_default_burst_preamble_sec = 600 * 1e-6; - constexpr static double uhd_default_tx_adv_samples = 98; - constexpr static double uhd_default_tx_adv_offset_sec = 4 * 1e-6; + constexpr static double uhd_default_tx_adv_samples = 98; + constexpr static double uhd_default_tx_adv_offset_sec = 4 * 1e-6; - constexpr static double blade_default_burst_preamble_sec = 0.0; constexpr static double blade_default_tx_adv_samples = 27; constexpr static double blade_default_tx_adv_offset_sec = 1e-6; - double tx_freq, rx_freq, freq_offset; - - trace tr_local_time; - trace tr_usrp_time; - trace tr_tx_time; - trace tr_is_eob; - bool trace_enabled; - uint32_t tti; - bool agc_enabled; - - bool continuous_tx; - bool is_initialized; - bool radio_is_streaming; - - uint32_t saved_nof_channels; - char saved_args[128]; - char saved_devname[128]; + 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); }; } // namespace srslte diff --git a/lib/include/srslte/radio/radio_base.h b/lib/include/srslte/radio/radio_base.h deleted file mode 100644 index c016f5cef..000000000 --- a/lib/include/srslte/radio/radio_base.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2013-2019 Software Radio Systems Limited - * - * This file is part of srsLTE. - * - * srsLTE 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. - * - * srsLTE 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/. - * - */ - -/****************************************************************************** - * File: radio_base.h - * Description: Base class for all eNB/UE radios. - *****************************************************************************/ - -#ifndef SRSLTE_RADIO_BASE_H -#define SRSLTE_RADIO_BASE_H - -#include "srslte/common/interfaces_common.h" -#include "srslte/common/logger.h" -#include "srslte/interfaces/common_interfaces.h" -#include "srslte/radio/radio_metrics.h" - -namespace srslte { - -class radio_base -{ -public: - radio_base(srslte::logger* logger_){}; - virtual ~radio_base(){}; - - virtual std::string get_type() = 0; - - virtual int init(const rf_args_t& args_, phy_interface_radio* phy_) = 0; - virtual void stop() = 0; - - virtual bool get_metrics(rf_metrics_t* metrics) = 0; -}; - -} // namespace srslte - -#endif // SRSLTE_RADIO_BASE_H diff --git a/lib/include/srslte/radio/radio_multi.h b/lib/include/srslte/radio/radio_multi.h deleted file mode 100644 index 02c9fd31d..000000000 --- a/lib/include/srslte/radio/radio_multi.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2013-2019 Software Radio Systems Limited - * - * This file is part of srsLTE. - * - * srsLTE 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. - * - * srsLTE 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/. - * - */ - -/****************************************************************************** - * File: radio_multi.h - * Description: Class for using multiple srslte::radio's for both eNB/UE - *****************************************************************************/ - -#ifndef SRSLTE_RADIO_MULTI_H -#define SRSLTE_RADIO_MULTI_H - -#include "srslte/common/logger.h" -#include "srslte/interfaces/common_interfaces.h" -#include "srslte/phy/rf/rf.h" -#include "srslte/radio/radio.h" -#include "srslte/radio/radio_base.h" -#include "srslte/radio/radio_metrics.h" - -namespace srslte { - -class radio_multi : public radio_base, public radio_interface_phy -{ -public: - radio_multi(srslte::logger* logger_); - ~radio_multi() override; - - std::string get_type() override; - - int init(const rf_args_t& args_, phy_interface_radio* phy_); - - void stop() override; - - static void rf_msg(srslte_rf_error_t error); - void handle_rf_msg(srslte_rf_error_t error); - - bool get_metrics(rf_metrics_t* metrics) override; - - // radio_interface_phy - bool is_init() override - { - if (not radios.empty()) { - return radios.at(0)->is_init(); - } - return false; - } - void reset() override - { - if (not radios.empty()) { - radios.at(0)->reset(); - } - } - - bool is_continuous_tx() override - { - if (not radios.empty()) { - return radios.at(0)->is_continuous_tx(); - } - return false; - } - bool get_is_start_of_burst(const uint32_t& radio_idx) override - { - return radios.at(radio_idx)->get_is_start_of_burst(); - } - bool tx(const uint32_t& radio_idx, - cf_t* buffer[SRSLTE_MAX_PORTS], - const uint32_t& nof_samples, - const srslte_timestamp_t& tx_time) override - { - return radios.at(radio_idx)->tx(buffer, nof_samples, tx_time); - } - void tx_end() override - { - // Send Tx exd to all radios - for (auto& r : radios) { - r->tx_end(); - } - } - - bool rx_now(const uint32_t& radio_idx, - cf_t* buffer[SRSLTE_MAX_PORTS], - const uint32_t& nof_samples, - srslte_timestamp_t* rxd_time) override - { - return radios.at(radio_idx)->rx_now(buffer, nof_samples, rxd_time); - } - void set_rx_gain(const uint32_t& radio_idx, const float& gain) override { radios.at(radio_idx)->set_rx_gain(gain); } - void set_rx_gain_th(const float& gain) override { radios.at(0)->set_rx_gain_th(gain); } - float get_rx_gain(const uint32_t& radio_idx) override { return radios.at(radio_idx)->get_rx_gain(); } - void set_tx_freq(const uint32_t& radio_idx, const uint32_t& channel_idx, const double& freq) override - { - radios.at(radio_idx)->set_tx_freq(channel_idx, freq); - } - void set_rx_freq(const uint32_t& radio_idx, const uint32_t& channel_idx, const double& freq) override - { - radios.at(radio_idx)->set_rx_freq(channel_idx, freq); - } - double get_freq_offset() override { return radios.at(0)->get_freq_offset(); } - double get_tx_freq(const uint32_t& radio_idx) override { return radios.at(radio_idx)->get_tx_freq(); } - double get_rx_freq(const uint32_t& radio_idx) override { return radios.at(radio_idx)->get_rx_freq(); } - float get_max_tx_power() override { return args.tx_max_power; } - float get_tx_gain_offset() override { return args.tx_gain_offset; } - float get_rx_gain_offset() override { return args.rx_gain_offset; } - void set_tx_srate(const uint32_t& radio_idx, const double& srate) override - { - radios.at(radio_idx)->set_tx_srate(srate); - } - void set_rx_srate(const uint32_t& radio_idx, const double& srate) override - { - radios.at(radio_idx)->set_rx_srate(srate); - } - srslte_rf_info_t* get_info(const uint32_t& radio_idx) override - { - srslte_rf_info_t* ret = nullptr; - - if (radio_idx < radios.size()) { - ret = radios.at(radio_idx)->get_info(); - } - - return ret; - } - -protected: - rf_args_t args = {}; - - std::vector > radios; - - srslte::logger* logger = nullptr; - srslte::log_filter log; - bool running = false; - - srslte::rf_metrics_t rf_metrics = {}; - phy_interface_radio* phy = nullptr; -}; -} // namespace srslte - -#endif // SRSLTE_RADIO_MULTI_H diff --git a/lib/src/phy/channel/channel.cc b/lib/src/phy/channel/channel.cc index 598d72061..7000ca3cf 100644 --- a/lib/src/phy/channel/channel.cc +++ b/lib/src/phy/channel/channel.cc @@ -25,12 +25,20 @@ using namespace srslte; -channel::channel(const channel::args_t& channel_args, uint32_t _nof_ports) +channel::channel(const channel::args_t& channel_args, uint32_t _nof_channels) { int ret = SRSLTE_SUCCESS; uint32_t srate_max = (uint32_t)srslte_symbol_sz(SRSLTE_MAX_PRB) * 15000; uint32_t buffer_size = (uint32_t)SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB) * 5; // be safe, 5 Subframes + if (_nof_channels > SRSLTE_MAX_CHANNELS) { + fprintf(stderr, + "Error creating channel object: maximum number of channels exceeded (%d > %d)\n", + _nof_channels, + SRSLTE_MAX_CHANNELS); + return; + } + // Copy args args = channel_args; @@ -41,8 +49,8 @@ channel::channel(const channel::args_t& channel_args, uint32_t _nof_ports) ret = SRSLTE_ERROR; } - nof_ports = _nof_ports; - for (uint32_t i = 0; i < nof_ports; i++) { + nof_channels = _nof_channels; + for (uint32_t i = 0; i < nof_channels; i++) { // Create fading channel if (channel_args.fading_enable && !channel_args.fading_model.empty() && channel_args.fading_model != "none" && ret == SRSLTE_SUCCESS) { @@ -103,7 +111,7 @@ channel::~channel() free(rlf); } - for (uint32_t i = 0; i < nof_ports; i++) { + for (uint32_t i = 0; i < nof_channels; i++) { if (fading[i]) { srslte_channel_fading_free(fading[i]); free(fading[i]); @@ -121,12 +129,15 @@ void channel::set_logger(log_filter* _log_h) log_h = _log_h; } -void channel::run(cf_t* in[SRSLTE_MAX_PORTS], cf_t* out[SRSLTE_MAX_PORTS], uint32_t len, const srslte_timestamp_t& t) +void channel::run(cf_t* in[SRSLTE_MAX_CHANNELS], + cf_t* out[SRSLTE_MAX_CHANNELS], + uint32_t len, + const srslte_timestamp_t& t) { // check input pointers if (in != nullptr && out != nullptr) { if (current_srate) { - for (uint32_t i = 0; i < nof_ports; i++) { + for (uint32_t i = 0; i < nof_channels; i++) { // Check buffers are not null if (in[i] != nullptr && out[i] != nullptr) { // Copy input buffer @@ -175,7 +186,7 @@ void channel::run(cf_t* in[SRSLTE_MAX_PORTS], cf_t* out[SRSLTE_MAX_PORTS], uint3 } } else { - for (uint32_t i = 0; i < nof_ports; i++) { + for (uint32_t i = 0; i < nof_channels; i++) { // Check buffers are not null if (in[i] != nullptr && out[i] != nullptr && in[i] != out[i]) { memcpy(out[i], in[i], sizeof(cf_t) * len); @@ -188,7 +199,7 @@ void channel::run(cf_t* in[SRSLTE_MAX_PORTS], cf_t* out[SRSLTE_MAX_PORTS], uint3 void channel::set_srate(uint32_t srate) { if (current_srate != srate) { - for (uint32_t i = 0; i < nof_ports; i++) { + for (uint32_t i = 0; i < nof_channels; i++) { if (fading[i]) { srslte_channel_fading_free(fading[i]); diff --git a/lib/src/phy/rf/rf_blade_imp.c b/lib/src/phy/rf/rf_blade_imp.c index 7c7d48293..3978dbacc 100644 --- a/lib/src/phy/rf/rf_blade_imp.c +++ b/lib/src/phy/rf/rf_blade_imp.c @@ -40,16 +40,18 @@ typedef struct { srslte_rf_info_t info; } rf_blade_handler_t; -static srslte_rf_error_handler_t blade_error_handler = NULL; +static srslte_rf_error_handler_t blade_error_handler = NULL; +static void* blade_error_handler_arg = NULL; void rf_blade_suppress_stdout(UNUSED void* h) { bladerf_log_set_verbosity(BLADERF_LOG_LEVEL_SILENT); } -void rf_blade_register_error_handler(UNUSED void* ptr, srslte_rf_error_handler_t new_handler) +void rf_blade_register_error_handler(UNUSED void* ptr, srslte_rf_error_handler_t new_handler, void* arg) { - blade_error_handler = new_handler; + blade_error_handler = new_handler; + blade_error_handler_arg = arg; } const unsigned int num_buffers = 256; @@ -436,7 +438,7 @@ int rf_blade_recv_with_time(void* h, srslte_rf_error_t error; error.opt = meta.actual_count; error.type = SRSLTE_RF_ERROR_OVERFLOW; - blade_error_handler(error); + blade_error_handler(blade_error_handler_arg, error); } else { /*ERROR("Overrun detected in scheduled RX. " "%u valid samples were read.\n\n", meta.actual_count);*/ @@ -509,7 +511,7 @@ int rf_blade_send_timed(void* h, if (status == BLADERF_ERR_TIME_PAST) { if (blade_error_handler) { error.type = SRSLTE_RF_ERROR_LATE; - blade_error_handler(error); + blade_error_handler(blade_error_handler_arg, error); } else { ERROR("TX failed: %s\n", bladerf_strerror(status)); } @@ -519,7 +521,7 @@ int rf_blade_send_timed(void* h, } else if (meta.status == BLADERF_META_STATUS_UNDERRUN) { if (blade_error_handler) { error.type = SRSLTE_RF_ERROR_UNDERFLOW; - blade_error_handler(error); + blade_error_handler(blade_error_handler_arg, error); } else { ERROR("TX warning: underflow detected.\n"); } diff --git a/lib/src/phy/rf/rf_blade_imp.h b/lib/src/phy/rf/rf_blade_imp.h index 0a4564e81..271ee80c1 100644 --- a/lib/src/phy/rf/rf_blade_imp.h +++ b/lib/src/phy/rf/rf_blade_imp.h @@ -58,7 +58,7 @@ SRSLTE_API srslte_rf_info_t* rf_blade_get_info(void* h); SRSLTE_API void rf_blade_suppress_stdout(void* h); -SRSLTE_API void rf_blade_register_error_handler(void* h, srslte_rf_error_handler_t error_handler); +SRSLTE_API void rf_blade_register_error_handler(void* h, srslte_rf_error_handler_t error_handler, void* arg); SRSLTE_API double rf_blade_set_rx_freq(void* h, uint32_t ch, double freq); diff --git a/lib/src/phy/rf/rf_dev.h b/lib/src/phy/rf/rf_dev.h index 8fa76caf2..dbed82150 100644 --- a/lib/src/phy/rf/rf_dev.h +++ b/lib/src/phy/rf/rf_dev.h @@ -32,7 +32,7 @@ typedef struct { bool (*srslte_rf_has_rssi)(void* h); float (*srslte_rf_get_rssi)(void* h); void (*srslte_rf_suppress_stdout)(void* h); - void (*srslte_rf_register_error_handler)(void* h, srslte_rf_error_handler_t error_handler); + void (*srslte_rf_register_error_handler)(void* h, srslte_rf_error_handler_t error_handler, void* arg); int (*srslte_rf_open)(char* args, void** h); int (*srslte_rf_open_multi)(char* args, void** h, uint32_t nof_channels); int (*srslte_rf_close)(void* h); @@ -69,7 +69,7 @@ typedef struct { bool is_start_of_burst, bool is_end_of_burst); int (*srslte_rf_send_timed_multi)(void* h, - void* data[4], + void** data, int nsamples, time_t secs, double frac_secs, diff --git a/lib/src/phy/rf/rf_imp.c b/lib/src/phy/rf/rf_imp.c index 460505b64..6b57fc4ea 100644 --- a/lib/src/phy/rf/rf_imp.c +++ b/lib/src/phy/rf/rf_imp.c @@ -166,9 +166,9 @@ void srslte_rf_suppress_stdout(srslte_rf_t* rf) ((rf_dev_t*)rf->dev)->srslte_rf_suppress_stdout(rf->handler); } -void srslte_rf_register_error_handler(srslte_rf_t* rf, srslte_rf_error_handler_t error_handler) +void srslte_rf_register_error_handler(srslte_rf_t* rf, srslte_rf_error_handler_t error_handler, void* arg) { - ((rf_dev_t*)rf->dev)->srslte_rf_register_error_handler(rf->handler, error_handler); + ((rf_dev_t*)rf->dev)->srslte_rf_register_error_handler(rf->handler, error_handler, arg); } int srslte_rf_open(srslte_rf_t* h, char* args) @@ -306,7 +306,7 @@ int srslte_rf_send_timed3(srslte_rf_t* rf, } int srslte_rf_send_timed_multi(srslte_rf_t* rf, - void* data[4], + void** data, int nsamples, time_t secs, double frac_secs, @@ -321,7 +321,7 @@ int srslte_rf_send_timed_multi(srslte_rf_t* rf, } int srslte_rf_send_multi(srslte_rf_t* rf, - void* data[4], + void** data, int nsamples, bool blocking, bool is_start_of_burst, diff --git a/lib/src/phy/rf/rf_soapy_imp.c b/lib/src/phy/rf/rf_soapy_imp.c index 7a8b0a3bd..4542ab20c 100644 --- a/lib/src/phy/rf/rf_soapy_imp.c +++ b/lib/src/phy/rf/rf_soapy_imp.c @@ -59,6 +59,7 @@ typedef struct { size_t num_tx_channels; srslte_rf_error_handler_t soapy_error_handler; + void* soapy_error_handler_arg; bool async_thread_running; pthread_t async_thread; @@ -79,7 +80,7 @@ static void log_overflow(rf_soapy_handler_t* h) srslte_rf_error_t error; bzero(&error, sizeof(srslte_rf_error_t)); error.type = SRSLTE_RF_ERROR_OVERFLOW; - h->soapy_error_handler(error); + h->soapy_error_handler(h->soapy_error_handler_arg, error); } else { h->num_overflows++; } @@ -92,7 +93,7 @@ static void log_late(rf_soapy_handler_t* h, bool is_rx) bzero(&error, sizeof(srslte_rf_error_t)); error.opt = is_rx ? 1 : 0; error.type = SRSLTE_RF_ERROR_LATE; - h->soapy_error_handler(error); + h->soapy_error_handler(h->soapy_error_handler_arg, error); } else { h->num_lates++; } @@ -104,7 +105,7 @@ static void log_underflow(rf_soapy_handler_t* h) srslte_rf_error_t error; bzero(&error, sizeof(srslte_rf_error_t)); error.type = SRSLTE_RF_ERROR_UNDERFLOW; - h->soapy_error_handler(error); + h->soapy_error_handler(h->soapy_error_handler_arg, error); } else { h->num_underflows++; } @@ -175,10 +176,11 @@ void rf_soapy_suppress_stdout(void* h) // not supported } -void rf_soapy_register_error_handler(void* h, srslte_rf_error_handler_t new_handler) +void rf_soapy_register_error_handler(void* h, srslte_rf_error_handler_t new_handler, void* arg) { - rf_soapy_handler_t* handler = (rf_soapy_handler_t*)h; - handler->soapy_error_handler = new_handler; + rf_soapy_handler_t* handler = (rf_soapy_handler_t*)h; + handler->soapy_error_handler = new_handler; + handler->soapy_error_handler_arg = arg; } const char* rf_soapy_devname(void* h) diff --git a/lib/src/phy/rf/rf_soapy_imp.h b/lib/src/phy/rf/rf_soapy_imp.h index 453b10e5f..7cff81774 100644 --- a/lib/src/phy/rf/rf_soapy_imp.h +++ b/lib/src/phy/rf/rf_soapy_imp.h @@ -63,7 +63,7 @@ SRSLTE_API srslte_rf_info_t* rf_soapy_get_info(void* h); SRSLTE_API void rf_soapy_suppress_stdout(void* h); -SRSLTE_API void rf_soapy_register_error_handler(void* h, srslte_rf_error_handler_t error_handler); +SRSLTE_API void rf_soapy_register_error_handler(void* h, srslte_rf_error_handler_t error_handler, void* arg); SRSLTE_API double rf_soapy_set_rx_freq(void* h, uint32_t ch, double freq); diff --git a/lib/src/phy/rf/rf_uhd_imp.c b/lib/src/phy/rf/rf_uhd_imp.c index 562f3ef28..d6419a21e 100644 --- a/lib/src/phy/rf/rf_uhd_imp.c +++ b/lib/src/phy/rf/rf_uhd_imp.c @@ -57,6 +57,7 @@ typedef struct { int nof_tx_channels; srslte_rf_error_handler_t uhd_error_handler; + void* uhd_error_handler_arg; float current_master_clock; @@ -71,7 +72,7 @@ void suppress_handler(const char* x) // do nothing } -cf_t zero_mem[64 * 1024]; +static cf_t zero_mem[64 * 1024]; static void log_overflow(rf_uhd_handler_t* h) { @@ -79,7 +80,7 @@ static void log_overflow(rf_uhd_handler_t* h) srslte_rf_error_t error; bzero(&error, sizeof(srslte_rf_error_t)); error.type = SRSLTE_RF_ERROR_OVERFLOW; - h->uhd_error_handler(error); + h->uhd_error_handler(h->uhd_error_handler_arg, error); } } @@ -90,7 +91,7 @@ static void log_late(rf_uhd_handler_t* h, bool is_rx) bzero(&error, sizeof(srslte_rf_error_t)); error.opt = is_rx ? 1 : 0; error.type = SRSLTE_RF_ERROR_LATE; - h->uhd_error_handler(error); + h->uhd_error_handler(h->uhd_error_handler_arg, error); } } @@ -101,7 +102,7 @@ static void log_underflow(rf_uhd_handler_t* h) srslte_rf_error_t error; bzero(&error, sizeof(srslte_rf_error_t)); error.type = SRSLTE_RF_ERROR_UNDERFLOW; - h->uhd_error_handler(error); + h->uhd_error_handler(h->uhd_error_handler_arg, error); } } #endif @@ -116,7 +117,7 @@ static void log_rx_error(rf_uhd_handler_t* h) srslte_rf_error_t error; bzero(&error, sizeof(srslte_rf_error_t)); error.type = SRSLTE_RF_ERROR_RX; - h->uhd_error_handler(error); + h->uhd_error_handler(h->uhd_error_handler_arg, error); } } @@ -155,10 +156,11 @@ void rf_uhd_suppress_stdout(void* h) rf_uhd_register_msg_handler_c(suppress_handler); } -void rf_uhd_register_error_handler(void* h, srslte_rf_error_handler_t new_handler) +void rf_uhd_register_error_handler(void* h, srslte_rf_error_handler_t new_handler, void* arg) { - rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h; - handler->uhd_error_handler = new_handler; + rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h; + handler->uhd_error_handler = new_handler; + handler->uhd_error_handler_arg = arg; } static bool find_string(uhd_string_vector_handle h, const char* str) @@ -351,9 +353,10 @@ int rf_uhd_stop_rx_stream(void* h) void rf_uhd_flush_buffer(void* h) { int n; - cf_t tmp1[1024]; - cf_t tmp2[1024]; - void* data[2] = {tmp1, tmp2}; + void* data[SRSLTE_MAX_CHANNELS] = {}; + for (int i = 0; i < SRSLTE_MAX_CHANNELS; i++) { + data[i] = zero_mem; + } do { n = rf_uhd_recv_with_time_multi(h, data, 1024, 0, NULL, NULL); } while (n > 0); @@ -404,11 +407,20 @@ int rf_uhd_open_multi(char* args, void** h, uint32_t nof_channels) if (h) { *h = NULL; + if (nof_channels > SRSLTE_MAX_CHANNELS) { + fprintf(stderr, + "Error opening UHD: maximum number of channels exceeded (%d>%d)\n", + nof_channels, + SRSLTE_MAX_CHANNELS); + return SRSLTE_ERROR; + } + rf_uhd_handler_t* handler = (rf_uhd_handler_t*)malloc(sizeof(rf_uhd_handler_t)); if (!handler) { perror("malloc"); - return -1; + return SRSLTE_ERROR; } + bzero(handler, sizeof(rf_uhd_handler_t)); *h = handler; @@ -471,7 +483,7 @@ int rf_uhd_open_multi(char* args, void** h, uint32_t nof_channels) /* Do nothing */ } else if (strstr(args, "otw_format=")) { ERROR("Wrong over the wire format. Valid formats: sc12, sc16\n"); - return -1; + return SRSLTE_ERROR; } // Set transmitter subdevice spec string @@ -555,12 +567,12 @@ int rf_uhd_open_multi(char* args, void** h, uint32_t nof_channels) uhd_string_vector_free(&devices_str); /* Create UHD handler */ - printf("Opening USRP with args: %s\n", args); + printf("Opening USRP channels=%d, args: %s\n", nof_channels, args); uhd_error error = uhd_usrp_make(&handler->usrp, args); if (error) { fprintf(stderr, "Error opening UHD: code %d\n", error); free(handler); - return -1; + return SRSLTE_ERROR; } /* Set transmitter subdev spec if specified */ @@ -630,7 +642,10 @@ int rf_uhd_open_multi(char* args, void** h, uint32_t nof_channels) handler->has_rssi = get_has_rssi(handler); - size_t channel[4] = {0, 1, 2, 3}; + size_t channel[SRSLTE_MAX_CHANNELS] = {}; + for (int i = 0; i < SRSLTE_MAX_CHANNELS; i++) { + channel[i] = i; + } uhd_stream_args_t stream_args = { .cpu_format = "fc32", .otw_format = otw_format, @@ -658,13 +673,13 @@ int rf_uhd_open_multi(char* args, void** h, uint32_t nof_channels) error = uhd_usrp_get_rx_stream(handler->usrp, &stream_args, handler->rx_stream); if (error) { ERROR("Error opening RX stream: %d\n", error); - return -1; + return SRSLTE_ERROR; } uhd_tx_streamer_make(&handler->tx_stream); error = uhd_usrp_get_tx_stream(handler->usrp, &stream_args, handler->tx_stream); if (error) { ERROR("Error opening TX stream: %d\n", error); - return -1; + return SRSLTE_ERROR; } uhd_rx_streamer_max_num_samps(handler->rx_stream, &handler->rx_nof_samples); @@ -698,7 +713,7 @@ int rf_uhd_open_multi(char* args, void** h, uint32_t nof_channels) handler->async_thread_running = true; if (pthread_create(&handler->async_thread, NULL, async_thread, handler)) { perror("pthread_create"); - return -1; + return SRSLTE_ERROR; } } #endif @@ -931,7 +946,7 @@ int rf_uhd_recv_with_time_multi(void* h, int trials = 0; if (blocking) { while (rxd_samples_total < nsamples && trials < 100) { - void* buffs_ptr[4]; + void* buffs_ptr[SRSLTE_MAX_CHANNELS] = {}; for (int i = 0; i < handler->nof_rx_channels; i++) { cf_t* data_c = (cf_t*)data[i]; buffs_ptr[i] = &data_c[rxd_samples_total]; @@ -1000,7 +1015,7 @@ int rf_uhd_send_timed(void* h, } int rf_uhd_send_timed_multi(void* h, - void* data[4], + void** data, int nsamples, time_t secs, double frac_secs, @@ -1027,8 +1042,8 @@ int rf_uhd_send_timed_multi(void* h, uhd_tx_metadata_set_time_spec(&handler->tx_md, secs, frac_secs); } int n = 0; - cf_t* data_c[4]; - for (int i = 0; i < 4; i++) { + cf_t* data_c[SRSLTE_MAX_CHANNELS] = {}; + for (int i = 0; i < SRSLTE_MAX_CHANNELS; i++) { data_c[i] = data[i] ? data[i] : zero_mem; } do { @@ -1049,8 +1064,8 @@ int rf_uhd_send_timed_multi(void* h, uhd_tx_metadata_set_end(&handler->tx_md, is_end_of_burst); } - const void* buffs_ptr[4]; - for (int i = 0; i < 4; i++) { + const void* buffs_ptr[SRSLTE_MAX_CHANNELS] = {}; + for (int i = 0; i < SRSLTE_MAX_CHANNELS; i++) { void* buff = (void*)&data_c[i][n]; buffs_ptr[i] = buff; } @@ -1070,8 +1085,8 @@ int rf_uhd_send_timed_multi(void* h, } else { - const void* buffs_ptr[4]; - for (int i = 0; i < 4; i++) { + const void* buffs_ptr[SRSLTE_MAX_CHANNELS] = {}; + for (int i = 0; i < SRSLTE_MAX_CHANNELS; i++) { buffs_ptr[i] = data[i]; } uhd_tx_metadata_set_has_time_spec(&handler->tx_md, is_start_of_burst); diff --git a/lib/src/phy/rf/rf_uhd_imp.h b/lib/src/phy/rf/rf_uhd_imp.h index d71dd6ee7..9e3018d7a 100644 --- a/lib/src/phy/rf/rf_uhd_imp.h +++ b/lib/src/phy/rf/rf_uhd_imp.h @@ -63,7 +63,7 @@ SRSLTE_API srslte_rf_info_t* rf_uhd_get_info(void* h); SRSLTE_API void rf_uhd_suppress_stdout(void* h); -SRSLTE_API void rf_uhd_register_error_handler(void* h, srslte_rf_error_handler_t error_handler); +SRSLTE_API void rf_uhd_register_error_handler(void* h, srslte_rf_error_handler_t error_handler, void* arg); SRSLTE_API double rf_uhd_set_rx_freq(void* h, uint32_t ch, double freq); @@ -94,7 +94,7 @@ SRSLTE_API int rf_uhd_send_timed(void* h, bool is_end_of_burst); SRSLTE_API int rf_uhd_send_timed_multi(void* h, - void* data[SRSLTE_MAX_PORTS], + void** data, int nsamples, time_t secs, double frac_secs, diff --git a/lib/src/phy/rf/rf_utils.c b/lib/src/phy/rf/rf_utils.c index b3a0c565b..37c61d4b9 100644 --- a/lib/src/phy/rf/rf_utils.c +++ b/lib/src/phy/rf/rf_utils.c @@ -79,11 +79,11 @@ free_and_exit: return ret; } -int srslte_rf_recv_wrapper_cs(void* h, cf_t* data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t* t) +int srslte_rf_recv_wrapper_cs(void* h, cf_t* data[SRSLTE_MAX_CHANNELS], uint32_t nsamples, srslte_timestamp_t* t) { DEBUG(" ---- Receive %d samples ---- \n", nsamples); - void* ptr[SRSLTE_MAX_PORTS]; - for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + void* ptr[SRSLTE_MAX_CHANNELS]; + for (int i = 0; i < SRSLTE_MAX_CHANNELS; i++) { ptr[i] = data[i]; } return srslte_rf_recv_with_time_multi(h, ptr, nsamples, 1, NULL, NULL); @@ -98,15 +98,16 @@ static SRSLTE_AGC_CALLBACK(srslte_rf_set_rx_gain_wrapper) * Return 1 if the MIB is decoded, 0 if not or -1 on error. */ int rf_mib_decoder(srslte_rf_t* rf, - uint32_t nof_rx_antennas, + uint32_t nof_rx_channels, cell_search_cfg_t* config, srslte_cell_t* cell, float* cfo) { int ret = SRSLTE_ERROR; srslte_ue_mib_sync_t ue_mib; - uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; - if (srslte_ue_mib_sync_init_multi(&ue_mib, srslte_rf_recv_wrapper_cs, nof_rx_antennas, (void*)rf)) { + uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN] = {}; + + if (srslte_ue_mib_sync_init_multi(&ue_mib, srslte_rf_recv_wrapper_cs, nof_rx_channels, (void*)rf)) { fprintf(stderr, "Error initiating srslte_ue_mib_sync\n"); goto clean_exit; } @@ -157,7 +158,7 @@ clean_exit: /** This function is simply a wrapper to the ue_cell_search module for rf devices */ int rf_cell_search(srslte_rf_t* rf, - uint32_t nof_rx_antennas, + uint32_t nof_rx_channels, cell_search_cfg_t* config, int force_N_id_2, srslte_cell_t* cell, @@ -170,7 +171,7 @@ int rf_cell_search(srslte_rf_t* rf, bzero(found_cells, 3 * sizeof(srslte_ue_cellsearch_result_t)); if (srslte_ue_cellsearch_init_multi( - &cs, config->max_frames_pss, srslte_rf_recv_wrapper_cs, nof_rx_antennas, (void*)rf)) { + &cs, config->max_frames_pss, srslte_rf_recv_wrapper_cs, nof_rx_channels, (void*)rf)) { fprintf(stderr, "Error initiating UE cell detect\n"); return SRSLTE_ERROR; } @@ -245,7 +246,7 @@ int rf_cell_search(srslte_rf_t* rf, * -1 on error */ int rf_search_and_decode_mib(srslte_rf_t* rf, - uint32_t nof_rx_antennas, + uint32_t nof_rx_channels, cell_search_cfg_t* config, int force_N_id_2, srslte_cell_t* cell, @@ -254,10 +255,10 @@ int rf_search_and_decode_mib(srslte_rf_t* rf, int ret = SRSLTE_ERROR; printf("Searching for cell...\n"); - ret = rf_cell_search(rf, nof_rx_antennas, config, force_N_id_2, cell, cfo); + ret = rf_cell_search(rf, nof_rx_channels, config, force_N_id_2, cell, cfo); if (ret > 0) { printf("Decoding PBCH for cell %d (N_id_2=%d)\n", cell->id, cell->id % 3); - ret = rf_mib_decoder(rf, nof_rx_antennas, config, cell, cfo); + ret = rf_mib_decoder(rf, nof_rx_channels, config, cell, cfo); if (ret < 0) { ERROR("Could not decode PBCH from CELL ID %d\n", cell->id); return SRSLTE_ERROR; diff --git a/lib/src/phy/rf/rf_zmq_imp.c b/lib/src/phy/rf/rf_zmq_imp.c index 2f8bdcdbc..783390971 100644 --- a/lib/src/phy/rf/rf_zmq_imp.c +++ b/lib/src/phy/rf/rf_zmq_imp.c @@ -42,21 +42,21 @@ typedef struct { uint32_t base_srate; uint32_t decim_factor; // decimation factor between base_srate used on transport on radio's rate double rx_gain; - uint32_t tx_freq_mhz[SRSLTE_MAX_PORTS]; - uint32_t rx_freq_mhz[SRSLTE_MAX_PORTS]; + uint32_t tx_freq_mhz[SRSLTE_MAX_CHANNELS]; + uint32_t rx_freq_mhz[SRSLTE_MAX_CHANNELS]; bool tx_used; // Server void* context; - rf_zmq_tx_t transmitter[SRSLTE_MAX_PORTS]; - rf_zmq_rx_t receiver[SRSLTE_MAX_PORTS]; + rf_zmq_tx_t transmitter[SRSLTE_MAX_CHANNELS]; + rf_zmq_rx_t receiver[SRSLTE_MAX_CHANNELS]; char rx_port[PARAM_LEN]; char tx_port[PARAM_LEN]; char id[PARAM_LEN_SHORT]; // Various sample buffers - cf_t* buffer_decimation[SRSLTE_MAX_PORTS]; + cf_t* buffer_decimation[SRSLTE_MAX_CHANNELS]; cf_t* buffer_tx; // Rx timestamp @@ -154,7 +154,7 @@ void rf_zmq_suppress_stdout(void* h) // do nothing } -void rf_zmq_register_error_handler(void* h, srslte_rf_error_handler_t new_handler) +void rf_zmq_register_error_handler(void* h, srslte_rf_error_handler_t new_handler, void* arg) { // do nothing } @@ -211,7 +211,7 @@ static inline int parse_double(const char* args, const char* config_arg, double* int rf_zmq_open_multi(char* args, void** h, uint32_t nof_channels) { int ret = SRSLTE_ERROR; - if (h) { + if (h && nof_channels < SRSLTE_MAX_CHANNELS) { *h = NULL; rf_zmq_handler_t* handler = (rf_zmq_handler_t*)malloc(sizeof(rf_zmq_handler_t)); @@ -724,7 +724,7 @@ int rf_zmq_recv_with_time_multi(void* h, // Map ports to data buffers according to the selected frequencies pthread_mutex_lock(&handler->rx_config_mutex); - cf_t* buffers[SRSLTE_MAX_PORTS] = {}; // Buffer pointers, NULL if unmatched + cf_t* buffers[SRSLTE_MAX_CHANNELS] = {}; // Buffer pointers, NULL if unmatched for (uint32_t i = 0; i < handler->nof_channels; i++) { bool mapped = false; @@ -798,7 +798,7 @@ int rf_zmq_recv_with_time_multi(void* h, // copy from rx buffer as many samples as requested into provided buffer bool completed = false; - int32_t count[SRSLTE_MAX_PORTS] = {}; + int32_t count[SRSLTE_MAX_CHANNELS] = {}; while (!completed) { uint32_t completed_count = 0; @@ -933,7 +933,7 @@ int rf_zmq_send_timed_multi(void* h, // Map ports to data buffers according to the selected frequencies pthread_mutex_lock(&handler->tx_config_mutex); - cf_t* buffers[SRSLTE_MAX_PORTS] = {}; // Buffer pointers, NULL if unmatched + cf_t* buffers[SRSLTE_MAX_CHANNELS] = {}; // Buffer pointers, NULL if unmatched for (uint32_t i = 0; i < handler->nof_channels; i++) { bool mapped = false; diff --git a/lib/src/phy/rf/rf_zmq_imp.h b/lib/src/phy/rf/rf_zmq_imp.h index 1fab6540f..a19ff3c77 100644 --- a/lib/src/phy/rf/rf_zmq_imp.h +++ b/lib/src/phy/rf/rf_zmq_imp.h @@ -61,7 +61,7 @@ SRSLTE_API srslte_rf_info_t* rf_zmq_get_info(void* h); SRSLTE_API void rf_zmq_suppress_stdout(void* h); -SRSLTE_API void rf_zmq_register_error_handler(void* h, srslte_rf_error_handler_t error_handler); +SRSLTE_API void rf_zmq_register_error_handler(void* h, srslte_rf_error_handler_t error_handler, void* arg); SRSLTE_API double rf_zmq_set_rx_freq(void* h, uint32_t ch, double freq); diff --git a/lib/src/phy/ue/ue_cell_search.c b/lib/src/phy/ue/ue_cell_search.c index 5241d4c8f..fa370bb2f 100644 --- a/lib/src/phy/ue/ue_cell_search.c +++ b/lib/src/phy/ue/ue_cell_search.c @@ -60,7 +60,7 @@ int srslte_ue_cellsearch_init(srslte_ue_cellsearch_t* q, goto clean_exit; } - for (int p = 0; p < SRSLTE_MAX_PORTS; p++) { + for (int p = 0; p < SRSLTE_MAX_CHANNELS; p++) { q->sf_buffer[p] = NULL; } q->sf_buffer[0] = srslte_vec_cf_malloc(CELL_SEARCH_BUFFER_MAX_SAMPLES); @@ -95,15 +95,16 @@ clean_exit: return ret; } -int srslte_ue_cellsearch_init_multi(srslte_ue_cellsearch_t* q, - uint32_t max_frames, - int(recv_callback)(void*, cf_t * [SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*), - uint32_t nof_rx_antennas, - void* stream_handler) +int srslte_ue_cellsearch_init_multi( + srslte_ue_cellsearch_t* q, + uint32_t max_frames, + int(recv_callback)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*), + uint32_t nof_rx_antennas, + void* stream_handler) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q != NULL && nof_rx_antennas > 0) { + if (q != NULL && nof_rx_antennas < SRSLTE_MAX_CHANNELS) { ret = SRSLTE_ERROR; srslte_cell_t cell; diff --git a/lib/src/phy/ue/ue_mib.c b/lib/src/phy/ue/ue_mib.c index c8d1f0e6a..e45889be6 100644 --- a/lib/src/phy/ue/ue_mib.c +++ b/lib/src/phy/ue/ue_mib.c @@ -33,7 +33,7 @@ #define MIB_BUFFER_MAX_SAMPLES (3 * SRSLTE_SF_LEN_PRB(SRSLTE_UE_MIB_NOF_PRB)) -int srslte_ue_mib_init(srslte_ue_mib_t* q, cf_t* in_buffer[SRSLTE_MAX_PORTS], uint32_t max_prb) +int srslte_ue_mib_init(srslte_ue_mib_t* q, cf_t* in_buffer, uint32_t max_prb) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -47,13 +47,13 @@ int srslte_ue_mib_init(srslte_ue_mib_t* q, cf_t* in_buffer[SRSLTE_MAX_PORTS], ui goto clean_exit; } - q->sf_symbols[0] = srslte_vec_malloc(SRSLTE_SF_LEN_RE(max_prb, SRSLTE_CP_NORM) * sizeof(cf_t)); - if (!q->sf_symbols[0]) { + q->sf_symbols = srslte_vec_cf_malloc(SRSLTE_SF_LEN_RE(max_prb, SRSLTE_CP_NORM)); + if (!q->sf_symbols) { perror("malloc"); goto clean_exit; } - if (srslte_ofdm_rx_init(&q->fft, SRSLTE_CP_NORM, in_buffer[0], q->sf_symbols[0], max_prb)) { + if (srslte_ofdm_rx_init(&q->fft, SRSLTE_CP_NORM, in_buffer, q->sf_symbols, max_prb)) { ERROR("Error initializing FFT\n"); goto clean_exit; } @@ -79,8 +79,8 @@ clean_exit: void srslte_ue_mib_free(srslte_ue_mib_t* q) { - if (q->sf_symbols[0]) { - free(q->sf_symbols[0]); + if (q->sf_symbols) { + free(q->sf_symbols); } srslte_sync_free(&q->sfind); srslte_chest_dl_res_free(&q->chest_res); @@ -140,8 +140,12 @@ int srslte_ue_mib_decode(srslte_ue_mib_t* q, srslte_dl_sf_cfg_t sf_cfg; ZERO_OBJECT(sf_cfg); + // Current MIB decoder implementation uses a single antenna + cf_t* sf_buffer[SRSLTE_MAX_PORTS] = {}; + sf_buffer[0] = q->sf_symbols; + /* Get channel estimates of sf idx #0 for each port */ - ret = srslte_chest_dl_estimate(&q->chest, &sf_cfg, q->sf_symbols, &q->chest_res); + ret = srslte_chest_dl_estimate(&q->chest, &sf_cfg, sf_buffer, &q->chest_res); if (ret < 0) { return SRSLTE_ERROR; } @@ -152,7 +156,7 @@ int srslte_ue_mib_decode(srslte_ue_mib_t* q, } /* Decode PBCH */ - ret = srslte_pbch_decode(&q->pbch, &q->chest_res, q->sf_symbols, bch_payload, nof_tx_ports, sfn_offset); + ret = srslte_pbch_decode(&q->pbch, &q->chest_res, sf_buffer, bch_payload, nof_tx_ports, sfn_offset); if (ret < 0) { ERROR("Error decoding PBCH (%d)\n", ret); } else if (ret == 1) { @@ -169,21 +173,23 @@ int srslte_ue_mib_decode(srslte_ue_mib_t* q, } int srslte_ue_mib_sync_init_multi(srslte_ue_mib_sync_t* q, - int(recv_callback)(void*, cf_t * [SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*), - uint32_t nof_rx_antennas, + int(recv_callback)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*), + uint32_t nof_rx_channels, void* stream_handler) { - for (int i = 0; i < nof_rx_antennas; i++) { + for (int i = 0; i < nof_rx_channels; i++) { q->sf_buffer[i] = srslte_vec_cf_malloc(MIB_BUFFER_MAX_SAMPLES); } - q->nof_rx_antennas = nof_rx_antennas; + q->nof_rx_channels = nof_rx_channels; - if (srslte_ue_mib_init(&q->ue_mib, q->sf_buffer, SRSLTE_UE_MIB_NOF_PRB)) { + // Use 1st RF channel only to receive MIB + if (srslte_ue_mib_init(&q->ue_mib, q->sf_buffer[0], SRSLTE_UE_MIB_NOF_PRB)) { ERROR("Error initiating ue_mib\n"); return SRSLTE_ERROR; } + // Configure ue_sync to receive all channels if (srslte_ue_sync_init_multi( - &q->ue_sync, SRSLTE_UE_MIB_NOF_PRB, false, recv_callback, nof_rx_antennas, stream_handler)) { + &q->ue_sync, SRSLTE_UE_MIB_NOF_PRB, false, recv_callback, nof_rx_channels, stream_handler)) { fprintf(stderr, "Error initiating ue_sync\n"); srslte_ue_mib_free(&q->ue_mib); return SRSLTE_ERROR; @@ -213,7 +219,7 @@ int srslte_ue_mib_sync_set_cell(srslte_ue_mib_sync_t* q, srslte_cell_t cell) void srslte_ue_mib_sync_free(srslte_ue_mib_sync_t* q) { - for (int i = 0; i < q->nof_rx_antennas; i++) { + for (int i = 0; i < q->nof_rx_channels; i++) { if (q->sf_buffer[i]) { free(q->sf_buffer[i]); } diff --git a/lib/src/phy/ue/ue_sync.c b/lib/src/phy/ue/ue_sync.c index 2bcd2ea52..234080698 100644 --- a/lib/src/phy/ue/ue_sync.c +++ b/lib/src/phy/ue/ue_sync.c @@ -46,7 +46,7 @@ #define DUMMY_BUFFER_NUM_SAMPLES (15 * 2048 / 2) static cf_t dummy_buffer0[DUMMY_BUFFER_NUM_SAMPLES]; static cf_t dummy_buffer1[DUMMY_BUFFER_NUM_SAMPLES]; -static cf_t* dummy_offset_buffer[SRSLTE_MAX_PORTS] = {dummy_buffer0, dummy_buffer1, dummy_buffer1, dummy_buffer1}; +static cf_t* dummy_offset_buffer[SRSLTE_MAX_CHANNELS] = {dummy_buffer0, dummy_buffer1, dummy_buffer1, dummy_buffer1}; int srslte_ue_sync_init_file(srslte_ue_sync_t* q, uint32_t nof_prb, char* file_name, int offset_time, float offset_freq) { @@ -156,7 +156,7 @@ int srslte_ue_sync_start_agc(srslte_ue_sync_t* q, return n; } -int recv_callback_multi_to_single(void* h, cf_t* x[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t* t) +int recv_callback_multi_to_single(void* h, cf_t* x[SRSLTE_MAX_CHANNELS], uint32_t nsamples, srslte_timestamp_t* t) { srslte_ue_sync_t* q = (srslte_ue_sync_t*)h; return q->recv_callback_single(q->stream_single, (void*)x[0], nsamples, t); @@ -177,7 +177,7 @@ int srslte_ue_sync_init(srslte_ue_sync_t* q, int srslte_ue_sync_init_multi(srslte_ue_sync_t* q, uint32_t max_prb, bool search_cell, - int(recv_callback)(void*, cf_t * [SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*), + int(recv_callback)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*), uint32_t nof_rx_antennas, void* stream_handler) @@ -185,13 +185,14 @@ int srslte_ue_sync_init_multi(srslte_ue_sync_t* q, return srslte_ue_sync_init_multi_decim(q, max_prb, search_cell, recv_callback, nof_rx_antennas, stream_handler, 1); } -int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t* q, - uint32_t max_prb, - bool search_cell, - int(recv_callback)(void*, cf_t * [SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*), - uint32_t nof_rx_antennas, - void* stream_handler, - int decimate) +int srslte_ue_sync_init_multi_decim( + srslte_ue_sync_t* q, + uint32_t max_prb, + bool search_cell, + int(recv_callback)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*), + uint32_t nof_rx_antennas, + void* stream_handler, + int decimate) { return srslte_ue_sync_init_multi_decim_mode( q, max_prb, search_cell, recv_callback, nof_rx_antennas, stream_handler, 1, SYNC_MODE_PSS); @@ -201,7 +202,7 @@ int srslte_ue_sync_init_multi_decim_mode( srslte_ue_sync_t* q, uint32_t max_prb, bool search_cell, - int(recv_callback)(void*, cf_t* [SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*), + int(recv_callback)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*), uint32_t nof_rx_antennas, void* stream_handler, int decimate, @@ -209,7 +210,7 @@ int srslte_ue_sync_init_multi_decim_mode( { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q != NULL && stream_handler != NULL && nof_rx_antennas <= SRSLTE_MAX_PORTS && recv_callback != NULL) { + if (q != NULL && stream_handler != NULL && nof_rx_antennas <= SRSLTE_MAX_CHANNELS && recv_callback != NULL) { ret = SRSLTE_ERROR; // int decimate = q->decimate; bzero(q, sizeof(srslte_ue_sync_t)); @@ -559,7 +560,7 @@ void srslte_ue_sync_set_agc_period(srslte_ue_sync_t* q, uint32_t period) q->agc_period = period; } -static int find_peak_ok(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PORTS]) +static int find_peak_ok(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_CHANNELS]) { if (srslte_sync_sss_detected(&q->sfind)) { @@ -700,7 +701,7 @@ static int track_peak_no(srslte_ue_sync_t* q) } } -static int receive_samples(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PORTS], const uint32_t max_num_samples) +static int receive_samples(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_CHANNELS], const uint32_t max_num_samples) { ///< A negative time offset means there are samples in our buffer for the next subframe bc we are sampling too fast if (q->next_rf_sample_offset < 0) { @@ -714,7 +715,7 @@ static int receive_samples(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PO } ///< Get N subframes from the USRP getting more samples and keeping the previous samples, if any - cf_t* ptr[SRSLTE_MAX_PORTS] = {NULL}; + cf_t* ptr[SRSLTE_MAX_CHANNELS] = {NULL}; for (int i = 0; i < q->nof_rx_antennas; i++) { ptr[i] = &input_buffer[i][q->next_rf_sample_offset]; } @@ -729,7 +730,9 @@ static int receive_samples(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PO } /* Returns 1 if the subframe is synchronized in time, 0 otherwise */ -int srslte_ue_sync_zerocopy(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PORTS], const uint32_t max_num_samples) +int srslte_ue_sync_zerocopy(srslte_ue_sync_t* q, + cf_t* input_buffer[SRSLTE_MAX_CHANNELS], + const uint32_t max_num_samples) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -830,7 +833,7 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_P return ret; } -int srslte_ue_sync_run_find_pss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PORTS]) +int srslte_ue_sync_run_find_pss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_CHANNELS]) { int ret = SRSLTE_ERROR; int n = srslte_sync_find(&q->sfind, input_buffer[0], 0, &q->peak_idx); @@ -867,7 +870,7 @@ int srslte_ue_sync_run_find_pss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRS return ret; }; -int srslte_ue_sync_run_track_pss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PORTS]) +int srslte_ue_sync_run_track_pss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_CHANNELS]) { int ret = SRSLTE_ERROR; uint32_t track_idx = 0; @@ -930,7 +933,7 @@ int srslte_ue_sync_run_track_pss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SR } int srslte_ue_sync_run_find_gnss_mode(srslte_ue_sync_t* q, - cf_t* input_buffer[SRSLTE_MAX_PORTS], + cf_t* input_buffer[SRSLTE_MAX_CHANNELS], const uint32_t max_num_samples) { INFO("Calibration samples received start at %ld + %f\n", q->last_timestamp.full_secs, q->last_timestamp.frac_secs); @@ -988,7 +991,7 @@ int srslte_ue_sync_run_find_gnss_mode(srslte_ue_sync_t* q, } ///< The track function in GNSS mode only needs to increment the system frame number -int srslte_ue_sync_run_track_gnss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PORTS]) +int srslte_ue_sync_run_track_gnss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_CHANNELS]) { INFO("SYNC TRACK: sfn=%d, sf_idx=%d, next_state=%d\n", q->frame_number, q->sf_idx, q->state); diff --git a/lib/src/radio/CMakeLists.txt b/lib/src/radio/CMakeLists.txt index eff43c47b..72d7e1a8e 100644 --- a/lib/src/radio/CMakeLists.txt +++ b/lib/src/radio/CMakeLists.txt @@ -19,7 +19,7 @@ # if(RF_FOUND) - add_library(srslte_radio STATIC radio.cc radio_multi.cc) + add_library(srslte_radio STATIC radio.cc) target_link_libraries(srslte_radio srslte_rf) endif(RF_FOUND) diff --git a/lib/src/radio/radio.cc b/lib/src/radio/radio.cc index d12c06844..15906527a 100644 --- a/lib/src/radio/radio.cc +++ b/lib/src/radio/radio.cc @@ -30,54 +30,115 @@ extern "C" { namespace srslte { -bool radio::init(log_filter* _log_h, const char* args, char* devname, uint32_t nof_channels) +radio::radio(srslte::log_filter* log_h_) : logger(nullptr), log_h(log_h_), zeros(NULL) { - char* mutable_arg_str = nullptr; - std::vector args_vec; - if (args != nullptr) { - args_vec.resize(strlen(args) + 1); - strcpy(&args_vec[0], args); - mutable_arg_str = &args_vec[0]; - } - if (srslte_rf_open_devname(&rf_device, devname, mutable_arg_str, nof_channels)) { - ERROR("Error opening RF device\n"); - return false; + zeros = srslte_vec_cf_malloc(SRSLTE_SF_LEN_MAX); + srslte_vec_cf_zero(zeros, SRSLTE_SF_LEN_MAX); +} + +radio::radio(srslte::logger* logger_) : logger(logger_), log_h(nullptr), zeros(NULL) +{ + zeros = srslte_vec_cf_malloc(SRSLTE_SF_LEN_MAX); + srslte_vec_cf_zero(zeros, SRSLTE_SF_LEN_MAX); +} + +radio::~radio() +{ + if (zeros) { + free(zeros); + zeros = nullptr; } +} - log_h = _log_h; - tx_adv_negative = false; - agc_enabled = false; - burst_preamble_samples = 0; - burst_preamble_time_rounded = 0; - cur_tx_srate = 0; - is_start_of_burst = true; +int radio::init(const rf_args_t& args, phy_interface_radio* phy_) +{ + phy = phy_; - // Suppress radio stdout - srslte_rf_suppress_stdout(&rf_device); + // Init log + if (log_h == nullptr) { + if (logger != nullptr) { + log_local.init("RF ", logger); + log_local.set_level(args.log_level); + log_h = &log_local; + } else { + fprintf(stderr, "Must all radio constructor with either logger or log_filter\n"); + return SRSLTE_ERROR; + } + } + + if (args.nof_antennas > SRSLTE_MAX_PORTS) { + log_h->error("Maximum number of antennas exceeded (%d > %d)\n", args.nof_antennas, SRSLTE_MAX_PORTS); + return SRSLTE_ERROR; + } + if (args.nof_carriers > SRSLTE_MAX_CARRIERS) { + log_h->error("Maximum number of carriers exceeded (%d > %d)\n", args.nof_carriers, SRSLTE_MAX_CARRIERS); + return SRSLTE_ERROR; + } + + nof_channels = args.nof_antennas * args.nof_carriers; + nof_antennas = args.nof_antennas; + + // Init and start Radio + char* device_args = nullptr; + if (args.device_args != "auto") { + device_args = (char*)args.device_args.c_str(); + } + char* dev_name = nullptr; + if (args.device_name != "auto") { + dev_name = (char*)args.device_name.c_str(); + } + log_h->console("Opening %d channels in RF device=%s with args=%s\n", + nof_channels, + dev_name ? dev_name : "default", + device_args ? device_args : "default"); + if (srslte_rf_open_devname(&rf_device, dev_name, device_args, nof_channels)) { + ERROR("Error opening RF device\n"); + return SRSLTE_ERROR; + } + + is_start_of_burst = true; + is_initialized = true; + + // Set RF options + tx_adv_auto = true; + if (args.time_adv_nsamples != "auto") { + int t = (int)strtol(args.time_adv_nsamples.c_str(), nullptr, 10); + set_tx_adv(abs(t)); + set_tx_adv_neg(t < 0); + } continuous_tx = true; - tx_adv_auto = true; - // Set default preamble length each known device - // We distinguish by device family, maybe we should calibrate per device - if (strstr(srslte_rf_name(&rf_device), "uhd")) { - } else if (strstr(srslte_rf_name(&rf_device), "bladerf")) { - burst_preamble_sec = blade_default_burst_preamble_sec; - } else { - burst_preamble_sec = 0; - log_h->console("\nWarning burst preamble is not calibrated for device %s. Set a value manually\n\n", - srslte_rf_name(&rf_device)); + if (args.continuous_tx != "auto") { + continuous_tx = (args.continuous_tx == "yes"); } - if (args) { - strncpy(saved_args, args, 127); + // Set fixed gain options + if (args.rx_gain < 0) { + start_agc(false); + } else { + set_rx_gain(args.rx_gain); } - if (devname) { - strncpy(saved_devname, devname, 127); + if (args.tx_gain > 0) { + set_tx_gain(args.tx_gain); + } else { + // Set same gain than for RX until power control sets a gain + set_tx_gain(args.rx_gain); + log_h->console("\nWarning: TX gain was not set. Using open-loop power control (not working properly)\n\n"); } - saved_nof_channels = nof_channels; - is_initialized = true; - return true; + // Frequency offset + freq_offset = args.freq_offset; + + // Get device info + rf_info = *get_info(); + + // Suppress radio stdout + srslte_rf_suppress_stdout(&rf_device); + + // Register handler for processing O/U/L + srslte_rf_register_error_handler(&rf_device, rf_msg_callback, this); + + return SRSLTE_SUCCESS; } bool radio::is_init() @@ -103,21 +164,6 @@ void radio::reset() usleep(100000); } -void radio::set_tx_rx_gain_offset(float offset) -{ - srslte_rf_set_tx_rx_gain_offset(&rf_device, offset); -} - -void radio::set_burst_preamble(double preamble_us) -{ - burst_preamble_sec = (double)preamble_us / 1e6; -} - -void radio::set_continuous_tx(bool enable) -{ - continuous_tx = enable; -} - bool radio::is_continuous_tx() { return continuous_tx; @@ -139,23 +185,22 @@ void radio::set_tx_adv_neg(bool tx_adv_is_neg) bool radio::start_agc(bool tx_gain_same_rx) { + if (!is_initialized) { + return false; + } if (srslte_rf_start_gain_thread(&rf_device, tx_gain_same_rx)) { ERROR("Error starting AGC Thread RF device\n"); return false; } - agc_enabled = true; - return true; } -bool radio::rx_at(cf_t* buffer, uint32_t nof_samples, srslte_timestamp_t rx_time) -{ - ERROR("Not implemented\n"); - return false; -} -bool radio::rx_now(cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t* rxd_time) +bool radio::rx_now(rf_buffer_interface& buffer, const uint32_t& nof_samples, srslte_timestamp_t* rxd_time) { + if (!is_initialized) { + return false; + } bool ret = true; if (!radio_is_streaming) { @@ -166,7 +211,10 @@ bool radio::rx_now(cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_ time_t* full_secs = rxd_time ? &rxd_time->full_secs : NULL; double* frac_secs = rxd_time ? &rxd_time->frac_secs : NULL; - if (srslte_rf_recv_with_time_multi(&rf_device, (void**)buffer, nof_samples, true, full_secs, frac_secs) > 0) { + // Conversion from safe C++ std::array to the unsafe C interface. We must ensure that the RF driver implementation + // accepts up to SRSLTE_MAX_CHANNELS buffers + + if (srslte_rf_recv_with_time_multi(&rf_device, buffer.to_void(), nof_samples, true, full_secs, frac_secs) > 0) { ret = true; } else { ret = false; @@ -177,80 +225,49 @@ bool radio::rx_now(cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_ void radio::get_time(srslte_timestamp_t* now) { + if (!is_initialized) { + return; + } srslte_rf_get_time(&rf_device, &now->full_secs, &now->frac_secs); } -float radio::get_max_tx_power() -{ - return 40; -} - float radio::get_rssi() { + if (!is_initialized) { + return 0.0f; + } return srslte_rf_get_rssi(&rf_device); } bool radio::has_rssi() { + if (!is_initialized) { + return false; + } return srslte_rf_has_rssi(&rf_device); } -bool radio::is_first_of_burst() -{ - return is_start_of_burst; -} - -#define BLOCKING_TX true - -bool radio::tx_single(cf_t* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) +bool radio::tx(rf_buffer_interface& buffer, const uint32_t& nof_samples, const srslte_timestamp_t& tx_time_) { - cf_t* _buffer[SRSLTE_MAX_PORTS]; - - _buffer[0] = (buffer) ? buffer : zeros; - for (int p = 1; p < SRSLTE_MAX_PORTS; p++) { - _buffer[p] = zeros; + if (!is_initialized) { + return false; } - - return this->tx(_buffer, nof_samples, tx_time); -} - -bool radio::tx(cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time) -{ + srslte_timestamp_t tx_time = tx_time_; if (!tx_adv_negative) { srslte_timestamp_sub(&tx_time, 0, tx_adv_sec); } else { srslte_timestamp_add(&tx_time, 0, tx_adv_sec); } - if (is_start_of_burst) { - if (burst_preamble_samples != 0) { - srslte_timestamp_t tx_time_pad; - srslte_timestamp_copy(&tx_time_pad, &tx_time); - srslte_timestamp_sub(&tx_time_pad, 0, burst_preamble_time_rounded); - srslte_rf_send_timed_multi(&rf_device, - (void**)buffer, - burst_preamble_samples, - tx_time_pad.full_secs, - tx_time_pad.frac_secs, - true, - true, - false); - is_start_of_burst = false; - } - } - // Save possible end of burst time srslte_timestamp_copy(&end_of_burst_time, &tx_time); srslte_timestamp_add(&end_of_burst_time, 0, (double)nof_samples / cur_tx_srate); - int ret = srslte_rf_send_timed_multi(&rf_device, - (void**)buffer, - nof_samples, - tx_time.full_secs, - tx_time.frac_secs, - BLOCKING_TX, - is_start_of_burst, - false); + // Conversion from safe C++ std::array to the unsafe C interface. We must ensure that the RF driver implementation + // accepts up to SRSLTE_MAX_CHANNELS buffers + + int ret = srslte_rf_send_timed_multi( + &rf_device, buffer.to_void(), nof_samples, tx_time.full_secs, tx_time.frac_secs, true, is_start_of_burst, false); is_start_of_burst = false; if (ret > 0) { return true; @@ -261,6 +278,9 @@ bool radio::tx(cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_time void radio::tx_end() { + if (!is_initialized) { + return; + } if (!is_start_of_burst) { srslte_rf_send_timed2(&rf_device, zeros, 0, end_of_burst_time.full_secs, end_of_burst_time.frac_secs, false, true); is_start_of_burst = true; @@ -272,78 +292,91 @@ bool radio::get_is_start_of_burst() return is_start_of_burst; } -void radio::set_freq_offset(double freq) +void radio::set_rx_freq(const uint32_t& channel_idx, const double& freq) { - freq_offset = freq; -} - -void radio::set_rx_freq(uint32_t ch, double freq) -{ - rx_freq = srslte_rf_set_rx_freq(&rf_device, ch, freq + freq_offset); + if (!is_initialized) { + return; + } + if ((channel_idx + 1) * nof_antennas <= nof_channels) { + for (uint32_t i = 0; i < nof_antennas; i++) { + srslte_rf_set_rx_freq(&rf_device, channel_idx * nof_antennas + i, freq + freq_offset); + } + } else { + log_h->error("set_rx_freq: channel_idx=%d for %d antennas exceeds maximum channels (%d)\n", + channel_idx, + nof_antennas, + nof_channels); + } } -void radio::set_rx_gain(float gain) +void radio::set_rx_gain(const float& gain) { + if (!is_initialized) { + return; + } srslte_rf_set_rx_gain(&rf_device, gain); } -void radio::set_rx_gain_th(float gain) +void radio::set_rx_gain_th(const float& gain) { + if (!is_initialized) { + return; + } srslte_rf_set_rx_gain_th(&rf_device, gain); } -void radio::set_rx_srate(double srate) +void radio::set_rx_srate(const double& srate) { + if (!is_initialized) { + return; + } srslte_rf_set_rx_srate(&rf_device, srate); } -void radio::set_tx_freq(uint32_t ch, double freq) +void radio::set_tx_freq(const uint32_t& channel_idx, const double& freq) { - tx_freq = srslte_rf_set_tx_freq(&rf_device, ch, freq + freq_offset); + if (!is_initialized) { + return; + } + if ((channel_idx + 1) * nof_antennas <= nof_channels) { + for (uint32_t i = 0; i < nof_antennas; i++) { + srslte_rf_set_tx_freq(&rf_device, channel_idx * nof_antennas + i, freq + freq_offset); + } + } else { + log_h->error("set_tx_freq: channel_idx=%d for %d antennas exceeds maximum channels (%d)\n", + channel_idx, + nof_antennas, + nof_channels); + } } -void radio::set_tx_gain(float gain) +void radio::set_tx_gain(const float& gain) { + if (!is_initialized) { + return; + } srslte_rf_set_tx_gain(&rf_device, gain); } -double radio::get_rx_freq() -{ - return rx_freq; -} - double radio::get_freq_offset() { return freq_offset; } -double radio::get_tx_freq() -{ - return tx_freq; -} - -float radio::get_tx_gain() -{ - return srslte_rf_get_tx_gain(&rf_device); -} - float radio::get_rx_gain() { + if (!is_initialized) { + return 0.0f; + } return srslte_rf_get_rx_gain(&rf_device); } -void radio::set_tx_srate(double srate) +void radio::set_tx_srate(const double& srate) { - cur_tx_srate = srslte_rf_set_tx_srate(&rf_device, srate); - burst_preamble_samples = (uint32_t)(cur_tx_srate * burst_preamble_sec); - if (burst_preamble_samples > burst_preamble_max_samples) { - fprintf(stderr, - "Error setting TX srate %.1f MHz. Maximum burst preamble samples: %d, requested: %d\n", - srate * 1e-6, - burst_preamble_max_samples, - burst_preamble_samples); + if (!is_initialized) { + return; } - burst_preamble_time_rounded = (double)burst_preamble_samples / cur_tx_srate; + cur_tx_srate = srslte_rf_set_tx_srate(&rf_device, srate); int nsamples = 0; /* Set time advance for each known device if in auto mode */ @@ -450,7 +483,7 @@ void radio::set_tx_srate(double srate) cur_tx_srate); tx_adv_sec = blade_default_tx_adv_samples * (1 / cur_tx_srate) + blade_default_tx_adv_offset_sec; } - } else { + } else if (!strcmp(srslte_rf_name(&rf_device), "zmq")) { log_h->console("\nWarning TX/RX time offset has not been calibrated for device %s. Set a value manually\n\n", srslte_rf_name(&rf_device)); } @@ -467,14 +500,59 @@ void radio::set_tx_srate(double srate) } } -void radio::register_error_handler(srslte_rf_error_handler_t h) +srslte_rf_info_t* radio::get_info() { - srslte_rf_register_error_handler(&rf_device, h); + if (!is_initialized) { + return NULL; + } + return srslte_rf_get_info(&rf_device); } -srslte_rf_info_t* radio::get_info() +bool radio::get_metrics(rf_metrics_t* metrics) { - return srslte_rf_get_info(&rf_device); + *metrics = rf_metrics; + rf_metrics = {}; + return true; +} + +void radio::handle_rf_msg(srslte_rf_error_t error) +{ + if (!is_initialized) { + return; + } + if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_OVERFLOW) { + rf_metrics.rf_o++; + rf_metrics.rf_error = true; + log_h->info("Overflow\n"); + + // inform PHY about overflow + phy->radio_overflow(); + } else if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_UNDERFLOW) { + rf_metrics.rf_u++; + rf_metrics.rf_error = true; + log_h->info("Underflow\n"); + } else if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_LATE) { + rf_metrics.rf_l++; + rf_metrics.rf_error = true; + log_h->info("Late (detected in %s)\n", error.opt ? "rx call" : "asynchronous thread"); + } else if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_RX) { + log_h->error("Fatal radio error occured.\n"); + phy->radio_failure(); + } else if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_OTHER) { + std::string str(error.msg); + str.erase(std::remove(str.begin(), str.end(), '\n'), str.end()); + str.erase(std::remove(str.begin(), str.end(), '\r'), str.end()); + str.push_back('\n'); + log_h->info("%s\n", str.c_str()); + } +} + +void radio::rf_msg_callback(void* arg, srslte_rf_error_t error) +{ + radio* h = (radio*)arg; + if (arg != nullptr) { + h->handle_rf_msg(error); + } } } // namespace srslte diff --git a/lib/src/radio/radio_multi.cc b/lib/src/radio/radio_multi.cc deleted file mode 100644 index 7183835a9..000000000 --- a/lib/src/radio/radio_multi.cc +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2013-2019 Software Radio Systems Limited - * - * This file is part of srsLTE. - * - * srsLTE 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. - * - * srsLTE 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 "srslte/radio/radio_multi.h" -#include - -namespace srslte { - -std::mutex radio_instance_mutex; -static radio_multi* instance; - -radio_multi::radio_multi(srslte::logger* logger_) : logger(logger_), radio_base(logger_) -{ - std::lock_guard lock(radio_instance_mutex); - instance = this; -} - -radio_multi::~radio_multi() -{ - stop(); -} - -std::string radio_multi::get_type() -{ - return "radio_multi"; -} - -int radio_multi::init(const rf_args_t& args_, phy_interface_radio* phy_) -{ - args = args_; - phy = phy_; - - // Init log - log.init("RF ", logger); - log.set_level(args.log_level); - - if (args.nof_radios > SRSLTE_MAX_RADIOS) { - log.error("Maximum supported number of radios exceeded (%d > %d)\n", args.nof_radios, SRSLTE_MAX_RADIOS); - return SRSLTE_ERROR; - } - - // Init and start Radio - char* dev_name = nullptr; - if (args.device_name != "auto") { - dev_name = (char*)args.device_name.c_str(); - } - - const char* dev_args[SRSLTE_MAX_RADIOS] = {nullptr}; - for (int i = 0; i < SRSLTE_MAX_RADIOS; i++) { - if (args.device_args[i] != "auto") { - dev_args[i] = args.device_args[i].c_str(); - } - } - - log.console( - "Opening %d RF devices with %d RF channels...\n", args.nof_radios, args.nof_rf_channels * args.nof_rx_ant); - for (uint32_t r = 0; r < args.nof_radios; r++) { - std::unique_ptr radio = std::unique_ptr(new srslte::radio()); - if (!radio->init(&log, dev_args[r], dev_name, args.nof_rf_channels * args.nof_rx_ant)) { - log.console("Failed to find device %s with args %s\n", args.device_name.c_str(), args.device_args[0].c_str()); - return SRSLTE_ERROR; - } - - // Set RF options - if (args.time_adv_nsamples != "auto") { - int t = (int)strtol(args.time_adv_nsamples.c_str(), nullptr, 10); - radio->set_tx_adv(abs(t)); - radio->set_tx_adv_neg(t < 0); - } - if (args.burst_preamble != "auto") { - radio->set_burst_preamble(strtof(args.burst_preamble.c_str(), nullptr)); - } - if (args.continuous_tx != "auto") { - radio->set_continuous_tx(args.continuous_tx == "yes"); - } - - // Set PHY options - if (args.rx_gain < 0) { - radio->start_agc(false); - } else { - radio->set_rx_gain(args.rx_gain); - } - if (args.tx_gain > 0) { - radio->set_tx_gain(args.tx_gain); - } else { - radio->set_tx_gain(args.rx_gain); - log.console("\nWarning: TX gain was not set. Using open-loop power control (not working properly)\n\n"); - } - - radio->register_error_handler(rf_msg); - radio->set_freq_offset(args.freq_offset); - - // append to radios - radios.push_back(std::move(radio)); - } - - running = true; - - return SRSLTE_SUCCESS; -} - -void radio_multi::stop() -{ - if (running) { - for (auto& radio : radios) { - radio->stop(); - } - - std::lock_guard lock(radio_instance_mutex); - instance = nullptr; - - running = false; - } -} - -bool radio_multi::get_metrics(rf_metrics_t* metrics) -{ - *metrics = rf_metrics; - rf_metrics = {}; - return true; -} - -void radio_multi::rf_msg(srslte_rf_error_t error) -{ - std::lock_guard lock(radio_instance_mutex); - if (instance) { - instance->handle_rf_msg(error); - } -} - -void radio_multi::handle_rf_msg(srslte_rf_error_t error) -{ - if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_OVERFLOW) { - rf_metrics.rf_o++; - rf_metrics.rf_error = true; - log.info("Overflow\n"); - - // inform PHY about overflow - phy->radio_overflow(); - } else if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_UNDERFLOW) { - rf_metrics.rf_u++; - rf_metrics.rf_error = true; - log.info("Underflow\n"); - } else if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_LATE) { - rf_metrics.rf_l++; - rf_metrics.rf_error = true; - log.info("Late (detected in %s)\n", error.opt ? "rx call" : "asynchronous thread"); - } else if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_RX) { - log.error("Fatal radio error occured.\n"); - phy->radio_failure(); - } else if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_OTHER) { - std::string str(error.msg); - str.erase(std::remove(str.begin(), str.end(), '\n'), str.end()); - str.erase(std::remove(str.begin(), str.end(), '\r'), str.end()); - str.push_back('\n'); - log.info("%s\n", str.c_str()); - } -} - -} // namespace srslte diff --git a/lib/src/radio/test/benchmark_radio.cc b/lib/src/radio/test/benchmark_radio.cc index d1ff0264a..7fa4cf544 100644 --- a/lib/src/radio/test/benchmark_radio.cc +++ b/lib/src/radio/test/benchmark_radio.cc @@ -37,6 +37,8 @@ extern "C" { using namespace srslte; +#define SRSLTE_MAX_RADIOS 3 + static char radios_args[SRSLTE_MAX_RADIOS][64] = {"auto", "auto", "auto"}; log_filter log_h; @@ -254,6 +256,8 @@ int main(int argc, char** argv) bzero(&ts_rx, sizeof(ts_rx)); bzero(&ts_tx, sizeof(ts_tx)); + rf_buffer_t rf_buffers[SRSLTE_MAX_RADIOS] = {}; + float delay_idx[SRSLTE_MAX_RADIOS] = {0}; uint32_t delay_count = 0; @@ -267,7 +271,7 @@ int main(int argc, char** argv) /* Instanciate and allocate memory */ printf("Instantiating objects and allocating memory...\n"); for (uint32_t r = 0; r < nof_radios; r++) { - radio_h[r] = new radio(); + radio_h[r] = new radio(&log_h); if (!radio_h[r]) { fprintf(stderr, "Error: Calling radio constructor\n"); goto clean_exit; @@ -298,7 +302,13 @@ int main(int argc, char** argv) /* Initialise instances */ printf("Initialising instances...\n"); for (uint32_t r = 0; r < nof_radios; r++) { - if (!radio_h[r]->init(&log_h, radios_args[r], NULL, nof_ports)) { + rf_args_t radio_args = {}; + radio_args.nof_antennas = nof_ports; + radio_args.nof_carriers = 1; + radio_args.device_args = radios_args[r]; + radio_args.rx_gain = agc_enable ? -1 : rf_gain; + + if (!radio_h[r]->init(radio_args, NULL)) { fprintf(stderr, "Error: Calling radio_multi constructor\n"); goto clean_exit; } @@ -307,13 +317,10 @@ int main(int argc, char** argv) // enable and init agc if (agc_enable) { - radio_h[r]->start_agc(); if (srslte_agc_init_uhd(&agc[r], SRSLTE_AGC_MODE_PEAK_AMPLITUDE, 0, set_gain_callback, radio_h[r])) { fprintf(stderr, "Error: Initiating AGC %d\n", r); goto clean_exit; } - } else { - radio_h[r]->set_rx_gain(rf_gain); } // Set Rx/Tx sampling rate @@ -355,13 +362,19 @@ int main(int argc, char** argv) /* Receive */ printf("Start capturing %d frames of %d samples...\n", nof_frames, frame_size); + for (int i = 0; i < SRSLTE_MAX_RADIOS; i++) { + for (int j = 0; j < SRSLTE_MAX_PORTS; j++) { + rf_buffers[i].set(j, buffers[i][j]); + } + } + for (uint32_t i = 0; i < nof_frames; i++) { int gap = 0; frame_size = SRSLTE_MIN(frame_size, nof_samples); // receive each radio for (uint32_t r = 0; r < nof_radios; r++) { - radio_h[r]->rx_now(buffers[r], frame_size, &ts_rx[r]); + radio_h[r]->rx_now(rf_buffers[r], frame_size, &ts_rx[r]); } // run agc @@ -376,7 +389,7 @@ int main(int argc, char** argv) for (uint32_t r = 0; r < nof_radios; r++) { srslte_timestamp_copy(&ts_tx, &ts_rx[r]); srslte_timestamp_add(&ts_tx, 0, 0.004); - radio_h[r]->tx_single(buffers[r][0], frame_size, ts_tx); + radio_h[r]->tx(rf_buffers[r], frame_size, ts_tx); } } diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index 3d8841a8f..40152fe7f 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -59,11 +59,9 @@ drb_config = drb.conf # device_args: Arguments for the device driver. Options are "auto" or any string. # Default for UHD: "recv_frame_size=9232,send_frame_size=9232" # Default for bladeRF: "" -# #time_adv_nsamples: Transmission time advance (in number of samples) to compensate for RF delay +# time_adv_nsamples: Transmission time advance (in number of samples) to compensate for RF delay # from antenna to timestamp insertion. # Default "auto". B210 USRP: 100 samples, bladeRF: 27. -# burst_preamble_us: Preamble length to transmit before start of burst. -# Default "auto". B210 USRP: 400 us, bladeRF: 0 us. ##################################################################### [rf] dl_earfcn = 3400 @@ -80,7 +78,6 @@ rx_gain = 40 #device_args = auto #time_adv_nsamples = auto -#burst_preamble_us = auto ##################################################################### diff --git a/srsenb/hdr/enb.h b/srsenb/hdr/enb.h index 89c86f570..d5e99243f 100644 --- a/srsenb/hdr/enb.h +++ b/srsenb/hdr/enb.h @@ -35,7 +35,7 @@ #include "phy/phy.h" #include "srsenb/hdr/stack/rrc/rrc.h" -#include "srslte/radio/radio_base.h" +#include "srslte/radio/radio.h" #include "srsenb/hdr/phy/enb_phy_base.h" #include "srsenb/hdr/stack/enb_stack_base.h" @@ -141,7 +141,7 @@ private: // eNB components std::unique_ptr stack = nullptr; - std::unique_ptr radio = nullptr; + std::unique_ptr radio = nullptr; std::unique_ptr phy = nullptr; srslte::logger_stdout logger_stdout; diff --git a/srsenb/hdr/phy/phy.h b/srsenb/hdr/phy/phy.h index 739c2858f..2ac8be27f 100644 --- a/srsenb/hdr/phy/phy.h +++ b/srsenb/hdr/phy/phy.h @@ -28,9 +28,9 @@ #include "srslte/common/log.h" #include "srslte/common/log_filter.h" #include "srslte/common/trace.h" -#include "srslte/interfaces/common_interfaces.h" #include "srslte/interfaces/enb_interfaces.h" #include "srslte/interfaces/enb_metrics_interface.h" +#include "srslte/interfaces/radio_interfaces.h" #include "srslte/radio/radio.h" #include "txrx.h" diff --git a/srsenb/hdr/phy/phy_common.h b/srsenb/hdr/phy/phy_common.h index 84bef4331..ff2f53f82 100644 --- a/srsenb/hdr/phy/phy_common.h +++ b/srsenb/hdr/phy/phy_common.h @@ -29,9 +29,9 @@ #include "srslte/common/log.h" #include "srslte/common/thread_pool.h" #include "srslte/common/threads.h" -#include "srslte/interfaces/common_interfaces.h" #include "srslte/interfaces/enb_interfaces.h" #include "srslte/interfaces/enb_metrics_interface.h" +#include "srslte/interfaces/radio_interfaces.h" #include "srslte/phy/channel/channel.h" #include "srslte/radio/radio.h" #include @@ -63,7 +63,7 @@ public: * @param nof_samples number of samples to transmit * @param tx_time timestamp to transmit samples */ - void worker_end(void* tx_sem_id, cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time); + void worker_end(void* tx_sem_id, srslte::rf_buffer_t& buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); // Common objects phy_args_t params = {}; diff --git a/srsenb/hdr/radio/enb_radio_multi.h b/srsenb/hdr/radio/enb_radio_multi.h deleted file mode 100644 index 4bbe1bf7f..000000000 --- a/srsenb/hdr/radio/enb_radio_multi.h +++ /dev/null @@ -1,49 +0,0 @@ - -/* - * Copyright 2013-2019 Software Radio Systems Limited - * - * This file is part of srsLTE. - * - * srsLTE 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. - * - * srsLTE 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/. - * - */ - -/****************************************************************************** - * File: enb_radio_multi.h - * Description: Header-only class for eNB to set DL/UL freq during init - *****************************************************************************/ - -#ifndef SRSENB_RADIO_MULTI_H -#define SRSENB_RADIO_MULTI_H - -#include "srslte/common/logger.h" -#include "srslte/interfaces/common_interfaces.h" -#include "srslte/phy/rf/rf.h" -#include "srslte/radio/radio_base.h" -#include "srslte/radio/radio_metrics.h" -#include "srslte/radio/radio_multi.h" - -namespace srsenb { - -class enb_radio_multi : public srslte::radio_multi -{ -public: - enb_radio_multi(srslte::logger* logger_); - ~enb_radio_multi() override; - int init(const srslte::rf_args_t& args_, srslte::phy_interface_radio* phy_); -}; -} // namespace srsenb - -#endif // SRSENB_RADIO_MULTI_H diff --git a/srsenb/src/CMakeLists.txt b/srsenb/src/CMakeLists.txt index 450aeb190..4d0394b3e 100644 --- a/srsenb/src/CMakeLists.txt +++ b/srsenb/src/CMakeLists.txt @@ -18,7 +18,6 @@ # and at http://www.gnu.org/licenses/. # -add_subdirectory(radio) add_subdirectory(phy) add_subdirectory(stack) @@ -36,8 +35,7 @@ endif (RPATH) add_library(enb_cfg_parser parser.cc enb_cfg_parser.cc) add_executable(srsenb main.cc enb.cc metrics_stdout.cc metrics_csv.cc) -target_link_libraries(srsenb srsenb_radio - srsenb_phy +target_link_libraries(srsenb srsenb_phy srsenb_stack srsenb_upper srsenb_mac diff --git a/srsenb/src/enb.cc b/srsenb/src/enb.cc index 2db58d6bb..9e9d73125 100644 --- a/srsenb/src/enb.cc +++ b/srsenb/src/enb.cc @@ -20,7 +20,6 @@ */ #include "srsenb/hdr/enb.h" -#include "srsenb/hdr/radio/enb_radio_multi.h" #include "srsenb/hdr/stack/enb_stack_lte.h" #include "srsenb/src/enb_cfg_parser.h" #include "srslte/build_info.h" @@ -38,7 +37,7 @@ enb::~enb() { // pool has to be cleaned after enb is deleted stack.reset(); - srslte::byte_buffer_pool::cleanup(); + srslte::byte_buffer_pool::cleanup(); } int enb::init(const all_args_t& args_, srslte::logger* logger_) @@ -67,7 +66,7 @@ int enb::init(const all_args_t& args_, srslte::logger* logger_) return SRSLTE_ERROR; } - std::unique_ptr lte_radio = std::unique_ptr(new enb_radio_multi(logger)); + std::unique_ptr lte_radio = std::unique_ptr(new srslte::radio(logger)); if (!lte_radio) { log.console("Error creating radio multi instance.\n"); return SRSLTE_ERROR; diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index f7f4ee178..ce156aa08 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -998,9 +998,8 @@ int set_derived_args(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_cfg_ } // Patch certain args that are not exposed yet - args_->rf.nof_radios = 1; - args_->rf.nof_rf_channels = rrc_cfg_->cell_list.size(); - args_->rf.nof_rx_ant = args_->enb.nof_ports; + args_->rf.nof_carriers = rrc_cfg_->cell_list.size(); + args_->rf.nof_antennas = args_->enb.nof_ports; return SRSLTE_SUCCESS; } diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index b3af68063..b907c87c3 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -31,8 +31,8 @@ #include #include #include -#include #include +#include #include "srsenb/hdr/enb.h" #include "srsenb/hdr/metrics_csv.h" @@ -94,9 +94,8 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("rf.ul_freq", bpo::value(&args->rf.ul_freq)->default_value(-1), "Uplink Frequency (if positive overrides EARFCN)") ("rf.device_name", bpo::value(&args->rf.device_name)->default_value("auto"), "Front-end device name") - ("rf.device_args", bpo::value(&args->rf.device_args[0])->default_value("auto"), "Front-end device arguments") + ("rf.device_args", bpo::value(&args->rf.device_args)->default_value("auto"), "Front-end device arguments") ("rf.time_adv_nsamples", bpo::value(&args->rf.time_adv_nsamples)->default_value("auto"), "Transmission time advance") - ("rf.burst_preamble_us", bpo::value(&args->rf.burst_preamble)->default_value("auto"), "Transmission time advance") ("pcap.enable", bpo::value(&args->stack.pcap.enable)->default_value(false), "Enable MAC packet captures for wireshark") ("pcap.filename", bpo::value(&args->stack.pcap.filename)->default_value("ue.pcap"), "MAC layer capture filename") diff --git a/srsenb/src/phy/phy_common.cc b/srsenb/src/phy/phy_common.cc index 0a69ababd..39c8548d2 100644 --- a/srsenb/src/phy/phy_common.cc +++ b/srsenb/src/phy/phy_common.cc @@ -104,21 +104,21 @@ void phy_common::stop() * Each worker uses this function to indicate that all processing is done and data is ready for transmission or * there is no transmission at all (tx_enable). In that case, the end of burst message will be sent to the radio */ -void phy_common::worker_end(void* tx_sem_id, - cf_t* buffer[SRSLTE_MAX_PORTS], - uint32_t nof_samples, - srslte_timestamp_t tx_time) +void phy_common::worker_end(void* tx_sem_id, + srslte::rf_buffer_t& buffer, + uint32_t nof_samples, + srslte_timestamp_t tx_time) { // Wait for the green light to transmit in the current TTI semaphore.wait(tx_sem_id); // Run DL channel emulator if created if (dl_channel) { - dl_channel->run(buffer, buffer, nof_samples, tx_time); + dl_channel->run(buffer.to_cf_t(), buffer.to_cf_t(), nof_samples, tx_time); } // Always transmit on single radio - radio->tx(0, buffer, nof_samples, tx_time); + radio->tx(buffer, nof_samples, tx_time); // Trigger MAC clock stack->tti_clock(); diff --git a/srsenb/src/phy/sf_worker.cc b/srsenb/src/phy/sf_worker.cc index 31525b819..e0644fc19 100644 --- a/srsenb/src/phy/sf_worker.cc +++ b/srsenb/src/phy/sf_worker.cc @@ -163,7 +163,6 @@ uint32_t sf_worker::get_nof_rnti() void sf_worker::work_imp() { std::lock_guard lock(work_mutex); - cf_t* signal_buffer_tx[SRSLTE_MAX_PORTS * SRSLTE_MAX_CARRIERS]; srslte_ul_sf_cfg_t ul_sf = {}; srslte_dl_sf_cfg_t dl_sf = {}; @@ -230,14 +229,15 @@ void sf_worker::work_imp() } // Get Transmission buffers - for (uint32_t cc = 0, i = 0; cc < phy->get_nof_carriers(); cc++) { - for (uint32_t ant = 0; ant < phy->get_nof_ports(cc); ant++, i++) { - signal_buffer_tx[i] = cc_workers[cc]->get_buffer_tx(ant); + srslte::rf_buffer_t tx_buffer = {}; + for (uint32_t cc = 0; cc < phy->get_nof_carriers(); cc++) { + for (uint32_t ant = 0; ant < phy->get_nof_ports(0); ant++) { + tx_buffer.set(cc, ant, phy->get_nof_ports(0), cc_workers[cc]->get_buffer_tx(ant)); } } Debug("Sending to radio\n"); - phy->worker_end(this, signal_buffer_tx, SRSLTE_SF_LEN_PRB(phy->get_nof_prb(0)), tx_time); + phy->worker_end(this, tx_buffer, SRSLTE_SF_LEN_PRB(phy->get_nof_prb(0)), tx_time); #ifdef DEBUG_WRITE_FILE fwrite(signal_buffer_tx, SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t), 1, f); diff --git a/srsenb/src/phy/txrx.cc b/srsenb/src/phy/txrx.cc index d59721ebf..c4b2525c8 100644 --- a/srsenb/src/phy/txrx.cc +++ b/srsenb/src/phy/txrx.cc @@ -84,32 +84,27 @@ void txrx::stop() void txrx::run_thread() { - sf_worker* worker = nullptr; - cf_t* buffer[worker_com->get_nof_carriers() * worker_com->get_nof_ports(0)] = {}; - srslte_timestamp_t rx_time = {}; - srslte_timestamp_t tx_time = {}; - uint32_t sf_len = SRSLTE_SF_LEN_PRB(worker_com->get_nof_prb(0)); + sf_worker* worker = nullptr; + srslte::rf_buffer_t buffer = {}; + srslte_timestamp_t rx_time = {}; + srslte_timestamp_t tx_time = {}; + uint32_t sf_len = SRSLTE_SF_LEN_PRB(worker_com->get_nof_prb(0)); float samp_rate = srslte_sampling_freq_hz(worker_com->get_nof_prb(0)); // Configure radio - radio_h->set_rx_srate(0, samp_rate); - radio_h->set_tx_srate(0, samp_rate); + radio_h->set_rx_srate(samp_rate); + radio_h->set_tx_srate(samp_rate); // Set Tx/Rx frequencies for (uint32_t cc_idx = 0; cc_idx < worker_com->get_nof_carriers(); cc_idx++) { float tx_freq_hz = worker_com->get_dl_freq_hz(cc_idx); float rx_freq_hz = worker_com->get_ul_freq_hz(cc_idx); uint32_t rf_port = worker_com->get_rf_port(cc_idx); - for (uint32_t i = 0; i < worker_com->get_nof_ports(cc_idx); i++) { - radio_h->set_tx_freq(0, rf_port + i, tx_freq_hz); - radio_h->set_rx_freq(0, rf_port + i, rx_freq_hz); - } - log_h->console("RF%d: samp_rate=%.2f MHz, DL=%.1f Mhz, UL=%.1f MHz\n", - cc_idx, - samp_rate / 1e6f, - tx_freq_hz / 1e6f, - rx_freq_hz / 1e6f); + log_h->console( + "Setting frequency: DL=%.1f Mhz, UL=%.1f MHz for cc_idx=%d\n", tx_freq_hz / 1e6f, rx_freq_hz / 1e6f, cc_idx); + radio_h->set_tx_freq(rf_port, tx_freq_hz); + radio_h->set_rx_freq(rf_port, rx_freq_hz); } // Set channel emulator sampling rate @@ -131,14 +126,15 @@ void txrx::run_thread() for (uint32_t cc = 0; cc < worker_com->get_nof_carriers(); cc++) { uint32_t rf_port = worker_com->get_rf_port(cc); for (uint32_t p = 0; p < worker_com->get_nof_ports(cc); p++) { - buffer[rf_port + p] = worker->get_buffer_rx(cc, p); + // WARNING: The number of ports for all cells must be the same + buffer.set(rf_port, p, worker_com->get_nof_ports(0), worker->get_buffer_rx(cc, p)); } } - radio_h->rx_now(0, buffer, sf_len, &rx_time); + radio_h->rx_now(buffer, sf_len, &rx_time); if (ul_channel) { - ul_channel->run(buffer, buffer, sf_len, rx_time); + ul_channel->run(buffer.to_cf_t(), buffer.to_cf_t(), sf_len, rx_time); } /* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */ @@ -161,7 +157,7 @@ void txrx::run_thread() // Trigger prach worker execution for (uint32_t cc = 0; cc < worker_com->get_nof_carriers(); cc++) { - prach->new_tti(cc, tti, buffer[worker_com->get_rf_port(cc) * worker_com->get_nof_ports(cc)]); + prach->new_tti(cc, tti, buffer.get(worker_com->get_rf_port(cc), 0, worker_com->get_nof_ports(0))); } } else { // wait_worker() only returns NULL if it's being closed. Quit now to avoid unnecessary loops here diff --git a/srsenb/src/radio/CMakeLists.txt b/srsenb/src/radio/CMakeLists.txt deleted file mode 100644 index 638d25d3f..000000000 --- a/srsenb/src/radio/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright 2013-2019 Software Radio Systems Limited -# -# This file is part of srsLTE -# -# srsLTE 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. -# -# srsLTE 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/. -# - -file(GLOB SOURCES "*.cc") -add_library(srsenb_radio STATIC ${SOURCES}) \ No newline at end of file diff --git a/srsenb/src/radio/enb_radio_multi.cc b/srsenb/src/radio/enb_radio_multi.cc deleted file mode 100644 index 4b792ebcc..000000000 --- a/srsenb/src/radio/enb_radio_multi.cc +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2013-2019 Software Radio Systems Limited - * - * This file is part of srsLTE. - * - * srsLTE 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. - * - * srsLTE 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 "srsenb/hdr/radio/enb_radio_multi.h" -#include - -namespace srsenb { - -enb_radio_multi::enb_radio_multi(srslte::logger* logger_) : radio_multi(logger_) {} - -enb_radio_multi::~enb_radio_multi() {} - -int enb_radio_multi::init(const srslte::rf_args_t& args_, srslte::phy_interface_radio* phy_) -{ - return radio_multi::init(args_, phy_); -} - -} // namespace srsenb diff --git a/srsenb/test/phy/enb_phy_test.cc b/srsenb/test/phy/enb_phy_test.cc index c05023ed0..6e7c748eb 100644 --- a/srsenb/test/phy/enb_phy_test.cc +++ b/srsenb/test/phy/enb_phy_test.cc @@ -181,8 +181,7 @@ public: } } - bool - tx(const uint32_t& radio_idx, cf_t** buffer, const uint32_t& nof_samples, const srslte_timestamp_t& tx_time) override + bool tx(srslte::rf_buffer_interface& buffer, const uint32_t& nof_samples, const srslte_timestamp_t& tx_time) override { int err = SRSLTE_SUCCESS; @@ -193,7 +192,7 @@ public: // Write ring buffer for (uint32_t i = 0; i < ringbuffers_tx.size() and err >= SRSLTE_SUCCESS; i++) { - err = srslte_ringbuffer_write(ringbuffers_tx[i], buffer[i], nbytes); + err = srslte_ringbuffer_write(ringbuffers_tx[i], buffer.get(i), nbytes); } // Notify call @@ -203,8 +202,7 @@ public: return err >= SRSLTE_SUCCESS; } void tx_end() override {} - bool - rx_now(const uint32_t& radio_idx, cf_t** buffer, const uint32_t& nof_samples, srslte_timestamp_t* rxd_time) override + bool rx_now(srslte::rf_buffer_interface& buffer, const uint32_t& nof_samples, srslte_timestamp_t* rxd_time) override { int err = SRSLTE_SUCCESS; @@ -216,7 +214,7 @@ public: // Write ring buffer for (uint32_t i = 0; i < ringbuffers_rx.size() and err >= SRSLTE_SUCCESS; i++) { do { - err = srslte_ringbuffer_read_timed(ringbuffers_rx[i], buffer[i], nbytes, 1000); + err = srslte_ringbuffer_read_timed(ringbuffers_rx[i], buffer.get(i), nbytes, 1000); } while (err < SRSLTE_SUCCESS and running); } @@ -236,24 +234,20 @@ public: // Return True if err >= SRSLTE_SUCCESS return err >= SRSLTE_SUCCESS; } - void set_tx_freq(const uint32_t& radio_idx, const uint32_t& channel_idx, const double& freq) override {} - void set_rx_freq(const uint32_t& radio_idx, const uint32_t& channel_idx, const double& freq) override {} + void set_tx_freq(const uint32_t& channel_idx, const double& freq) override {} + void set_rx_freq(const uint32_t& channel_idx, const double& freq) override {} void set_rx_gain_th(const float& gain) override {} - void set_rx_gain(const uint32_t& radio_idx, const float& gain) override {} - void set_tx_srate(const uint32_t& radio_idx, const double& srate) override {} - void set_rx_srate(const uint32_t& radio_idx, const double& srate) override { rx_srate = srate; } - float get_rx_gain(const uint32_t& radio_idx) override { return 0; } + void set_rx_gain(const float& gain) override {} + void set_tx_srate(const double& srate) override {} + void set_rx_srate(const double& srate) override { rx_srate = srate; } + void set_tx_gain(const float& gain) override {} + float get_rx_gain() override { return 0; } double get_freq_offset() override { return 0; } - double get_tx_freq(const uint32_t& radio_idx) override { return 0; } - double get_rx_freq(const uint32_t& radio_idx) override { return 0; } - float get_max_tx_power() override { return 0; } - float get_tx_gain_offset() override { return 0; } - float get_rx_gain_offset() override { return 0; } bool is_continuous_tx() override { return false; } - bool get_is_start_of_burst(const uint32_t& radio_idx) override { return false; } + bool get_is_start_of_burst() override { return false; } bool is_init() override { return false; } void reset() override {} - srslte_rf_info_t* get_info(const uint32_t& radio_idx) override { return nullptr; } + srslte_rf_info_t* get_info() override { return nullptr; } }; typedef std::unique_ptr unique_dummy_radio_t; @@ -725,9 +719,7 @@ public: std::string log_level, uint16_t rnti_, const srsenb::phy_interface_rrc_lte::phy_rrc_dedicated_list_t& phy_rrc_cfg_) : - radio(_radio), - log_h("UE PHY", nullptr, true), - phy_rrc_cfg(phy_rrc_cfg_) + radio(_radio), log_h("UE PHY", nullptr, true), phy_rrc_cfg(phy_rrc_cfg_) { // Calculate subframe length sf_len = static_cast(SRSLTE_SF_LEN_PRB(cell_list[0].cell.nof_prb)); diff --git a/srsue/hdr/phy/phy.h b/srsue/hdr/phy/phy.h index b7e373ecd..b33d63be2 100644 --- a/srsue/hdr/phy/phy.h +++ b/srsue/hdr/phy/phy.h @@ -25,11 +25,10 @@ #include "phy_common.h" #include "phy_metrics.h" #include "prach.h" -#include "scell/async_scell_recv.h" #include "sf_worker.h" #include "srslte/common/log_filter.h" #include "srslte/common/trace.h" -#include "srslte/interfaces/common_interfaces.h" +#include "srslte/interfaces/radio_interfaces.h" #include "srslte/interfaces/ue_interfaces.h" #include "srslte/radio/radio.h" #include "srslte/srslte.h" @@ -149,7 +148,6 @@ private: std::vector > workers; phy_common common; sync sfsync; - scell::async_recv_vector scell_sync; prach prach_buffer; srslte_prach_cfg_t prach_cfg = {}; @@ -161,7 +159,7 @@ private: /* Current time advance */ uint32_t n_ta = 0; - void set_default_args(phy_args_t* args); + static void set_default_args(phy_args_t& args); bool check_args(const phy_args_t& args); }; diff --git a/srsue/hdr/phy/phy_common.h b/srsue/hdr/phy/phy_common.h index b838380d5..eaf784bf7 100644 --- a/srsue/hdr/phy/phy_common.h +++ b/srsue/hdr/phy/phy_common.h @@ -26,7 +26,7 @@ #include "srslte/common/gen_mch_tables.h" #include "srslte/common/log.h" #include "srslte/common/tti_sempahore.h" -#include "srslte/interfaces/common_interfaces.h" +#include "srslte/interfaces/radio_interfaces.h" #include "srslte/interfaces/ue_interfaces.h" #include "srslte/radio/radio.h" #include "srslte/srslte.h" @@ -133,11 +133,8 @@ public: srslte_pdsch_ack_resource_t resource); bool get_dl_pending_ack(srslte_ul_sf_cfg_t* sf, uint32_t cc_idx, srslte_pdsch_ack_cc_t* ack); - void worker_end(void* h, - bool tx_enable, - cf_t* buffer[SRSLTE_MAX_RADIOS][SRSLTE_MAX_PORTS], - uint32_t nof_samples[SRSLTE_MAX_RADIOS], - srslte_timestamp_t tx_time[SRSLTE_MAX_RADIOS]); + void + worker_end(void* h, bool tx_enable, srslte::rf_buffer_t& buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); void set_cell(const srslte_cell_t& c); void set_nof_workers(uint32_t nof_workers); diff --git a/srsue/hdr/phy/sf_worker.h b/srsue/hdr/phy/sf_worker.h index eb9a7d841..ee983aa25 100644 --- a/srsue/hdr/phy/sf_worker.h +++ b/srsue/hdr/phy/sf_worker.h @@ -55,7 +55,7 @@ public: cf_t* get_buffer(uint32_t cc_idx, uint32_t antenna_idx); uint32_t get_buffer_len(); void set_tti(uint32_t tti); - void set_tx_time(uint32_t radio_idx, srslte_timestamp_t tx_time, int next_offset); + void set_tx_time(srslte_timestamp_t tx_time, int next_offset); void set_prach(cf_t* prach_ptr, float prach_power); void set_cfo(const uint32_t& cc_idx, float cfo); @@ -109,9 +109,9 @@ private: cf_t* prach_ptr = nullptr; float prach_power = 0; - uint32_t tti = 0; - srslte_timestamp_t tx_time[SRSLTE_MAX_RADIOS] = {}; - int next_offset[SRSLTE_MAX_RADIOS] = {}; + uint32_t tti = 0; + srslte_timestamp_t tx_time = {}; + int next_offset = {}; uint32_t rssi_read_cnt = 0; }; diff --git a/srsue/hdr/phy/sync.h b/srsue/hdr/phy/sync.h index 89226991b..640425cd7 100644 --- a/srsue/hdr/phy/sync.h +++ b/srsue/hdr/phy/sync.h @@ -35,9 +35,9 @@ #include "srslte/common/thread_pool.h" #include "srslte/common/threads.h" #include "srslte/common/tti_sync_cv.h" +#include "srslte/interfaces/radio_interfaces.h" #include "srslte/interfaces/ue_interfaces.h" #include "srslte/srslte.h" -#include "srsue/hdr/phy/scell/async_scell_recv.h" #include @@ -48,7 +48,7 @@ typedef _Complex float cf_t; class sync : public srslte::thread, public chest_feedback_itf { public: - sync() : thread("SYNC"){}; + sync() : thread("SYNC"), sf_buffer(sync_nof_rx_subframes){}; ~sync(); void init(srslte::radio_interface_phy* radio_, @@ -58,7 +58,6 @@ public: phy_common* _worker_com, srslte::log* _log_h, srslte::log* _log_phy_lib_h, - scell::async_recv_vector* scell_sync_, uint32_t prio, int sync_cpu_affinity = -1); void stop(); @@ -90,7 +89,7 @@ public: // Other functions void set_rx_gain(float gain); - int radio_recv_fnc(cf_t* data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t* rx_time); + int radio_recv_fnc(srslte::rf_buffer_t&, uint32_t nsamples, srslte_timestamp_t* rx_time); private: // Class to run cell search @@ -100,19 +99,19 @@ private: typedef enum { CELL_NOT_FOUND, CELL_FOUND, ERROR, TIMEOUT } ret_code; ~search(); - void init(cf_t* buffer[SRSLTE_MAX_PORTS], srslte::log* log_h, uint32_t nof_rx_antennas, sync* parent); + void init(srslte::rf_buffer_t& buffer_, srslte::log* log_h, uint32_t nof_rx_channels, sync* parent); void reset(); float get_last_cfo(); void set_agc_enable(bool enable); ret_code run(srslte_cell_t* cell, std::array& bch_payload); private: - sync* p = nullptr; - srslte::log* log_h = nullptr; - cf_t* buffer[SRSLTE_MAX_PORTS] = {}; - srslte_ue_cellsearch_t cs = {}; - srslte_ue_mib_sync_t ue_mib_sync = {}; - int force_N_id_2 = 0; + sync* p = nullptr; + srslte::log* log_h = nullptr; + srslte::rf_buffer_t buffer = {}; + srslte_ue_cellsearch_t cs = {}; + srslte_ue_mib_sync_t ue_mib_sync = {}; + int force_N_id_2 = 0; }; // Class to synchronize system frame number @@ -122,11 +121,11 @@ private: typedef enum { IDLE, SFN_FOUND, SFX0_FOUND, SFN_NOFOUND, ERROR } ret_code; sfn_sync() = default; ~sfn_sync(); - void init(srslte_ue_sync_t* ue_sync, - cf_t* buffer[SRSLTE_MAX_PORTS], - uint32_t buffer_max_samples_, - srslte::log* log_h, - uint32_t nof_subframes = SFN_SYNC_NOF_SUBFRAMES); + void init(srslte_ue_sync_t* ue_sync, + srslte::rf_buffer_t& buffer, + uint32_t buffer_max_samples_, + srslte::log* log_h, + uint32_t nof_subframes = SFN_SYNC_NOF_SUBFRAMES); void reset(); bool set_cell(srslte_cell_t cell); ret_code run_subframe(srslte_cell_t* cell, @@ -135,20 +134,20 @@ private: bool sfidx_only = false); ret_code decode_mib(srslte_cell_t* cell, uint32_t* tti_cnt, - cf_t* ext_buffer[SRSLTE_MAX_PORTS], + srslte::rf_buffer_t* ext_buffer, std::array& bch_payload, bool sfidx_only = false); private: const static int SFN_SYNC_NOF_SUBFRAMES = 100; - uint32_t cnt = 0; - uint32_t timeout = 0; - srslte::log* log_h = nullptr; - srslte_ue_sync_t* ue_sync = nullptr; - cf_t* buffer[SRSLTE_MAX_PORTS] = {}; - uint32_t buffer_max_samples = 0; - srslte_ue_mib_t ue_mib = {}; + uint32_t cnt = 0; + uint32_t timeout = 0; + srslte::log* log_h = nullptr; + srslte_ue_sync_t* ue_sync = nullptr; + srslte::rf_buffer_t mib_buffer = {}; + uint32_t buffer_max_samples = 0; + srslte_ue_mib_t ue_mib = {}; }; /* TODO: Intra-freq measurements can be improved by capturing 200 ms length signal and run cell search + @@ -176,9 +175,9 @@ private: sfn_sync sfn_p; std::vector > intra_freq_meas; - uint32_t current_sflen = 0; - int next_offset = 0; // Sample offset triggered by Time aligment commands - int next_radio_offset[SRSLTE_MAX_RADIOS] = {}; // Sample offset triggered by SFO compensation + uint32_t current_sflen = 0; + int next_offset = 0; // Sample offset triggered by Time aligment commands + int next_radio_offset = 0; // Sample offset triggered by SFO compensation // Pointers to other classes stack_interface_phy_lte* stack = nullptr; @@ -188,14 +187,14 @@ private: srslte::radio_interface_phy* radio_h = nullptr; phy_common* worker_com = nullptr; prach* prach_buffer = nullptr; - scell::async_recv_vector* scell_sync = nullptr; srslte::channel_ptr channel_emulator = nullptr; // Object for synchronization of the primary cell srslte_ue_sync_t ue_sync = {}; // Buffer for primary and secondary cell samples - cf_t* sf_buffer[SRSLTE_MAX_RADIOS][SRSLTE_MAX_PORTS] = {}; + const static uint32_t sync_nof_rx_subframes = 5; + srslte::rf_buffer_t sf_buffer = {}; // Sync metrics sync_metrics_t metrics = {}; @@ -349,10 +348,10 @@ private: uint32_t tti = 0; srslte_timestamp_t tti_ts = {}; srslte_timestamp_t radio_ts = {}; - std::array mib; - - uint32_t nof_workers = 0; + std::array mib = {}; + uint32_t nof_workers = 0; + uint32_t nof_rf_channels = 0; float ul_dl_factor = NAN; int current_earfcn = 0; uint32_t cellsearch_earfcn_index = 0; diff --git a/srsue/hdr/phy/ue_lte_phy_base.h b/srsue/hdr/phy/ue_lte_phy_base.h index 1c5ce809f..5f3fc348f 100644 --- a/srsue/hdr/phy/ue_lte_phy_base.h +++ b/srsue/hdr/phy/ue_lte_phy_base.h @@ -28,7 +28,7 @@ #define SRSUE_UE_LTE_PHY_BASE_H #include "srslte/common/log_filter.h" -#include "srslte/interfaces/common_interfaces.h" +#include "srslte/interfaces/radio_interfaces.h" #include "srsue/hdr/phy/ue_phy_base.h" namespace srsue { diff --git a/srsue/hdr/ue.h b/srsue/hdr/ue.h index 7b44d3892..10e5e541f 100644 --- a/srsue/hdr/ue.h +++ b/srsue/hdr/ue.h @@ -37,7 +37,7 @@ #include "srslte/common/log_filter.h" #include "srslte/common/logger_file.h" #include "srslte/interfaces/ue_interfaces.h" -#include "srslte/radio/radio_base.h" +#include "srslte/radio/radio.h" #include "stack/ue_stack_base.h" #include "ue_metrics_interface.h" @@ -108,7 +108,7 @@ public: private: // UE consists of a radio, a PHY and a stack element std::unique_ptr phy; - std::unique_ptr radio; + std::unique_ptr radio; std::unique_ptr stack; std::unique_ptr gw_inst; diff --git a/srsue/src/CMakeLists.txt b/srsue/src/CMakeLists.txt index c92ebbf7c..a966b77a7 100644 --- a/srsue/src/CMakeLists.txt +++ b/srsue/src/CMakeLists.txt @@ -61,6 +61,8 @@ endif(NOT SRSGUI_FOUND) # Checks that ue.conf.example is valid and it does not leak memory if RF fails if (ZEROMQ_FOUND) add_test(ue_rf_failure srsue ${CMAKE_SOURCE_DIR}/srsue/ue.conf.example --rf.device_name=zmq) + add_test(ue_rf_failure_max_channels srsue ${CMAKE_SOURCE_DIR}/srsue/ue.conf.example --rf.device_name=zmq --rf.nof_antennas=4 --rf.nof_carriers=5) + add_test(ue_rf_failure_exceeds_channels srsue ${CMAKE_SOURCE_DIR}/srsue/ue.conf.example --rf.device_name=zmq --rf.nof_antennas=5 --rf.nof_carriers=5) endif(ZEROMQ_FOUND) ######################################################################## diff --git a/srsue/src/main.cc b/srsue/src/main.cc index 587ce2720..949865cd0 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -78,22 +78,18 @@ static int parse_args(all_args_t* args, int argc, char* argv[]) ("ue.phy", bpo::value(&args->phy.type)->default_value("lte"), "Type of the PHY [lte]") ("ue.stack", bpo::value(&args->stack.type)->default_value("lte"), "Type of the upper stack [lte]") - ("rf.dl_earfcn", bpo::value(&args->phy.dl_earfcn)->default_value("3400"), "Downlink EARFCN list") - ("rf.freq_offset", bpo::value(&args->rf.freq_offset)->default_value(0), "(optional) Frequency offset") - ("rf.dl_freq", bpo::value(&args->phy.dl_freq)->default_value(-1), "Downlink Frequency (if positive overrides EARFCN)") - ("rf.ul_freq", bpo::value(&args->phy.ul_freq)->default_value(-1), "Uplink Frequency (if positive overrides EARFCN)") - ("rf.rx_gain", bpo::value(&args->rf.rx_gain)->default_value(-1), "Front-end receiver gain") - ("rf.tx_gain", bpo::value(&args->rf.tx_gain)->default_value(-1), "Front-end transmitter gain") - ("rf.nof_radios", bpo::value(&args->rf.nof_radios)->default_value(1), "Number of available RF devices") - ("rf.nof_rf_channels", bpo::value(&args->rf.nof_rf_channels)->default_value(1), "Number of RF channels per radio") - ("rf.nof_rx_ant", bpo::value(&args->rf.nof_rx_ant)->default_value(1), "Number of RX antennas per channel") + ("rf.dl_earfcn", bpo::value(&args->phy.dl_earfcn)->default_value("3400"), "Downlink EARFCN list") + ("rf.freq_offset", bpo::value(&args->rf.freq_offset)->default_value(0), "(optional) Frequency offset") + ("rf.dl_freq", bpo::value(&args->phy.dl_freq)->default_value(-1), "Downlink Frequency (if positive overrides EARFCN)") + ("rf.ul_freq", bpo::value(&args->phy.ul_freq)->default_value(-1), "Uplink Frequency (if positive overrides EARFCN)") + ("rf.rx_gain", bpo::value(&args->rf.rx_gain)->default_value(-1), "Front-end receiver gain") + ("rf.tx_gain", bpo::value(&args->rf.tx_gain)->default_value(-1), "Front-end transmitter gain") + ("rf.nof_carriers", bpo::value(&args->rf.nof_carriers)->default_value(1), "Number of carriers") + ("rf.nof_antennas", bpo::value(&args->rf.nof_antennas)->default_value(1), "Number of antennas per carrier") ("rf.device_name", bpo::value(&args->rf.device_name)->default_value("auto"), "Front-end device name") - ("rf.device_args", bpo::value(&args->rf.device_args[0])->default_value("auto"), "Front-end device arguments") - ("rf.device_args_2", bpo::value(&args->rf.device_args[1])->default_value("auto"), "Front-end device 2 arguments") - ("rf.device_args_3", bpo::value(&args->rf.device_args[2])->default_value("auto"), "Front-end device 3 arguments") + ("rf.device_args", bpo::value(&args->rf.device_args)->default_value("auto"), "Front-end device arguments") ("rf.time_adv_nsamples", bpo::value(&args->rf.time_adv_nsamples)->default_value("auto"), "Transmission time advance") - ("rf.burst_preamble_us", bpo::value(&args->rf.burst_preamble)->default_value("auto"), "Transmission time advance") ("rf.continuous_tx", bpo::value(&args->rf.continuous_tx)->default_value("auto"), "Transmit samples continuously to the radio or on bursts (auto/yes/no). Default is auto (yes for UHD, no for rest)") ("rrc.feature_group", bpo::value(&args->stack.rrc.feature_group)->default_value(0xe6041000), "Hex value of the featureGroupIndicators field in the" diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index dfc2e2eac..5e4d57f20 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -77,33 +77,33 @@ void phy::srslte_phy_logger(phy_logger_level_t log_level, char* str) } } -void phy::set_default_args(phy_args_t* args) -{ - args->nof_rx_ant = 1; - args->ul_pwr_ctrl_en = false; - args->prach_gain = -1; - args->cqi_max = -1; - args->cqi_fixed = -1; - args->snr_ema_coeff = 0.1; - args->snr_estim_alg = "refs"; - args->pdsch_max_its = 4; - args->nof_phy_threads = DEFAULT_WORKERS; - args->equalizer_mode = "mmse"; - args->cfo_integer_enabled = false; - args->cfo_correct_tol_hz = 50; - args->sss_algorithm = "full"; - args->estimator_fil_auto = false; - args->estimator_fil_stddev = 1.0f; - args->estimator_fil_order = 4; -} - -bool phy::check_args(const phy_args_t& args) -{ - if (args.nof_phy_threads > MAX_WORKERS) { +void phy::set_default_args(phy_args_t& args_) +{ + args_.nof_rx_ant = 1; + args_.ul_pwr_ctrl_en = false; + args_.prach_gain = -1; + args_.cqi_max = -1; + args_.cqi_fixed = -1; + args_.snr_ema_coeff = 0.1; + args_.snr_estim_alg = "refs"; + args_.pdsch_max_its = 4; + args_.nof_phy_threads = DEFAULT_WORKERS; + args_.equalizer_mode = "mmse"; + args_.cfo_integer_enabled = false; + args_.cfo_correct_tol_hz = 50; + args_.sss_algorithm = "full"; + args_.estimator_fil_auto = false; + args_.estimator_fil_stddev = 1.0f; + args_.estimator_fil_order = 4; +} + +bool phy::check_args(const phy_args_t& args_) +{ + if (args_.nof_phy_threads > MAX_WORKERS) { log_h->console("Error in PHY args: nof_phy_threads must be 1, 2 or 3\n"); return false; } - if (args.snr_ema_coeff > 1.0) { + if (args_.snr_ema_coeff > 1.0) { log_h->console("Error in PHY args: snr_ema_coeff must be 0<=w<=1\n"); return false; } @@ -193,13 +193,6 @@ void phy::run_thread() workers.push_back(std::move(w)); } - // Load Asynchronous SCell objects - for (int i = 0; i < (int)args.nof_radios - 1; i++) { - auto t = scell::async_recv_ptr(new scell::async_scell_recv()); - t->init(radio, &common, log_h); - scell_sync.push_back(std::move(t)); - } - // Warning this must be initialized after all workers have been added to the pool sfsync.init(radio, stack, @@ -208,7 +201,6 @@ void phy::run_thread() &common, log_h, log_phy_lib_h, - &scell_sync, SF_RECV_THREAD_PRIO, args.sync_cpu_affinity); @@ -238,10 +230,6 @@ void phy::stop() std::unique_lock lock(config_mutex); if (is_configured) { sfsync.stop(); - for (uint32_t i = 0; i < args.nof_radios - 1; i++) { - scell_sync.at(i)->stop(); - } - workers_pool.stop(); prach_buffer.stop(); @@ -342,7 +330,7 @@ bool phy::cell_is_camping() float phy::get_phr() { - float phr = radio->get_max_tx_power() - common.cur_pusch_power; + float phr = radio->get_info()->max_tx_gain - common.cur_pusch_power; return phr; } @@ -445,8 +433,6 @@ void phy::set_config(srslte::phy_cfg_t& config_, uint32_t cc_idx, uint32_t earfc // Component carrier index zero should be reserved for PCell if (cc_idx < args.nof_carriers) { - carrier_map_t* m = &args.carrier_map[cc_idx]; - // Send configuration to workers for (uint32_t i = 0; i < nof_workers; i++) { if (cell_info) { @@ -463,19 +449,12 @@ void phy::set_config(srslte::phy_cfg_t& config_, uint32_t cc_idx, uint32_t earfc if (cc_idx == 0) { prach_cfg = config_.prach_cfg; } else if (cell_info) { - // If SCell does not share synchronism with PCell ... - if (m->radio_idx > 0) { - scell_sync.at(m->radio_idx - 1)->set_scell_cell(cc_idx, cell_info, earfcn); - } else { - // Change frequency only if the earfcn was modified - if (common.scell_cfg[cc_idx].earfcn != earfcn) { - float dl_freq = srslte_band_fd(earfcn) * 1e6f; - float ul_freq = srslte_band_fu(srslte_band_ul_earfcn(earfcn)) * 1e6f; - for (uint32_t p = 0; p < common.args->nof_rx_ant; p++) { - radio->set_rx_freq(m->radio_idx, m->channel_idx + p, dl_freq); - radio->set_tx_freq(m->radio_idx, m->channel_idx + p, ul_freq); - } - } + // Change frequency only if the earfcn was modified + if (common.scell_cfg[cc_idx].earfcn != earfcn) { + float dl_freq = srslte_band_fd(earfcn) * 1e6f; + float ul_freq = srslte_band_fu(srslte_band_ul_earfcn(earfcn)) * 1e6f; + radio->set_rx_freq(cc_idx, dl_freq); + radio->set_tx_freq(cc_idx, ul_freq); } // Store SCell earfcn and pci diff --git a/srsue/src/phy/phy_common.cc b/srsue/src/phy/phy_common.cc index cc827cf4e..f4213b02a 100644 --- a/srsue/src/phy/phy_common.cc +++ b/srsue/src/phy/phy_common.cc @@ -42,8 +42,7 @@ using namespace asn1::rrc; namespace srsue { -static cf_t zeros[50000] = {}; -static cf_t* zeros_multi[SRSLTE_MAX_PORTS] = {zeros, zeros, zeros, zeros}; +static srslte::rf_buffer_t zeros_multi(1); phy_common::phy_common() { @@ -73,8 +72,7 @@ void phy_common::init(phy_args_t* _args, // Instantiate UL channel emulator if (args->ul_channel_args.enable) { - ul_channel = - srslte::channel_ptr(new srslte::channel(args->ul_channel_args, args->nof_rf_channels * args->nof_rx_ant)); + ul_channel = srslte::channel_ptr(new srslte::channel(args->ul_channel_args, args->nof_carriers * args->nof_rx_ant)); } } @@ -525,45 +523,41 @@ bool phy_common::get_dl_pending_ack(srslte_ul_sf_cfg_t* sf, uint32_t cc_idx, srs * Each worker uses this function to indicate that all processing is done and data is ready for transmission or * there is no transmission at all (tx_enable). In that case, the end of burst message will be sent to the radio */ -void phy_common::worker_end(void* tx_sem_id, - bool tx_enable, - cf_t* buffer[SRSLTE_MAX_RADIOS][SRSLTE_MAX_PORTS], - uint32_t nof_samples[SRSLTE_MAX_RADIOS], - srslte_timestamp_t tx_time[SRSLTE_MAX_RADIOS]) +void phy_common::worker_end(void* tx_sem_id, + bool tx_enable, + srslte::rf_buffer_t& buffer, + uint32_t nof_samples, + srslte_timestamp_t tx_time) { // Wait for the green light to transmit in the current TTI semaphore.wait(tx_sem_id); // For each radio, transmit - for (uint32_t i = 0; i < args->nof_radios; i++) { - if (tx_enable && !srslte_timestamp_iszero(&tx_time[i])) { + if (tx_enable && !srslte_timestamp_iszero(&tx_time)) { - if (ul_channel) { - ul_channel->run(buffer[i], buffer[i], nof_samples[i], tx_time[i]); - } - - radio_h->tx(i, buffer[i], nof_samples[i], tx_time[i]); - } else { - if (radio_h->is_continuous_tx()) { - if (is_pending_tx_end) { - radio_h->tx_end(); - is_pending_tx_end = false; - } else { - if (!radio_h->get_is_start_of_burst(i)) { + if (ul_channel) { + ul_channel->run(buffer.to_cf_t(), buffer.to_cf_t(), nof_samples, tx_time); + } - if (ul_channel && !srslte_timestamp_iszero(&tx_time[i])) { - bzero(zeros_multi[0], sizeof(cf_t) * nof_samples[i]); - ul_channel->run(zeros_multi, zeros_multi, nof_samples[i], tx_time[i]); - } + radio_h->tx(buffer, nof_samples, tx_time); + } else { + if (radio_h->is_continuous_tx()) { + if (is_pending_tx_end) { + radio_h->tx_end(); + is_pending_tx_end = false; + } else { + if (!radio_h->get_is_start_of_burst()) { - radio_h->tx(i, zeros_multi, nof_samples[i], tx_time[i]); + if (ul_channel && !srslte_timestamp_iszero(&tx_time)) { + srslte_vec_cf_zero(zeros_multi.get(0), nof_samples); + ul_channel->run(zeros_multi.to_cf_t(), zeros_multi.to_cf_t(), nof_samples, tx_time); } - } - } else { - if (i == 0) { - radio_h->tx_end(); + + radio_h->tx(zeros_multi, nof_samples, tx_time); } } + } else { + radio_h->tx_end(); } } @@ -622,9 +616,9 @@ void phy_common::set_ul_metrics(const ul_metrics_t m, uint32_t cc_idx) } } -void phy_common::get_ul_metrics(ul_metrics_t m[SRSLTE_MAX_RADIOS]) +void phy_common::get_ul_metrics(ul_metrics_t m[SRSLTE_MAX_CARRIERS]) { - memcpy(m, ul_metrics, sizeof(ul_metrics_t) * SRSLTE_MAX_RADIOS); + memcpy(m, ul_metrics, sizeof(ul_metrics_t) * SRSLTE_MAX_CARRIERS); ul_metrics_read = true; } diff --git a/srsue/src/phy/scell/async_scell_recv.cc b/srsue/src/phy/scell/async_scell_recv.cc deleted file mode 100644 index a493231df..000000000 --- a/srsue/src/phy/scell/async_scell_recv.cc +++ /dev/null @@ -1,621 +0,0 @@ -/* - * Copyright 2013-2019 Software Radio Systems Limited - * - * This file is part of srsLTE. - * - * srsLTE 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. - * - * srsLTE 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 "srsue/hdr/phy/scell/async_scell_recv.h" -#include "srsue/hdr/phy/phy_common.h" -#include -#include -#include -#include -#include - -#define LOG_PREABLE "[scell_recv] " - -#define LOG_ALL_CONSOLE 0 - -#if LOG_ALL_CONSOLE -#define Error(fmt, ...) log_h->console(LOG_PREABLE fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) log_h->console(LOG_PREABLE fmt, ##__VA_ARGS__) -#define Info(fmt, ...) log_h->console(LOG_PREABLE fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) log_h->console(LOG_PREABLE fmt, ##__VA_ARGS__) -#else -#define Error(fmt, ...) log_h->error(LOG_PREABLE fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) log_h->warning(LOG_PREABLE fmt, ##__VA_ARGS__) -#define Info(fmt, ...) log_h->info(LOG_PREABLE fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) log_h->debug(LOG_PREABLE fmt, ##__VA_ARGS__) -#endif - -namespace srsue { -namespace scell { - -async_scell_recv::async_scell_recv() : thread("ASYNC_SCELL_RECV") -{ - initiated = false; - buffer_write_idx = 0; - buffer_read_idx = 0; - dl_freq = -1; - ul_freq = -1; - bzero(&cell, sizeof(srslte_cell_t)); - bzero(sf_buffer, sizeof(sf_buffer)); - running = false; - radio_idx = 1; - current_sflen = 0; - next_radio_offset = 0; -} - -async_scell_recv::~async_scell_recv() -{ - if (initiated) { - srslte_ue_sync_free(&ue_sync); - } - - for (auto& b : sf_buffer) { - if (b) { - free(b); - } - } -} - -static int radio_recv_callback(void* obj, cf_t* data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t* rx_time) -{ - return ((async_scell_recv*)obj)->radio_recv_fnc(data, nsamples, rx_time); -} - -static SRSLTE_AGC_CALLBACK(callback_set_rx_gain) -{ - ((async_scell_recv*)h)->set_rx_gain(gain_db); -} - -void async_scell_recv::init(srslte::radio_interface_phy* _radio_handler, phy_common* _worker_com, srslte::log* _log_h) -{ - // Get handlers - radio_h = _radio_handler; - worker_com = _worker_com; - log_h = _log_h; - - // Calculate number of RF channels - uint32_t nof_rf_channels = worker_com->args->nof_rf_channels * worker_com->args->nof_rx_ant; - - // Initialise buffers - for (uint32_t s = 0; s < ASYNC_NOF_BUFFERS; s++) { - buffers[s].init(nof_rf_channels); - } - - for (uint32_t i = 0; i < nof_rf_channels; i++) { - sf_buffer[i] = srslte_vec_cf_malloc(SF_BUFFER_MAX_SAMPLES); - if (!sf_buffer[i]) { - fprintf(stderr, "Error allocating buffer\n"); - return; - } - } - - if (srslte_ue_sync_init_multi(&ue_sync, SRSLTE_MAX_PRB, false, radio_recv_callback, nof_rf_channels, this)) { - fprintf(stderr, "SYNC: Initiating ue_sync\n"); - return; - } - - if (srslte_ue_mib_init(&ue_mib, sf_buffer, SRSLTE_MAX_PRB)) { - fprintf(stderr, "Error initaiting UE MIB decoder\n"); - return; - } - - if (pthread_cond_init(&cvar_buffer, nullptr)) { - fprintf(stderr, "Initiating condition var\n"); - return; - } - - reset(); - running = false; - initiated = true; -} - -void async_scell_recv::stop() -{ - running = false; - wait_thread_finish(); - - pthread_mutex_destroy(&mutex_buffer); - pthread_mutex_destroy(&mutex_uesync); - pthread_cond_destroy(&cvar_buffer); -} - -void async_scell_recv::in_sync() -{ - in_sync_cnt++; - // Send RRC in-sync signal after 100 ms consecutive subframes - if (in_sync_cnt == NOF_IN_SYNC_SF) { - in_sync_cnt = 0; - out_of_sync_cnt = 0; - } -} -void async_scell_recv::out_of_sync() -{ - // Send RRC out-of-sync signal after 200 ms consecutive subframes - Info("Out-of-sync %d/%d\n", out_of_sync_cnt, NOF_OUT_OF_SYNC_SF); - out_of_sync_cnt++; - if (out_of_sync_cnt == NOF_OUT_OF_SYNC_SF) { - Info("Sending to RRC\n"); - out_of_sync_cnt = 0; - in_sync_cnt = 0; - } -} - -void async_scell_recv::set_cfo(float cfo) -{ - srslte_ue_sync_set_cfo_ref(&ue_sync, cfo); -} - -float async_scell_recv::get_tx_cfo() -{ - float cfo = srslte_ue_sync_get_cfo(&ue_sync); - - float ret = cfo * ul_dl_factor; - - if (worker_com->args->cfo_is_doppler) { - ret *= -1; - } else { - /* Compensates the radio frequency offset applied equally to DL and UL. Does not work in doppler mode */ - if (radio_h->get_freq_offset() != 0.0f) { - const float offset_hz = (float)radio_h->get_freq_offset() * (1.0f - ul_dl_factor); - ret = cfo - offset_hz; - } - } - - return ret / 15000; -} - -void async_scell_recv::set_agc_enable(bool enable) -{ - do_agc = enable; - if (do_agc) { - if (radio_h) { - srslte_rf_info_t* rf_info = radio_h->get_info(radio_idx); - srslte_ue_sync_start_agc( - &ue_sync, callback_set_rx_gain, rf_info->min_rx_gain, rf_info->max_rx_gain, radio_h->get_rx_gain(radio_idx)); - } else { - fprintf(stderr, "Error setting Secondary cell AGC: PHY not initiated\n"); - } - } else { - fprintf(stderr, "Error stopping AGC: not implemented\n"); - } -} - -void async_scell_recv::set_rx_gain(float gain) -{ - radio_h->set_rx_gain_th(gain); -} - -int async_scell_recv::radio_recv_fnc(cf_t* data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t* rx_time) -{ - int ret = 0; - - if (running) { - if (radio_h->rx_now(radio_idx, data, nsamples, rx_time)) { - int offset = nsamples - current_sflen; - if (abs(offset) < 10 && offset != 0) { - next_radio_offset += offset; - } else if (nsamples < 10) { - next_radio_offset += nsamples; - } - - log_h->debug("SYNC: received %d samples from radio\n", nsamples); - ret = nsamples; - } else { - ret = SRSLTE_ERROR; - } - } - - return ret; -} - -void async_scell_recv::reset() -{ - in_sync_cnt = 0; - out_of_sync_cnt = 0; - - for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { - current_earfcn[i] = UINT32_MAX; - } -} - -void async_scell_recv::radio_error() -{ - log_h->error("SYNC: Receiving from radio.\n"); - // Need to find a method to effectively reset radio, reloading the driver does not work - radio_h->reset(); -} - -void async_scell_recv::set_ue_sync_opts(srslte_ue_sync_t* q, float cfo) -{ - if (worker_com->args->cfo_integer_enabled) { - srslte_ue_sync_set_cfo_i_enable(q, true); - } - - srslte_ue_sync_set_cfo_ema(q, worker_com->args->cfo_pss_ema); - srslte_ue_sync_set_cfo_tol(q, worker_com->args->cfo_correct_tol_hz); - srslte_ue_sync_set_cfo_loop_bw(q, - worker_com->args->cfo_loop_bw_pss, - worker_com->args->cfo_loop_bw_ref, - worker_com->args->cfo_loop_pss_tol, - worker_com->args->cfo_loop_ref_min, - worker_com->args->cfo_loop_pss_tol, - worker_com->args->cfo_loop_pss_conv); - - // Disable CP based CFO estimation during find - if (cfo != 0) { - q->cfo_current_value = cfo / 15000; - q->cfo_is_copied = true; - q->cfo_correct_enable_find = true; - srslte_sync_set_cfo_cp_enable(&q->sfind, false, 0); - } - - // Set SFO ema and correct period - srslte_ue_sync_set_sfo_correct_period(q, worker_com->args->sfo_correct_period); - srslte_ue_sync_set_sfo_ema(q, worker_com->args->sfo_ema); - - srslte_sync_set_sss_algorithm(&q->strack, SSS_FULL); - srslte_sync_set_sss_algorithm(&q->sfind, SSS_FULL); -} - -bool async_scell_recv::set_scell_cell(uint32_t carrier_idx, srslte_cell_t* _cell, uint32_t dl_earfcn) -{ - bool ret = true; - bool reset_ue_sync = false; - - Info("Set cell:{nof_prb=%d; cp=%s; id=%d} dl_earfcn=%d\n", - _cell->nof_prb, - srslte_cp_string(_cell->cp), - _cell->id, - dl_earfcn); - - // Lock mutex - pthread_mutex_lock(&mutex_uesync); - - // Get transceiver mapping - carrier_map_t* m = &worker_com->args->carrier_map[carrier_idx]; - uint32_t channel_idx = m->channel_idx; - radio_idx = m->radio_idx; - - // Set radio frequency if frequency changed - if (current_earfcn[channel_idx] != dl_earfcn) { - dl_freq = srslte_band_fd(dl_earfcn) * 1e6f; - ul_freq = srslte_band_fu(srslte_band_ul_earfcn(dl_earfcn)) * 1e6f; - for (uint32_t p = 0; p < worker_com->args->nof_rx_ant; p++) { - radio_h->set_rx_freq(m->radio_idx, m->channel_idx + p, dl_freq); - radio_h->set_tx_freq(m->radio_idx, m->channel_idx + p, ul_freq); - } - Info("Setting DL: %.1f MHz; UL %.1fMHz; Radio/Chan: %d/%d\n", dl_freq / 1e6, ul_freq / 1e6, radio_idx, channel_idx); - ul_dl_factor = ul_freq / dl_freq; - current_earfcn[channel_idx] = dl_earfcn; - reset_ue_sync = true; - } - - // Detect change in cell configuration - if (memcmp(&cell, _cell, sizeof(srslte_cell_t)) != 0) { - // Set sampling rate, if number of PRB changed - if (cell.nof_prb != _cell->nof_prb) { - double srate = srslte_sampling_freq_hz(_cell->nof_prb); - radio_h->set_rx_srate(radio_idx, srate); - radio_h->set_tx_srate(radio_idx, srate); - current_sflen = (uint32_t)SRSLTE_SF_LEN_PRB(_cell->nof_prb); - - Info("Setting SRate to %.2f MHz\n", srate / 1e6); - } - - // Copy cell - cell = *_cell; - reset_ue_sync = true; - - // Set cell in ue sync - if (srslte_ue_sync_set_cell(&ue_sync, cell)) { - Error("SYNC: Setting cell: initiating ue_sync\n"); - ret = false; - } - - // Set cell in MIB decoder - if (srslte_ue_mib_set_cell(&ue_mib, cell)) { - fprintf(stderr, "Error setting cell in UE MIB decoder\n"); - ret = false; - } - - srslte_ue_mib_reset(&ue_mib); - } - - // Reset ue_sync and set CFO/gain from search procedure - if (reset_ue_sync) { - srslte_ue_sync_reset(&ue_sync); - } - - // Reset thread state - state = DECODE_MIB; - - // If not running start! - if (!running) { - // Start main thread - start(1); - running = true; - } - - pthread_mutex_unlock(&mutex_uesync); - - return ret; -} - -void async_scell_recv::state_decode_mib() -{ - int sfn_offset = 0; - uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; - - uint32_t sfidx = srslte_ue_sync_get_sfidx(&ue_sync); - - if (sfidx == 0) { - // Run only for sub-frame index 0 - int n = srslte_ue_mib_decode(&ue_mib, bch_payload, nullptr, &sfn_offset); - - if (n < SRSLTE_SUCCESS) { - // Error decoding MIB, log error - Error("Error decoding UE MIB (%d)\n", n); - } else if (n == SRSLTE_UE_MIB_FOUND) { - // MIB Found - uint32_t sfn = 0; - srslte_pbch_mib_unpack(bch_payload, &cell, &sfn); - - Info("SCell MIB synchronised (SNR=%.2fdB)\n", ue_mib.chest_res.snr_db); - - // Set sub-frame index - tti = ((sfn + sfn_offset) % 1024) * 10; - - // Change state, reset ring buffer and go to Synchronized but idle - buffer_write_idx = 0; - buffer_read_idx = 0; - state = SYNCH_IDLE; - } else { - // MIB Not found - // Do nothing. Keep going. - } - } else { - // Do nothing. Keep going. - } -} - -void async_scell_recv::state_write_buffer() -{ - if (tti % SRSLTE_NOF_SF_X_FRAME != srslte_ue_sync_get_sfidx(&ue_sync) || ue_sync.state != SF_TRACK) { - // Real-time failure, go to decode MIB - Info("Detected Real-Time failure; Going to search MIB (from WRITE)\n"); - state = DECODE_MIB; - } else { - // Normal operation, try to write buffer - phch_scell_recv_buffer* buffer = &buffers[buffer_write_idx]; - srslte_timestamp_t rx_time = {}; - - // Lock mutex - pthread_mutex_lock(&mutex_buffer); - - // Copy last timestamp - srslte_ue_sync_get_last_timestamp(&ue_sync, &rx_time); - - // Extract essential information - buffer->set_sf(tti, &rx_time, next_radio_offset); - next_radio_offset = 0; - - // Increment write index - buffer_write_idx = (buffer_write_idx + 1) % ASYNC_NOF_BUFFERS; - - // Detect overflow - if (buffer_write_idx == buffer_read_idx) { - // Reset buffer and goto synchronized IDLE - Info("Detected overflow; reseting ring buffer and going to IDLE...\n"); - buffer_write_idx = 0; - buffer_read_idx = 0; - state = SYNCH_IDLE; - } - - // Unlock mutex and inform that data was received - pthread_cond_broadcast(&cvar_buffer); - pthread_mutex_unlock(&mutex_buffer); - } -} - -void async_scell_recv::state_synch_idle() -{ - if (tti % SRSLTE_NOF_SF_X_FRAME != srslte_ue_sync_get_sfidx(&ue_sync)) { - // Real-time failure, go to decode MIB - Debug("Detected Real-Time failure; Going to search MIB (from IDLE)\n"); - state = DECODE_MIB; - } else { - // Do nothing - } -} - -void async_scell_recv::run_thread() -{ - Info("Starting asynchronous scell reception...\n"); - while (running) { - phch_scell_recv_buffer* buffer = &buffers[buffer_write_idx]; - - // Lock ue_sync - pthread_mutex_lock(&mutex_uesync); - - // Get RF base-band - int ret = srslte_ue_sync_zerocopy( - &ue_sync, (state == DECODE_MIB) ? sf_buffer : buffer->get_buffer_ptr(), SF_BUFFER_MAX_SAMPLES); - if (ret < 0) { - fprintf(stderr, "Error calling srslte_ue_sync_work()\n"); - } - - // Unlock ue_sync - pthread_mutex_unlock(&mutex_uesync); - - if (ret == 1) { - // Synchronized - switch (state) { - case DECODE_MIB: - state_decode_mib(); - break; - case WRITE_BUFFER: - state_write_buffer(); - break; - case SYNCH_IDLE: - state_synch_idle(); - break; - } - - // Load metrics - sync_metrics_t metrics = {}; - metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync); - metrics.cfo = srslte_ue_sync_get_cfo(&ue_sync); - metrics.ta_us = NAN; - for (uint32_t i = 0; i < worker_com->args->nof_carriers; i++) { - if (worker_com->args->carrier_map[i].radio_idx == radio_idx) { - worker_com->set_sync_metrics(i, metrics); - } - } - - // Increment tti - tti = (tti + 1) % 10240; - } else if (ret == 0) { - // Error in synchronization - // Warning("SYNC: Out-of-sync detected in PSS/SSS\n"); - // out_of_sync(); - } - - if (ret < 0) { - // Radio error - radio_error(); - } - } -} - -bool async_scell_recv::tti_align(uint32_t tti) -{ - bool ret = false; - - if (state == SYNCH_IDLE) { - // Enable Writing in buffer - Debug("Start writing in buffer\n"); - state = WRITE_BUFFER; - } else if (state == DECODE_MIB) { - // Debug("SCell not ready for reading\n"); - return false; - } - - pthread_mutex_lock(&mutex_buffer); - - // Stage 1: Flush buffers if the tti is not available - // While data is available and no tti match, discard - while ((buffer_write_idx != buffer_read_idx) && (buffers[buffer_read_idx].get_tti() != tti)) { - // Discard buffer - Error("Expected TTI %d. Discarding tti %d.\n", tti, buffers[buffer_read_idx].get_tti()); - buffer_read_idx = (buffer_read_idx + 1) % ASYNC_NOF_BUFFERS; - } - - if ((buffers[buffer_read_idx].get_tti() == tti)) { - // tti match - ret = true; - } - - // Stage 2: If the tti is not found and the latest tti was -1; wait - // Get time and set timeout time - if (!ret) { - bool timedout = false; - - while (!ret && !timedout && buffer_write_idx == buffer_read_idx && running) { - struct timespec timeToWait = {}; - struct timeval now = {}; - - gettimeofday(&now, nullptr); - timeToWait.tv_sec = now.tv_sec; - timeToWait.tv_nsec = (now.tv_usec + 1000UL) * 1000UL; - - int rt = pthread_cond_timedwait(&cvar_buffer, &mutex_buffer, &timeToWait); - switch (rt) { - case ETIMEDOUT: - case EPERM: - // Consider all errors timed out, exit loop - timedout = true; - Error("Expected TTI %04d. timeout (%d).\n", tti, rt); - tti_align_timeout_counter++; - if (tti_align_timeout_counter > max_tti_align_timeout_counter) { - Error("Maximum number of timeouts reached (%d). Going back to decode MIB.\n", - max_tti_align_timeout_counter); - state = DECODE_MIB; - } - break; - default: - if ((buffers[buffer_read_idx].get_tti() == tti)) { - // tti match - ret = true; - } - break; - } - } - } - - pthread_mutex_unlock(&mutex_buffer); - - return ret; -} - -void async_scell_recv::read_sf(cf_t** dst, srslte_timestamp_t* timestamp, int* next_offset) -{ - pthread_mutex_lock(&mutex_buffer); - - // Block until data is filled - while (buffer_write_idx == buffer_read_idx && running) { - pthread_cond_wait(&cvar_buffer, &mutex_buffer); - } - - // Exit condition detected - if (!running) { - pthread_mutex_unlock(&mutex_buffer); - return; - } - - // Get reading buffer - phch_scell_recv_buffer* buffer = &buffers[buffer_read_idx]; - - if (dst) { - // Get data pointer - cf_t** buff = buffer->get_buffer_ptr(); - - uint32_t nof_rf_channels = worker_com->args->nof_rf_channels * worker_com->args->nof_rx_ant; - - // Copy data - for (uint32_t i = 0; i < nof_rf_channels; i++) { - if (dst[i]) { - // Check pointer is allocated - memcpy(dst[i], buff[i], sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); - } - } - } - - buffer->get_timestamp(timestamp); - buffer->get_next_offset(next_offset); - - // Increment read index - buffer_read_idx = (buffer_read_idx + 1) % ASYNC_NOF_BUFFERS; - - pthread_mutex_unlock(&mutex_buffer); -} - -} // namespace scell -} // namespace srsue diff --git a/srsue/src/phy/sf_worker.cc b/srsue/src/phy/sf_worker.cc index e0314ba3b..de780b8b7 100644 --- a/srsue/src/phy/sf_worker.cc +++ b/srsue/src/phy/sf_worker.cc @@ -138,10 +138,10 @@ void sf_worker::set_tti(uint32_t tti_) } } -void sf_worker::set_tx_time(uint32_t radio_idx, srslte_timestamp_t tx_time_, int next_offset_) +void sf_worker::set_tx_time(srslte_timestamp_t tx_time_, int next_offset_) { - next_offset[radio_idx] = next_offset_; - tx_time[radio_idx] = tx_time_; + next_offset = next_offset_; + tx_time = tx_time_; } void sf_worker::set_prach(cf_t* prach_ptr_, float prach_power_) @@ -199,8 +199,9 @@ void sf_worker::set_config(uint32_t cc_idx, srslte::phy_cfg_t& phy_cfg) void sf_worker::work_imp() { std::lock_guard lock(mutex); + srslte::rf_buffer_t tx_signal_ptr = {}; if (!cell_initiated) { - phy->worker_end(this, false, nullptr, nullptr, tx_time); + phy->worker_end(this, false, tx_signal_ptr, 0, tx_time); } /***** Downlink Processing *******/ @@ -227,12 +228,8 @@ void sf_worker::work_imp() /***** Uplink Generation + Transmission *******/ - bool tx_signal_ready = false; - cf_t* tx_signal_ptr[SRSLTE_MAX_RADIOS][SRSLTE_MAX_PORTS] = {}; - uint32_t nof_samples[SRSLTE_MAX_RADIOS] = {}; - for (uint32_t i = 0; i < phy->args->nof_radios; i++) { - nof_samples[i] = SRSLTE_SF_LEN_PRB(cell.nof_prb); - } + bool tx_signal_ready = false; + uint32_t nof_samples = SRSLTE_SF_LEN_PRB(cell.nof_prb); /* If TTI+4 is an uplink subframe (TODO: Support short PRACH and SRS in UpPts special subframes) */ if ((srslte_sfidx_tdd_type(tdd_config, TTI_TX(tti) % 10) == SRSLTE_TDD_SF_U) || cell.frame_type == SRSLTE_FDD) { @@ -247,15 +244,12 @@ void sf_worker::work_imp() for (int carrier_idx = phy->args->nof_carriers - 1; carrier_idx >= 0; carrier_idx--) { tx_signal_ready = cc_workers[carrier_idx]->work_ul(&uci_data); - // Get carrier mapping - carrier_map_t* m = &phy->args->carrier_map[carrier_idx]; - // Set signal pointer based on offset cf_t* b = cc_workers[carrier_idx]->get_tx_buffer(0); - if (next_offset[m->radio_idx] > 0) { - tx_signal_ptr[m->radio_idx][m->channel_idx] = b; + if (next_offset > 0) { + tx_signal_ptr.set(carrier_idx, 0, phy->args->nof_rx_ant, b); } else { - tx_signal_ptr[m->radio_idx][m->channel_idx] = &b[-next_offset[m->radio_idx]]; + tx_signal_ptr.set(carrier_idx, 0, phy->args->nof_rx_ant, &b[-next_offset]); } } } @@ -263,13 +257,11 @@ void sf_worker::work_imp() // Set PRACH buffer signal pointer if (prach_ptr) { - tx_signal_ready = true; - tx_signal_ptr[0][0] = prach_ptr; - prach_ptr = nullptr; + tx_signal_ready = true; + tx_signal_ptr.set(0, prach_ptr); + prach_ptr = nullptr; } else { - for (uint32_t i = 0; i < phy->args->nof_radios; i++) { - nof_samples[i] += next_offset[i]; - } + nof_samples += next_offset; } // Call worker_end to transmit the signal @@ -317,7 +309,7 @@ void sf_worker::update_measurements() } if (!rssi_read_cnt) { - phy->rx_gain_offset = phy->get_radio()->get_rx_gain(0) + phy->args->rx_gain_offset; + phy->rx_gain_offset = phy->get_radio()->get_rx_gain() + phy->args->rx_gain_offset; } rssi_read_cnt++; if (rssi_read_cnt == 1000) { diff --git a/srsue/src/phy/sync.cc b/srsue/src/phy/sync.cc index 375af3dab..4a6c41670 100644 --- a/srsue/src/phy/sync.cc +++ b/srsue/src/phy/sync.cc @@ -42,9 +42,11 @@ namespace srsue { -static int radio_recv_callback(void* obj, cf_t* data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t* rx_time) +static int +radio_recv_callback(void* obj, cf_t* data[SRSLTE_MAX_CHANNELS], uint32_t nsamples, srslte_timestamp_t* rx_time) { - return ((sync*)obj)->radio_recv_fnc(data, nsamples, rx_time); + srslte::rf_buffer_t x(data); + return ((sync*)obj)->radio_recv_fnc(x, nsamples, rx_time); } static SRSLTE_AGC_CALLBACK(callback_set_rx_gain) @@ -59,7 +61,6 @@ void sync::init(srslte::radio_interface_phy* _radio, phy_common* _worker_com, srslte::log* _log_h, srslte::log* _log_phy_lib_h, - scell::async_recv_vector* scell_sync_, uint32_t prio, int sync_cpu_affinity) { @@ -67,16 +68,14 @@ void sync::init(srslte::radio_interface_phy* _radio, log_h = _log_h; log_phy_lib_h = _log_phy_lib_h; stack = _stack; - scell_sync = scell_sync_; workers_pool = _workers_pool; worker_com = _worker_com; prach_buffer = _prach_buffer; - uint32_t nof_rf_channels = worker_com->args->nof_rf_channels * worker_com->args->nof_rx_ant; - for (uint32_t r = 0; r < worker_com->args->nof_radios; r++) { - for (uint32_t p = 0; p < nof_rf_channels; p++) { - sf_buffer[r][p] = srslte_vec_cf_malloc(SF_BUFFER_MAX_SAMPLES); - } + nof_rf_channels = worker_com->args->nof_carriers * worker_com->args->nof_rx_ant; + if (nof_rf_channels == 0 || nof_rf_channels > SRSLTE_MAX_CHANNELS) { + Error("SYNC: Invalid number of RF channels (%d)\n", nof_rf_channels); + return; } if (srslte_ue_sync_init_multi(&ue_sync, SRSLTE_MAX_PRB, false, radio_recv_callback, nof_rf_channels, this)) { @@ -92,10 +91,10 @@ void sync::init(srslte::radio_interface_phy* _radio, worker_com->set_nof_workers(nof_workers); // Initialize cell searcher - search_p.init(sf_buffer[0], log_h, nof_rf_channels, this); + search_p.init(sf_buffer, log_h, nof_rf_channels, this); // Initialize SFN synchronizer, it uses only pcell buffer - sfn_p.init(&ue_sync, sf_buffer[0], SF_BUFFER_MAX_SAMPLES, log_h); + sfn_p.init(&ue_sync, sf_buffer, sf_buffer.size(), log_h); // Start intra-frequency measurement for (uint32_t i = 0; i < worker_com->args->nof_carriers; i++) { @@ -110,13 +109,6 @@ void sync::init(srslte::radio_interface_phy* _radio, // Enable AGC for primary cell receiver set_agc_enable(worker_com->args->agc_enable); - // Enable AGC for secondary asynchronous receiver - if (scell_sync) { - for (auto& q : *scell_sync) { - q->set_agc_enable(worker_com->args->agc_enable); - } - } - // Start main thread if (sync_cpu_affinity < 0) { start(prio); @@ -127,13 +119,6 @@ void sync::init(srslte::radio_interface_phy* _radio, sync::~sync() { - for (uint32_t r = 0; r < SRSLTE_MAX_RADIOS; r++) { - for (uint32_t p = 0; p < SRSLTE_MAX_PORTS; p++) { - if (sf_buffer[r][p]) { - free(sf_buffer[r][p]); - } - } - } srslte_ue_sync_free(&ue_sync); } @@ -155,9 +140,9 @@ void sync::reset() out_of_sync_cnt = 0; time_adv_sec = 0; next_offset = 0; + next_radio_offset = 0; + current_earfcn = -1; srate_mode = SRATE_NONE; - ZERO_OBJECT(next_radio_offset); - current_earfcn = -1; sfn_p.reset(); search_p.reset(); } @@ -215,8 +200,8 @@ phy_interface_rrc_lte::cell_search_ret_t sync::cell_search(phy_interface_rrc_lte if (srate_mode != SRATE_FIND) { srate_mode = SRATE_FIND; - radio_h->set_rx_srate(0, 1.92e6); - radio_h->set_tx_srate(0, 1.92e6); + radio_h->set_rx_srate(1.92e6); + radio_h->set_tx_srate(1.92e6); Info("SYNC: Setting Cell Search sampling rate\n"); } @@ -372,22 +357,14 @@ bool sync::cell_is_camping() void sync::run_thread() { - sf_worker* worker = nullptr; - cf_t* buffer[SRSLTE_MAX_RADIOS][SRSLTE_MAX_PORTS] = {}; - srslte_cell_t temp_cell = {}; + sf_worker* worker = nullptr; + srslte_cell_t temp_cell = {}; bool is_end_of_burst = false; bool force_camping_sfn_sync = false; - cf_t* dummy_buffer[SRSLTE_MAX_PORTS]; - uint32_t nof_rf_channels = worker_com->args->nof_rf_channels * worker_com->args->nof_rx_ant; - if (nof_rf_channels > SRSLTE_MAX_PORTS) { - fprintf(stderr, "Fatal error: nof_rf_channels x nof_rx_ant must be lower than %d\n", SRSLTE_MAX_PORTS); - return; - } - for (uint32_t i = 0; i < nof_rf_channels; i++) { - dummy_buffer[i] = srslte_vec_cf_malloc(3 * SRSLTE_SF_LEN_PRB(100)); - } + srslte::rf_buffer_t dummy_buffer(sync_nof_rx_subframes); + srslte::rf_buffer_t sync_buffer = {}; uint32_t prach_nof_sf = 0; uint32_t prach_sf_cnt = 0; @@ -448,17 +425,15 @@ void sync::run_thread() worker = (sf_worker*)workers_pool->wait_worker(tti); if (worker) { - // For each carrier... + // Map carrier/antenna buffers to worker buffers for (uint32_t c = 0; c < worker_com->args->nof_carriers; c++) { - // get carrier mapping - carrier_map_t* m = &worker_com->args->carrier_map[c]; for (uint32_t i = 0; i < worker_com->args->nof_rx_ant; i++) { - buffer[m->radio_idx][m->channel_idx + i] = worker->get_buffer(c, i); + sync_buffer.set(c, i, worker_com->args->nof_rx_ant, worker->get_buffer(c, i)); } } // Primary Cell (PCell) Synchronization - switch (srslte_ue_sync_zerocopy(&ue_sync, buffer[0], worker->get_buffer_len())) { + switch (srslte_ue_sync_zerocopy(&ue_sync, sync_buffer.to_cf_t(), worker->get_buffer_len())) { case 1: // Check tti is synched with ue_sync @@ -474,7 +449,7 @@ void sync::run_thread() if (force_camping_sfn_sync) { uint32_t _tti = 0; temp_cell = cell; - sync::sfn_sync::ret_code ret = sfn_p.decode_mib(&temp_cell, &_tti, buffer[0], mib); + sync::sfn_sync::ret_code ret = sfn_p.decode_mib(&temp_cell, &_tti, &sf_buffer, mib); if (ret == sfn_sync::SFN_FOUND) { // Force tti tti = _tti; @@ -493,30 +468,11 @@ void sync::run_thread() Debug("SYNC: Worker %d synchronized\n", worker->get_id()); - // Read Asynchronous SCell, for each asynch active object - for (uint32_t i = 0; i < worker_com->args->nof_radios - 1; i++) { - srslte_timestamp_t tx_time; - srslte_timestamp_init(&tx_time, 0, 0); - - // Request TTI aligment - if (scell_sync->at(i)->tti_align(tti)) { - scell_sync->at(i)->read_sf(buffer[i + 1], &tx_time, &next_radio_offset[i + 1]); - srslte_timestamp_add(&tx_time, 0, TX_DELAY * 1e-3 - time_adv_sec); - } else { - // Failed, keep default Timestamp - // Error("SCell asynchronous failed to synchronise (%d)\n", i); - } - - worker->set_tx_time(i + 1, tx_time, next_radio_offset[i + 1] + next_offset); - } - metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync); metrics.cfo = srslte_ue_sync_get_cfo(&ue_sync); metrics.ta_us = time_adv_sec * 1e6f; for (uint32_t i = 0; i < worker_com->args->nof_carriers; i++) { - if (worker_com->args->carrier_map[i].radio_idx == 0) { - worker_com->set_sync_metrics(i, metrics); - } + worker_com->set_sync_metrics(i, metrics); } // Check if we need to TX a PRACH @@ -538,24 +494,11 @@ void sync::run_thread() // Set CFO for all Carriers for (uint32_t cc = 0; cc < worker_com->args->nof_carriers; cc++) { - float cfo; - - // Get radio index for the given carrier - uint32_t radio_idx = worker_com->args->carrier_map[cc].radio_idx; - - if (radio_idx == 0) { - // Use local CFO - cfo = get_tx_cfo(); - } else { - // Request CFO in the asynchronous receiver - cfo = scell_sync->at(radio_idx - 1)->get_tx_cfo(); - } - - worker->set_cfo(cc, cfo); + worker->set_cfo(cc, get_tx_cfo()); } worker->set_tti(tti); - worker->set_tx_time(0, tx_time, next_radio_offset[0] + next_offset); + worker->set_tx_time(tx_time, next_radio_offset + next_offset); next_offset = 0; ZERO_OBJECT(next_radio_offset); @@ -669,12 +612,6 @@ void sync::run_thread() // Increase TTI counter tti = (tti + 1) % 10240; } - - for (uint32_t p = 0; p < nof_rf_channels; p++) { - if (dummy_buffer[p]) { - free(dummy_buffer[p]); - } - } } /*************** @@ -728,10 +665,10 @@ void sync::set_agc_enable(bool enable) { if (enable) { if (running && radio_h) { - srslte_rf_info_t* rf_info = radio_h->get_info(0); + srslte_rf_info_t* rf_info = radio_h->get_info(); if (rf_info) { srslte_ue_sync_start_agc( - &ue_sync, callback_set_rx_gain, rf_info->min_rx_gain, rf_info->max_rx_gain, radio_h->get_rx_gain(0)); + &ue_sync, callback_set_rx_gain, rf_info->min_rx_gain, rf_info->max_rx_gain, radio_h->get_rx_gain()); search_p.set_agc_enable(true); } else { ERROR("Error: Radio does not provide RF information\n"); @@ -887,13 +824,11 @@ bool sync::set_frequency() set_dl_freq / 1e6, set_ul_freq / 1e6); - carrier_map_t* m = &worker_com->args->carrier_map[0]; - for (uint32_t i = 0; i < worker_com->args->nof_rx_ant; i++) { - radio_h->set_rx_freq(m->radio_idx, m->channel_idx + i, set_dl_freq); - radio_h->set_tx_freq(m->radio_idx, m->channel_idx + i, set_ul_freq); - } + // Logical channel is 0 + radio_h->set_rx_freq(0, set_dl_freq); + radio_h->set_tx_freq(0, set_ul_freq); - ul_dl_factor = (float)(radio_h->get_tx_freq(m->radio_idx) / radio_h->get_rx_freq(m->radio_idx)); + ul_dl_factor = (float)(set_ul_freq / set_dl_freq); srslte_ue_sync_reset(&ue_sync); @@ -918,8 +853,8 @@ void sync::set_sampling_rate() Info("SYNC: Setting sampling rate %.2f MHz\n", current_srate / 1000000); srate_mode = SRATE_CAMP; - radio_h->set_rx_srate(0, current_srate); - radio_h->set_tx_srate(0, current_srate); + radio_h->set_rx_srate(current_srate); + radio_h->set_tx_srate(current_srate); } else { Error("Error setting sampling rate for cell with %d PRBs\n", cell.nof_prb); } @@ -940,7 +875,7 @@ void sync::get_current_cell(srslte_cell_t* cell_, uint32_t* earfcn_) } } -int sync::radio_recv_fnc(cf_t* data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t* rx_time) +int sync::radio_recv_fnc(srslte::rf_buffer_t& data, uint32_t nsamples, srslte_timestamp_t* rx_time) { srslte_timestamp_t ts = {}; @@ -950,7 +885,7 @@ int sync::radio_recv_fnc(cf_t* data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte } // Receive - if (radio_h->rx_now(0, data, nsamples, rx_time)) { + if (radio_h->rx_now(data, nsamples, rx_time)) { // Detect Radio Timestamp reset if (srslte_timestamp_compare(rx_time, &radio_ts) < 0) { srslte_timestamp_init(&radio_ts, 0, 0.0); @@ -968,14 +903,14 @@ int sync::radio_recv_fnc(cf_t* data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte if (channel_emulator && rx_time) { channel_emulator->set_srate((uint32_t)current_srate); - channel_emulator->run(data, data, nsamples, *rx_time); + channel_emulator->run(data.to_cf_t(), data.to_cf_t(), nsamples, *rx_time); } int offset = nsamples - current_sflen; if (abs(offset) < 10 && offset != 0) { - next_radio_offset[0] = offset; + next_radio_offset = offset; } else if (nsamples < 10) { - next_radio_offset[0] = nsamples; + next_radio_offset = nsamples; } log_h->debug("SYNC: received %d samples from radio\n", nsamples); @@ -1000,21 +935,19 @@ sync::search::~search() srslte_ue_cellsearch_free(&cs); } -void sync::search::init(cf_t* buffer_[SRSLTE_MAX_PORTS], srslte::log* log_h_, uint32_t nof_rx_antennas, sync* parent) +void sync::search::init(srslte::rf_buffer_t& buffer_, srslte::log* log_h_, uint32_t nof_rx_channels, sync* parent) { log_h = log_h_; p = parent; - for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { - buffer[i] = buffer_[i]; - } + buffer = buffer_; - if (srslte_ue_cellsearch_init_multi(&cs, 8, radio_recv_callback, nof_rx_antennas, parent)) { + if (srslte_ue_cellsearch_init_multi(&cs, 8, radio_recv_callback, nof_rx_channels, parent)) { Error("SYNC: Initiating UE cell search\n"); } srslte_ue_cellsearch_set_nof_valid_frames(&cs, 4); - if (srslte_ue_mib_sync_init_multi(&ue_mib_sync, radio_recv_callback, nof_rx_antennas, parent)) { + if (srslte_ue_mib_sync_init_multi(&ue_mib_sync, radio_recv_callback, nof_rx_channels, parent)) { Error("SYNC: Initiating UE MIB synchronization\n"); } @@ -1037,12 +970,12 @@ float sync::search::get_last_cfo() void sync::search::set_agc_enable(bool enable) { if (enable) { - srslte_rf_info_t* rf_info = p->radio_h->get_info(0); + srslte_rf_info_t* rf_info = p->radio_h->get_info(); srslte_ue_sync_start_agc(&ue_mib_sync.ue_sync, callback_set_rx_gain, rf_info->min_rx_gain, rf_info->max_rx_gain, - p->radio_h->get_rx_gain(0)); + p->radio_h->get_rx_gain()); } else { ERROR("Error stop AGC not implemented\n"); } @@ -1154,22 +1087,21 @@ sync::sfn_sync::~sfn_sync() srslte_ue_mib_free(&ue_mib); } -void sync::sfn_sync::init(srslte_ue_sync_t* ue_sync_, - cf_t* buffer_[SRSLTE_MAX_PORTS], - uint32_t buffer_max_samples_, - srslte::log* log_h_, - uint32_t nof_subframes) +void sync::sfn_sync::init(srslte_ue_sync_t* ue_sync_, + srslte::rf_buffer_t& buffer, + uint32_t buffer_max_samples_, + srslte::log* log_h_, + uint32_t nof_subframes) { log_h = log_h_; ue_sync = ue_sync_; timeout = nof_subframes; - for (int p = 0; p < SRSLTE_MAX_PORTS; p++) { - buffer[p] = buffer_[p]; - } + mib_buffer = buffer; buffer_max_samples = buffer_max_samples_; - if (srslte_ue_mib_init(&ue_mib, buffer, SRSLTE_MAX_PRB)) { + // MIB decoder uses a single receiver antenna in logical channel 0 + if (srslte_ue_mib_init(&ue_mib, buffer.get(0), SRSLTE_MAX_PRB)) { Error("SYNC: Initiating UE MIB decoder\n"); } } @@ -1195,14 +1127,14 @@ sync::sfn_sync::ret_code sync::sfn_sync::run_subframe(srslte_cell_t* std::array& bch_payload, bool sfidx_only) { - int ret = srslte_ue_sync_zerocopy(ue_sync, buffer, buffer_max_samples); + int ret = srslte_ue_sync_zerocopy(ue_sync, mib_buffer.to_cf_t(), buffer_max_samples); if (ret < 0) { Error("SYNC: Error calling ue_sync_get_buffer.\n"); return ERROR; } if (ret == 1) { - sync::sfn_sync::ret_code ret2 = decode_mib(cell_, tti_cnt, NULL, bch_payload, sfidx_only); + sync::sfn_sync::ret_code ret2 = decode_mib(cell_, tti_cnt, nullptr, bch_payload, sfidx_only); if (ret2 != SFN_NOFOUND) { return ret2; } @@ -1219,15 +1151,15 @@ sync::sfn_sync::ret_code sync::sfn_sync::run_subframe(srslte_cell_t* return IDLE; } -sync::sfn_sync::ret_code sync::sfn_sync::decode_mib(srslte_cell_t* cell_, - uint32_t* tti_cnt, - cf_t* ext_buffer[SRSLTE_MAX_PORTS], +sync::sfn_sync::ret_code sync::sfn_sync::decode_mib(srslte_cell_t* cell_, + uint32_t* tti_cnt, + srslte::rf_buffer_t* ext_buffer, std::array& bch_payload, bool sfidx_only) { - // If external buffer provided not equal to internal buffer, copy data - if ((ext_buffer != NULL) && (ext_buffer != buffer)) { - memcpy(buffer[0], ext_buffer[0], sizeof(cf_t) * ue_sync->sf_len); + // If external buffer provided not equal to internal buffer, copy samples from channel/port 0 + if (ext_buffer != nullptr) { + memcpy(mib_buffer.get(0), ext_buffer->get(0), sizeof(cf_t) * ue_sync->sf_len); } if (srslte_ue_sync_get_sfidx(ue_sync) == 0) { diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index 21d906623..82507b7a0 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -21,7 +21,7 @@ #include "srsue/hdr/ue.h" #include "srslte/build_info.h" -#include "srslte/radio/radio_multi.h" +#include "srslte/radio/radio.h" #include "srslte/srslte.h" #include "srsue/hdr/phy/phy.h" #include "srsue/hdr/stack/ue_stack_lte.h" @@ -86,7 +86,7 @@ int ue::init(const all_args_t& args_, srslte::logger* logger_) return SRSLTE_ERROR; } - std::unique_ptr lte_radio = std::unique_ptr(new radio_multi(logger)); + std::unique_ptr lte_radio = std::unique_ptr(new srslte::radio(logger)); if (!lte_radio) { log.console("Error creating radio multi instance.\n"); return SRSLTE_ERROR; @@ -158,28 +158,21 @@ int ue::parse_args(const all_args_t& args_) } } - // replicate some RF parameter to make them available to PHY - args.phy.nof_rx_ant = args.rf.nof_rx_ant; - args.phy.agc_enable = args.rf.rx_gain < 0.0f; - - // Calculate number of carriers available in all radios - args.phy.nof_radios = args.rf.nof_radios; - args.phy.nof_rf_channels = args.rf.nof_rf_channels; - args.phy.nof_carriers = args.rf.nof_radios * args.rf.nof_rf_channels; - - if (args.phy.nof_carriers > SRSLTE_MAX_CARRIERS) { - log.error("Too many carriers (%d > %d)\n", args.phy.nof_carriers, SRSLTE_MAX_CARRIERS); + if (args.rf.nof_antennas > SRSLTE_MAX_PORTS) { + fprintf(stderr, "Maximum number of antennas exceeded (%d > %d)\n", args.rf.nof_antennas, SRSLTE_MAX_PORTS); return SRSLTE_ERROR; } - // Generate RF-Channel to Carrier map - for (uint32_t i = 0; i < args.phy.nof_carriers; i++) { - carrier_map_t* m = &args.phy.carrier_map[i]; - m->radio_idx = i / args.rf.nof_rf_channels; - m->channel_idx = (i % args.rf.nof_rf_channels) * args.rf.nof_rx_ant; - log.debug("Mapping carrier %d to channel %d in radio %d\n", i, m->channel_idx, m->radio_idx); + if (args.rf.nof_carriers > SRSLTE_MAX_CARRIERS) { + fprintf(stderr, "Maximum number of carriers exceeded (%d > %d)\n", args.rf.nof_carriers, SRSLTE_MAX_CARRIERS); + return SRSLTE_ERROR; } + // replicate some RF parameter to make them available to PHY + args.phy.nof_carriers = args.rf.nof_carriers; + args.phy.nof_rx_ant = args.rf.nof_antennas; + args.phy.agc_enable = args.rf.rx_gain < 0.0f; + // populate EARFCN list if (!args.phy.dl_earfcn.empty()) { args.phy.earfcn_list.clear(); @@ -203,7 +196,7 @@ int ue::parse_args(const all_args_t& args_) args.stack.rrc.ue_category = (uint32_t)strtoul(args.stack.rrc.ue_category_str.c_str(), nullptr, 10); // Consider Carrier Aggregation support if more than one - args.stack.rrc.support_ca = (args.rf.nof_rf_channels * args.rf.nof_radios) > 1; + args.stack.rrc.support_ca = (args.rf.nof_carriers > 1); return SRSLTE_SUCCESS; } diff --git a/srsue/test/phy/scell_search_test.cc b/srsue/test/phy/scell_search_test.cc index b4110ca31..07334439e 100644 --- a/srsue/test/phy/scell_search_test.cc +++ b/srsue/test/phy/scell_search_test.cc @@ -500,10 +500,15 @@ int main(int argc, char** argv) radio_log->set_level(radio_log_level); // Create radio - radio = std::unique_ptr(new srslte::radio()); + radio = std::unique_ptr(new srslte::radio(radio_log.get())); // Init radio - radio->init(radio_log.get(), (char*)radio_device_args.c_str(), (char*)radio_device_name.c_str(), 1); + srslte::rf_args_t radio_args = {}; + radio_args.device_args = radio_device_args; + radio_args.device_name = radio_device_name; + radio_args.nof_carriers = 1; + radio_args.nof_antennas = 1; + radio->init(radio_args, NULL); // Set sampling rate radio->set_rx_srate(srslte_sampling_freq_hz(cell_base.nof_prb)); @@ -561,7 +566,8 @@ int main(int argc, char** argv) if (radio) { // Receive radio - radio->rx_now(&baseband_buffer, SRSLTE_SF_LEN_PRB(cell_base.nof_prb), &ts); + srslte::rf_buffer_t radio_buffer(baseband_buffer); + radio->rx_now(radio_buffer, SRSLTE_SF_LEN_PRB(cell_base.nof_prb), &ts); } else { // Run eNb simulator bool put_pdsch = serving_cell_pdsch_enable; diff --git a/srsue/test/phy/ue_phy_test.cc b/srsue/test/phy/ue_phy_test.cc index b7255f0a1..6b89bdba3 100644 --- a/srsue/test/phy/ue_phy_test.cc +++ b/srsue/test/phy/ue_phy_test.cc @@ -191,10 +191,8 @@ private: uint32_t get_count_late() { return count_late; } - bool tx(const uint32_t& radio_idx, - cf_t** buffer, - const uint32_t& nof_samples, - const srslte_timestamp_t& tx_time) override + bool + tx(srslte::rf_buffer_interface& buffer, const uint32_t& nof_samples, const srslte_timestamp_t& tx_time) override { bool ret = true; notify_tx(); @@ -213,8 +211,7 @@ private: return ret; } void tx_end() override {} - bool - rx_now(const uint32_t& radio_idx, cf_t** buffer, const uint32_t& nof_samples, srslte_timestamp_t* rxd_time) override + bool rx_now(srslte::rf_buffer_interface& buffer, const uint32_t& nof_samples, srslte_timestamp_t* rxd_time) override { notify_rx_now(); @@ -222,7 +219,7 @@ private: auto base_nsamples = (uint32_t)floorf(((float)nof_samples * base_srate) / rx_srate); for (uint32_t i = 0; i < ring_buffers.size(); i++) { - cf_t* buf_ptr = ((buffer[i] != nullptr) && (base_srate == rx_srate)) ? buffer[i] : temp_buffer; + cf_t* buf_ptr = ((buffer.get(i) != nullptr) && (base_srate == rx_srate)) ? buffer.get(i) : temp_buffer; // Read base srate samples int ret = srslte_ringbuffer_read(&ring_buffers[i], buf_ptr, (uint32_t)sizeof(cf_t) * base_nsamples); @@ -233,14 +230,14 @@ private: } // Only if baseband buffer is provided - if (buffer[i]) { + if (buffer.get(i)) { if (base_srate > rx_srate) { // Decimate auto decimation = (uint32_t)roundf(base_srate / rx_srate); // Perform decimation for (uint32_t j = 0, k = 0; j < nof_samples; j++, k += decimation) { - buffer[i][j] = buf_ptr[k]; + buffer.get(i)[j] = buf_ptr[k]; } } else if (base_srate < rx_srate) { // Interpolate @@ -249,7 +246,7 @@ private: // Perform zero order hold interpolation for (uint32_t j = 0, k = 0; j < nof_samples; k++) { for (uint32_t c = 0; c < interpolation; c++, j++) { - buffer[i][j] = buf_ptr[k]; + buffer.get(i)[j] = buf_ptr[k]; } } } @@ -266,13 +263,13 @@ private: return true; } - void set_tx_freq(const uint32_t& radio_idx, const uint32_t& channel_idx, const double& freq) override + void set_tx_freq(const uint32_t& channel_idx, const double& freq) override { std::unique_lock lock(mutex); tx_freq = (float)freq; log_h.info("Set Tx freq to %+.0f MHz.\n", freq * 1.0e-6); } - void set_rx_freq(const uint32_t& radio_idx, const uint32_t& channel_idx, const double& freq) override + void set_rx_freq(const uint32_t& channel_idx, const double& freq) override { std::unique_lock lock(mutex); rx_freq = (float)freq; @@ -284,40 +281,41 @@ private: rx_gain = srslte_convert_dB_to_amplitude(gain); log_h.info("Set Rx gain-th to %+.1f dB (%.6f).\n", gain, rx_gain); } - void set_rx_gain(const uint32_t& radio_idx, const float& gain) override + void set_tx_gain(const float& gain) override + { + std::unique_lock lock(mutex); + rx_gain = srslte_convert_dB_to_amplitude(gain); + log_h.info("Set Tx gain to %+.1f dB (%.6f).\n", gain, rx_gain); + } + void set_rx_gain(const float& gain) override { std::unique_lock lock(mutex); rx_gain = srslte_convert_dB_to_amplitude(gain); log_h.info("Set Rx gain to %+.1f dB (%.6f).\n", gain, rx_gain); } - void set_tx_srate(const uint32_t& radio_idx, const double& srate) override + void set_tx_srate(const double& srate) override { std::unique_lock lock(mutex); tx_srate = (float)srate; log_h.info("Set Tx sampling rate to %+.3f MHz.\n", srate * 1.0e-6); } - void set_rx_srate(const uint32_t& radio_idx, const double& srate) override + void set_rx_srate(const double& srate) override { std::unique_lock lock(mutex); rx_srate = (float)srate; log_h.info("Set Rx sampling rate to %+.3f MHz.\n", srate * 1.0e-6); } - float get_rx_gain(const uint32_t& radio_idx) override + float get_rx_gain() override { std::unique_lock lock(mutex); return srslte_convert_amplitude_to_dB(rx_gain); } double get_freq_offset() override { return 0; } - double get_tx_freq(const uint32_t& radio_idx) override { return tx_freq; } - double get_rx_freq(const uint32_t& radio_idx) override { return rx_freq; } - float get_max_tx_power() override { return 0; } - float get_tx_gain_offset() override { return 0; } - float get_rx_gain_offset() override { return 0; } bool is_continuous_tx() override { return false; } - bool get_is_start_of_burst(const uint32_t& radio_idx) override { return false; } + bool get_is_start_of_burst() override { return false; } bool is_init() override { return false; } void reset() override {} - srslte_rf_info_t* get_info(const uint32_t& radio_idx) override { return &rf_info; } + srslte_rf_info_t* get_info() override { return &rf_info; } }; // Common instances @@ -358,7 +356,7 @@ public: phy->init(phy_args, &stack, &radio); // Initialise DL baseband buffers - for (uint32_t i = 0; i < phy_args.nof_rx_ant; i++) { + for (uint32_t i = 0; i < cell.nof_ports; i++) { enb_dl_buffer[i] = srslte_vec_cf_malloc(sf_len); if (!enb_dl_buffer[i]) { perror("malloc"); @@ -470,7 +468,7 @@ int main(int argc, char** argv) // Define Cell srslte_cell_t cell = {.nof_prb = 6, - .nof_ports = 1, + .nof_ports = 4, .id = 1, .cp = SRSLTE_CP_NORM, .phich_length = SRSLTE_PHICH_NORM, diff --git a/srsue/ue.conf.example b/srsue/ue.conf.example index 1ef676c06..b3a7c61dc 100644 --- a/srsue/ue.conf.example +++ b/srsue/ue.conf.example @@ -13,9 +13,8 @@ # Optional parameters: # dl_freq: Override DL frequency corresponding to dl_earfcn # ul_freq: Override UL frequency corresponding to dl_earfcn -# nof_radios: Number of available RF devices -# nof_rf_channels: Number of RF channels per radio -# nof_rx_ant: Number of RX antennas per channel +# nof_carriers: Number of carriers +# nof_antennas: Number of antennas per carrier (all carriers have the same number of antennas) # device_name: Device driver family. Supported options: "auto" (uses first found), "UHD" or "bladeRF" # device_args: Arguments for the device driver. Options are "auto" or any string. # Default for UHD: "recv_frame_size=9232,send_frame_size=9232" @@ -25,8 +24,6 @@ # time_adv_nsamples: Transmission time advance (in number of samples) to compensate for RF delay # from antenna to timestamp insertion. # Default "auto". B210 USRP: 100 samples, bladeRF: 27. -# burst_preamble_us: Preamble length to transmit before start of burst. -# Default "auto". B210 USRP: 400 us, bladeRF: 0 us. # continuous_tx: Transmit samples continuously to the radio or on bursts (auto/yes/no). # Default is auto (yes for UHD, no for rest) ##################################################################### @@ -36,8 +33,8 @@ freq_offset = 0 tx_gain = 80 #rx_gain = 40 -#nof_radios = 1 -#nof_rx_ant = 1 +#nof_carriers = 1 +#nof_antennas = 1 # For best performance in 2x2 MIMO and >= 15 MHz use the following device_args settings: # USRP B210: num_recv_frames=64,num_send_frames=64 @@ -47,7 +44,6 @@ tx_gain = 80 #device_args = auto #time_adv_nsamples = auto -#burst_preamble_us = auto #continuous_tx = auto