Remove radio_multi class and organize channels, ports and carrier buffers (#1019)

master
Ismael Gomez 5 years ago committed by GitHub
parent ecb22600ff
commit 4e12405fff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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);
}

@ -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;

@ -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

@ -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 <array>
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

@ -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;

@ -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 = {};
};

@ -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

@ -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,

@ -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,

@ -65,7 +65,7 @@ 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,9 +82,10 @@ 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,
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*),
int(recv_callback)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*),
uint32_t nof_rx_antennas,
void* stream_handler);

@ -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);

@ -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);
@ -98,13 +96,14 @@ 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;
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,
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);

@ -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;
@ -89,7 +89,7 @@ typedef struct SRSLTE_API {
int decimate;
void *stream;
void *stream_single;
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*);
int (*recv_callback_single)(void*, void*, uint32_t, srslte_timestamp_t*);
srslte_timestamp_t last_timestamp;
@ -159,23 +159,24 @@ 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,
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*),
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,
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*),
int(recv_callback)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*),
uint32_t nof_rx_antennas,
void* stream_handler,
int decimate,
@ -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);

@ -21,8 +21,11 @@
#include <string.h>
#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_)
{
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()
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])
{
if (zeros) {
free(zeros);
zeros = NULL;
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() {}
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);
/**
* The destructor will deallocate memory only if it was allocated passing nof_subframes > 0
*/
~rf_buffer_t()
{
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<cf_t*, SRSLTE_MAX_CHANNELS> 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]);
}
}
}
};
void set_burst_preamble(double preamble_us);
void set_tx_adv(int nsamples);
void set_tx_adv_neg(bool tx_adv_is_neg);
/**
* 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();
bool is_continuous_tx();
void set_continuous_tx(bool enable);
int init(const rf_args_t& args_, phy_interface_radio* phy_);
void stop();
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();
void get_time(srslte_timestamp_t* now);
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 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 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<uint32_t> tr_local_time;
trace<uint32_t> tr_usrp_time;
trace<uint32_t> tr_tx_time;
trace<uint32_t> 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

@ -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

@ -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<std::unique_ptr<radio> > 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

@ -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]);

@ -41,15 +41,17 @@ typedef struct {
} rf_blade_handler_t;
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_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");
}

@ -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);

@ -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,

@ -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,

@ -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;
handler->soapy_error_handler_arg = arg;
}
const char* rf_soapy_devname(void* 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);

@ -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;
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);

@ -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,

@ -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;

@ -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;

@ -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);

@ -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,
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*),
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;

@ -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]);
}

@ -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,10 +185,11 @@ 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,
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*),
int(recv_callback)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*),
uint32_t nof_rx_antennas,
void* stream_handler,
int decimate)
@ -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);

@ -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)

@ -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<char> 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);
}
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;
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);
}
// Suppress radio stdout
srslte_rf_suppress_stdout(&rf_device);
radio::~radio()
{
if (zeros) {
free(zeros);
zeros = nullptr;
}
}
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;
int radio::init(const rf_args_t& args, phy_interface_radio* phy_)
{
phy = phy_;
// 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 {
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));
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) {
strncpy(saved_args, args, 127);
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();
}
if (devname) {
strncpy(saved_devname, devname, 127);
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;
}
saved_nof_channels = nof_channels;
is_start_of_burst = true;
is_initialized = true;
return 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;
if (args.continuous_tx != "auto") {
continuous_tx = (args.continuous_tx == "yes");
}
// Set fixed gain options
if (args.rx_gain < 0) {
start_agc(false);
} else {
set_rx_gain(args.rx_gain);
}
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");
}
// 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)
bool radio::rx_now(rf_buffer_interface& buffer, const uint32_t& nof_samples, srslte_timestamp_t* rxd_time)
{
ERROR("Not implemented\n");
if (!is_initialized) {
return false;
}
bool radio::rx_now(cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t* rxd_time)
{
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)
{
srslte_rf_get_time(&rf_device, &now->full_secs, &now->frac_secs);
if (!is_initialized) {
return;
}
float radio::get_max_tx_power()
{
return 40;
srslte_rf_get_time(&rf_device, &now->full_secs, &now->frac_secs);
}
float radio::get_rssi()
{
if (!is_initialized) {
return 0.0f;
}
return srslte_rf_get_rssi(&rf_device);
}
bool radio::has_rssi()
{
return srslte_rf_has_rssi(&rf_device);
if (!is_initialized) {
return false;
}
bool radio::is_first_of_burst()
{
return is_start_of_burst;
return srslte_rf_has_rssi(&rf_device);
}
#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;
}
return this->tx(_buffer, nof_samples, tx_time);
if (!is_initialized) {
return false;
}
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;
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_freq(uint32_t ch, double freq)
{
rx_freq = srslte_rf_set_rx_freq(&rf_device, ch, freq + freq_offset);
}
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;
}
void radio::set_tx_gain(float gain)
{
srslte_rf_set_tx_gain(&rf_device, gain);
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);
}
double radio::get_rx_freq()
{
return rx_freq;
} else {
log_h->error("set_tx_freq: channel_idx=%d for %d antennas exceeds maximum channels (%d)\n",
channel_idx,
nof_antennas,
nof_channels);
}
double radio::get_freq_offset()
{
return freq_offset;
}
double radio::get_tx_freq()
void radio::set_tx_gain(const float& gain)
{
return tx_freq;
if (!is_initialized) {
return;
}
srslte_rf_set_tx_gain(&rf_device, gain);
}
float radio::get_tx_gain()
double radio::get_freq_offset()
{
return srslte_rf_get_tx_gain(&rf_device);
return freq_offset;
}
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

@ -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 <mutex>
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<std::mutex> 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<srslte::radio> radio = std::unique_ptr<srslte::radio>(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<std::mutex> 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<std::mutex> 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

@ -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);
}
}

@ -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
#####################################################################

@ -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<enb_stack_base> stack = nullptr;
std::unique_ptr<srslte::radio_base> radio = nullptr;
std::unique_ptr<srslte::radio> radio = nullptr;
std::unique_ptr<enb_phy_base> phy = nullptr;
srslte::logger_stdout logger_stdout;

@ -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"

@ -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 <map>
@ -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 = {};

@ -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

@ -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

@ -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"
@ -67,7 +66,7 @@ int enb::init(const all_args_t& args_, srslte::logger* logger_)
return SRSLTE_ERROR;
}
std::unique_ptr<enb_radio_multi> lte_radio = std::unique_ptr<enb_radio_multi>(new enb_radio_multi(logger));
std::unique_ptr<srslte::radio> lte_radio = std::unique_ptr<srslte::radio>(new srslte::radio(logger));
if (!lte_radio) {
log.console("Error creating radio multi instance.\n");
return SRSLTE_ERROR;

@ -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;
}

@ -31,8 +31,8 @@
#include <boost/program_options.hpp>
#include <boost/program_options/parsers.hpp>
#include <iostream>
#include <string>
#include <memory>
#include <string>
#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<float>(&args->rf.ul_freq)->default_value(-1), "Uplink Frequency (if positive overrides EARFCN)")
("rf.device_name", bpo::value<string>(&args->rf.device_name)->default_value("auto"), "Front-end device name")
("rf.device_args", bpo::value<string>(&args->rf.device_args[0])->default_value("auto"), "Front-end device arguments")
("rf.device_args", bpo::value<string>(&args->rf.device_args)->default_value("auto"), "Front-end device arguments")
("rf.time_adv_nsamples", bpo::value<string>(&args->rf.time_adv_nsamples)->default_value("auto"), "Transmission time advance")
("rf.burst_preamble_us", bpo::value<string>(&args->rf.burst_preamble)->default_value("auto"), "Transmission time advance")
("pcap.enable", bpo::value<bool>(&args->stack.pcap.enable)->default_value(false), "Enable MAC packet captures for wireshark")
("pcap.filename", bpo::value<string>(&args->stack.pcap.filename)->default_value("ue.pcap"), "MAC layer capture filename")

@ -105,7 +105,7 @@ void phy_common::stop()
* 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],
srslte::rf_buffer_t& buffer,
uint32_t nof_samples,
srslte_timestamp_t tx_time)
{
@ -114,11 +114,11 @@ void phy_common::worker_end(void* 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();

@ -163,7 +163,6 @@ uint32_t sf_worker::get_nof_rnti()
void sf_worker::work_imp()
{
std::lock_guard<std::mutex> 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);

@ -85,7 +85,7 @@ 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::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));
@ -93,23 +93,18 @@ void txrx::run_thread()
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

@ -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})

@ -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 <mutex>
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

@ -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<dummy_radio> 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<uint32_t>(SRSLTE_SF_LEN_PRB(cell_list[0].cell.nof_prb));

@ -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<std::unique_ptr<sf_worker> > 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);
};

@ -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);

@ -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);
@ -110,8 +110,8 @@ private:
float prach_power = 0;
uint32_t tti = 0;
srslte_timestamp_t tx_time[SRSLTE_MAX_RADIOS] = {};
int next_offset[SRSLTE_MAX_RADIOS] = {};
srslte_timestamp_t tx_time = {};
int next_offset = {};
uint32_t rssi_read_cnt = 0;
};

@ -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 <srsue/hdr/phy/scell/intra_measure.h>
@ -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,7 +99,7 @@ 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);
@ -109,7 +108,7 @@ private:
private:
sync* p = nullptr;
srslte::log* log_h = nullptr;
cf_t* buffer[SRSLTE_MAX_PORTS] = {};
srslte::rf_buffer_t buffer = {};
srslte_ue_cellsearch_t cs = {};
srslte_ue_mib_sync_t ue_mib_sync = {};
int force_N_id_2 = 0;
@ -123,7 +122,7 @@ private:
sfn_sync() = default;
~sfn_sync();
void init(srslte_ue_sync_t* ue_sync,
cf_t* buffer[SRSLTE_MAX_PORTS],
srslte::rf_buffer_t& buffer,
uint32_t buffer_max_samples_,
srslte::log* log_h,
uint32_t nof_subframes = SFN_SYNC_NOF_SUBFRAMES);
@ -135,7 +134,7 @@ 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<uint8_t, SRSLTE_BCH_PAYLOAD_LEN>& bch_payload,
bool sfidx_only = false);
@ -146,7 +145,7 @@ private:
uint32_t timeout = 0;
srslte::log* log_h = nullptr;
srslte_ue_sync_t* ue_sync = nullptr;
cf_t* buffer[SRSLTE_MAX_PORTS] = {};
srslte::rf_buffer_t mib_buffer = {};
uint32_t buffer_max_samples = 0;
srslte_ue_mib_t ue_mib = {};
};
@ -178,7 +177,7 @@ private:
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
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<uint8_t, SRSLTE_BCH_PAYLOAD_LEN> mib;
std::array<uint8_t, SRSLTE_BCH_PAYLOAD_LEN> 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;

@ -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 {

@ -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<ue_phy_base> phy;
std::unique_ptr<srslte::radio_base> radio;
std::unique_ptr<srslte::radio> radio;
std::unique_ptr<ue_stack_base> stack;
std::unique_ptr<gw> gw_inst;

@ -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)
########################################################################

@ -84,16 +84,12 @@ static int parse_args(all_args_t* args, int argc, char* argv[])
("rf.ul_freq", bpo::value<float>(&args->phy.ul_freq)->default_value(-1), "Uplink Frequency (if positive overrides EARFCN)")
("rf.rx_gain", bpo::value<float>(&args->rf.rx_gain)->default_value(-1), "Front-end receiver gain")
("rf.tx_gain", bpo::value<float>(&args->rf.tx_gain)->default_value(-1), "Front-end transmitter gain")
("rf.nof_radios", bpo::value<uint32_t>(&args->rf.nof_radios)->default_value(1), "Number of available RF devices")
("rf.nof_rf_channels", bpo::value<uint32_t>(&args->rf.nof_rf_channels)->default_value(1), "Number of RF channels per radio")
("rf.nof_rx_ant", bpo::value<uint32_t>(&args->rf.nof_rx_ant)->default_value(1), "Number of RX antennas per channel")
("rf.nof_carriers", bpo::value<uint32_t>(&args->rf.nof_carriers)->default_value(1), "Number of carriers")
("rf.nof_antennas", bpo::value<uint32_t>(&args->rf.nof_antennas)->default_value(1), "Number of antennas per carrier")
("rf.device_name", bpo::value<string>(&args->rf.device_name)->default_value("auto"), "Front-end device name")
("rf.device_args", bpo::value<string>(&args->rf.device_args[0])->default_value("auto"), "Front-end device arguments")
("rf.device_args_2", bpo::value<string>(&args->rf.device_args[1])->default_value("auto"), "Front-end device 2 arguments")
("rf.device_args_3", bpo::value<string>(&args->rf.device_args[2])->default_value("auto"), "Front-end device 3 arguments")
("rf.device_args", bpo::value<string>(&args->rf.device_args)->default_value("auto"), "Front-end device arguments")
("rf.time_adv_nsamples", bpo::value<string>(&args->rf.time_adv_nsamples)->default_value("auto"), "Transmission time advance")
("rf.burst_preamble_us", bpo::value<string>(&args->rf.burst_preamble)->default_value("auto"), "Transmission time advance")
("rf.continuous_tx", bpo::value<string>(&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<uint32_t>(&args->stack.rrc.feature_group)->default_value(0xe6041000), "Hex value of the featureGroupIndicators field in the"

@ -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<std::mutex> 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);
}
}
radio->set_rx_freq(cc_idx, dl_freq);
radio->set_tx_freq(cc_idx, ul_freq);
}
// Store SCell earfcn and pci

@ -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));
}
}
@ -527,45 +525,41 @@ bool phy_common::get_dl_pending_ack(srslte_ul_sf_cfg_t* sf, uint32_t cc_idx, srs
*/
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])
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]);
ul_channel->run(buffer.to_cf_t(), buffer.to_cf_t(), nof_samples, tx_time);
}
radio_h->tx(i, buffer[i], 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(i)) {
if (!radio_h->get_is_start_of_burst()) {
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]);
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);
}
radio_h->tx(i, zeros_multi, nof_samples[i], tx_time[i]);
radio_h->tx(zeros_multi, nof_samples, tx_time);
}
}
} else {
if (i == 0) {
radio_h->tx_end();
}
}
}
}
// Allow next TTI to transmit
semaphore.release();
@ -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;
}

@ -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 <srslte/interfaces/ue_interfaces.h>
#include <srslte/phy/ch_estimation/chest_dl.h>
#include <srslte/phy/common/phy_common.h>
#include <srslte/phy/ue/ue_sync.h>
#include <srslte/srslte.h>
#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

@ -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<std::mutex> 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 *******/
@ -228,11 +229,7 @@ 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);
}
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]);
}
}
}
@ -264,12 +258,10 @@ void sf_worker::work_imp()
// Set PRACH buffer signal pointer
if (prach_ptr) {
tx_signal_ready = true;
tx_signal_ptr[0][0] = prach_ptr;
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) {

@ -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;
srate_mode = SRATE_NONE;
ZERO_OBJECT(next_radio_offset);
next_radio_offset = 0;
current_earfcn = -1;
srate_mode = SRATE_NONE;
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");
}
@ -373,21 +358,13 @@ 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 = {};
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,31 +468,12 @@ 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);
}
}
// Check if we need to TX a PRACH
if (prach_buffer->is_ready_to_send(tti)) {
@ -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");
}
@ -1155,7 +1088,7 @@ sync::sfn_sync::~sfn_sync()
}
void sync::sfn_sync::init(srslte_ue_sync_t* ue_sync_,
cf_t* buffer_[SRSLTE_MAX_PORTS],
srslte::rf_buffer_t& buffer,
uint32_t buffer_max_samples_,
srslte::log* log_h_,
uint32_t nof_subframes)
@ -1164,12 +1097,11 @@ void sync::sfn_sync::init(srslte_ue_sync_t* ue_sync_,
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<uint8_t, SRSLTE_BCH_PAYLOAD_LEN>& 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;
}
@ -1221,13 +1153,13 @@ sync::sfn_sync::ret_code sync::sfn_sync::run_subframe(srslte_cell_t*
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],
srslte::rf_buffer_t* ext_buffer,
std::array<uint8_t, SRSLTE_BCH_PAYLOAD_LEN>& 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) {

@ -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<radio_multi> lte_radio = std::unique_ptr<radio_multi>(new radio_multi(logger));
std::unique_ptr<srslte::radio> lte_radio = std::unique_ptr<srslte::radio>(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;
}

@ -500,10 +500,15 @@ int main(int argc, char** argv)
radio_log->set_level(radio_log_level);
// Create radio
radio = std::unique_ptr<srslte::radio>(new srslte::radio());
radio = std::unique_ptr<srslte::radio>(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;

@ -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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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,

@ -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

Loading…
Cancel
Save