mirror of https://github.com/PentHertz/srsLTE.git
Remove radio_multi class and organize channels, ports and carrier buffers (#1019)
This commit is contained in:
parent
ecb22600ff
commit
4e12405fff
|
@ -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,
|
||||
|
|
|
@ -64,8 +64,8 @@ typedef struct SRSLTE_API {
|
|||
|
||||
typedef struct SRSLTE_API {
|
||||
srslte_ue_sync_t ue_sync;
|
||||
|
||||
cf_t *sf_buffer[SRSLTE_MAX_PORTS];
|
||||
|
||||
cf_t* sf_buffer[SRSLTE_MAX_CHANNELS];
|
||||
uint32_t nof_rx_antennas;
|
||||
|
||||
uint32_t max_frames;
|
||||
|
@ -82,11 +82,12 @@ SRSLTE_API int srslte_ue_cellsearch_init(srslte_ue_cellsearch_t *q,
|
|||
int (recv_callback)(void*, void*, uint32_t,srslte_timestamp_t*),
|
||||
void *stream_handler);
|
||||
|
||||
SRSLTE_API int srslte_ue_cellsearch_init_multi(srslte_ue_cellsearch_t *q,
|
||||
uint32_t max_frames_total,
|
||||
int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t,srslte_timestamp_t*),
|
||||
uint32_t nof_rx_antennas,
|
||||
void *stream_handler);
|
||||
SRSLTE_API int
|
||||
srslte_ue_cellsearch_init_multi(srslte_ue_cellsearch_t* q,
|
||||
uint32_t max_frames_total,
|
||||
int(recv_callback)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*),
|
||||
uint32_t nof_rx_antennas,
|
||||
void* stream_handler);
|
||||
|
||||
SRSLTE_API void srslte_ue_cellsearch_free(srslte_ue_cellsearch_t *q);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -97,15 +95,16 @@ SRSLTE_API int srslte_ue_mib_decode(srslte_ue_mib_t * q,
|
|||
*/
|
||||
typedef struct {
|
||||
srslte_ue_mib_t ue_mib;
|
||||
srslte_ue_sync_t ue_sync;
|
||||
cf_t *sf_buffer[SRSLTE_MAX_PORTS];
|
||||
uint32_t nof_rx_antennas;
|
||||
srslte_ue_sync_t ue_sync;
|
||||
cf_t* sf_buffer[SRSLTE_MAX_CHANNELS];
|
||||
uint32_t nof_rx_channels;
|
||||
} srslte_ue_mib_sync_t;
|
||||
|
||||
SRSLTE_API int srslte_ue_mib_sync_init_multi(srslte_ue_mib_sync_t *q,
|
||||
int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t *),
|
||||
uint32_t nof_rx_antennas,
|
||||
void *stream_handler);
|
||||
SRSLTE_API int
|
||||
srslte_ue_mib_sync_init_multi(srslte_ue_mib_sync_t* q,
|
||||
int(recv_callback)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*),
|
||||
uint32_t nof_rx_channels,
|
||||
void* stream_handler);
|
||||
|
||||
SRSLTE_API void srslte_ue_mib_sync_free(srslte_ue_mib_sync_t *q);
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ typedef enum SRSLTE_API { SF_FIND, SF_TRACK} srslte_ue_sync_state_t;
|
|||
|
||||
//#define MEASURE_EXEC_TIME
|
||||
|
||||
typedef int(ue_sync_recv_callback_t)(void*, cf_t * [SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*);
|
||||
typedef int(ue_sync_recv_callback_t)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*);
|
||||
|
||||
typedef struct SRSLTE_API {
|
||||
srslte_ue_sync_mode_t mode;
|
||||
|
@ -88,8 +88,8 @@ typedef struct SRSLTE_API {
|
|||
uint32_t agc_period;
|
||||
int decimate;
|
||||
void *stream;
|
||||
void *stream_single;
|
||||
int (*recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*);
|
||||
void *stream_single;
|
||||
int (*recv_callback)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*);
|
||||
int (*recv_callback_single)(void*, void*, uint32_t, srslte_timestamp_t*);
|
||||
srslte_timestamp_t last_timestamp;
|
||||
|
||||
|
@ -159,27 +159,28 @@ SRSLTE_API int
|
|||
srslte_ue_sync_init_multi(srslte_ue_sync_t* q,
|
||||
uint32_t max_prb,
|
||||
bool search_cell,
|
||||
int(recv_callback)(void*, cf_t * [SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*),
|
||||
int(recv_callback)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*),
|
||||
uint32_t nof_rx_antennas,
|
||||
void* stream_handler);
|
||||
|
||||
SRSLTE_API int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q,
|
||||
uint32_t max_prb,
|
||||
bool search_cell,
|
||||
int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*),
|
||||
uint32_t nof_rx_antennas,
|
||||
void *stream_handler,
|
||||
int decimate);
|
||||
|
||||
SRSLTE_API int
|
||||
srslte_ue_sync_init_multi_decim_mode(srslte_ue_sync_t* q,
|
||||
uint32_t max_prb,
|
||||
bool search_cell,
|
||||
int(recv_callback)(void*, cf_t* [SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*),
|
||||
uint32_t nof_rx_antennas,
|
||||
void* stream_handler,
|
||||
int decimate,
|
||||
srslte_ue_sync_mode_t mode);
|
||||
srslte_ue_sync_init_multi_decim(srslte_ue_sync_t* q,
|
||||
uint32_t max_prb,
|
||||
bool search_cell,
|
||||
int(recv_callback)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*),
|
||||
uint32_t nof_rx_antennas,
|
||||
void* stream_handler,
|
||||
int decimate);
|
||||
|
||||
SRSLTE_API int srslte_ue_sync_init_multi_decim_mode(
|
||||
srslte_ue_sync_t* q,
|
||||
uint32_t max_prb,
|
||||
bool search_cell,
|
||||
int(recv_callback)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*),
|
||||
uint32_t nof_rx_antennas,
|
||||
void* stream_handler,
|
||||
int decimate,
|
||||
srslte_ue_sync_mode_t mode);
|
||||
|
||||
SRSLTE_API int srslte_ue_sync_init_file(srslte_ue_sync_t *q,
|
||||
uint32_t nof_prb,
|
||||
|
@ -223,7 +224,7 @@ SRSLTE_API uint32_t srslte_ue_sync_sf_len(srslte_ue_sync_t* q);
|
|||
SRSLTE_API void srslte_ue_sync_set_agc_period(srslte_ue_sync_t* q, uint32_t period);
|
||||
|
||||
SRSLTE_API int
|
||||
srslte_ue_sync_zerocopy(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PORTS], const uint32_t max_num_samples);
|
||||
srslte_ue_sync_zerocopy(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_CHANNELS], const uint32_t max_num_samples);
|
||||
|
||||
SRSLTE_API void srslte_ue_sync_set_cfo_tol(srslte_ue_sync_t* q, float tol);
|
||||
|
||||
|
@ -268,15 +269,15 @@ SRSLTE_API void srslte_ue_sync_set_sfo_ema(srslte_ue_sync_t *q,
|
|||
SRSLTE_API void srslte_ue_sync_get_last_timestamp(srslte_ue_sync_t *q,
|
||||
srslte_timestamp_t *timestamp);
|
||||
|
||||
SRSLTE_API int srslte_ue_sync_run_find_pss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PORTS]);
|
||||
SRSLTE_API int srslte_ue_sync_run_find_pss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_CHANNELS]);
|
||||
|
||||
SRSLTE_API int srslte_ue_sync_run_track_pss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PORTS]);
|
||||
SRSLTE_API int srslte_ue_sync_run_track_pss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_CHANNELS]);
|
||||
|
||||
SRSLTE_API int srslte_ue_sync_run_find_gnss_mode(srslte_ue_sync_t* q,
|
||||
cf_t* input_buffer[SRSLTE_MAX_PORTS],
|
||||
cf_t* input_buffer[SRSLTE_MAX_CHANNELS],
|
||||
const uint32_t max_num_samples);
|
||||
|
||||
SRSLTE_API int srslte_ue_sync_run_track_gnss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PORTS]);
|
||||
SRSLTE_API int srslte_ue_sync_run_track_gnss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_CHANNELS]);
|
||||
|
||||
SRSLTE_API int srslte_ue_sync_set_tti_from_timestamp(srslte_ue_sync_t* q, srslte_timestamp_t* rx_timestamp);
|
||||
|
||||
|
|
|
@ -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 (zeros) {
|
||||
free(zeros);
|
||||
zeros = NULL;
|
||||
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])
|
||||
{
|
||||
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);
|
||||
/**
|
||||
* 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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
int init(const rf_args_t& args_, phy_interface_radio* phy_);
|
||||
void stop();
|
||||
void reset();
|
||||
bool start_agc(bool tx_gain_same_rx = false);
|
||||
|
||||
void set_burst_preamble(double preamble_us);
|
||||
void set_tx_adv(int nsamples);
|
||||
void set_tx_adv_neg(bool tx_adv_is_neg);
|
||||
// ==== PHY interface ===
|
||||
|
||||
bool is_continuous_tx();
|
||||
void set_continuous_tx(bool enable);
|
||||
// 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;
|
||||
|
||||
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);
|
||||
// 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(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_tx_gain(const float& gain) override;
|
||||
void set_rx_gain_th(const float& gain) override;
|
||||
void set_rx_gain(const float& gain) override;
|
||||
void set_tx_srate(const double& srate) override;
|
||||
void set_rx_srate(const double& srate) override;
|
||||
|
||||
void set_freq_offset(double freq);
|
||||
void set_tx_freq(uint32_t chan, double freq);
|
||||
void set_rx_freq(uint32_t chan, double freq);
|
||||
// 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;
|
||||
|
||||
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);
|
||||
// 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();
|
||||
void handle_rf_msg(srslte_rf_error_t error);
|
||||
static void rf_msg_callback(void* arg, srslte_rf_error_t error);
|
||||
|
||||
bool is_init();
|
||||
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;
|
||||
|
||||
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
|
||||
srslte_timestamp_t end_of_burst_time = {};
|
||||
bool is_start_of_burst = 0;
|
||||
uint32_t tx_adv_nsamples = 0;
|
||||
double tx_adv_sec = 0.0f; // Transmission time advance to compensate for antenna->timestamp delay
|
||||
bool tx_adv_auto = false;
|
||||
bool tx_adv_negative = false;
|
||||
bool is_initialized = false;
|
||||
bool radio_is_streaming = false;
|
||||
bool continuous_tx = false;
|
||||
double freq_offset = 0.0f;
|
||||
double cur_tx_srate = 0.0f;
|
||||
uint32_t nof_antennas = 0;
|
||||
uint32_t nof_channels = 0;
|
||||
|
||||
// Define default values for known radios
|
||||
bool tx_adv_auto;
|
||||
bool tx_adv_negative;
|
||||
constexpr static double uhd_default_burst_preamble_sec = 600 * 1e-6;
|
||||
constexpr static double uhd_default_tx_adv_samples = 98;
|
||||
constexpr static double uhd_default_tx_adv_offset_sec = 4 * 1e-6;
|
||||
constexpr static double uhd_default_tx_adv_samples = 98;
|
||||
constexpr static double uhd_default_tx_adv_offset_sec = 4 * 1e-6;
|
||||
|
||||
constexpr static double blade_default_burst_preamble_sec = 0.0;
|
||||
constexpr static double blade_default_tx_adv_samples = 27;
|
||||
constexpr static double blade_default_tx_adv_offset_sec = 1e-6;
|
||||
|
||||
double tx_freq, rx_freq, freq_offset;
|
||||
|
||||
trace<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]);
|
||||
|
||||
|
|
|
@ -40,16 +40,18 @@ typedef struct {
|
|||
srslte_rf_info_t info;
|
||||
} rf_blade_handler_t;
|
||||
|
||||
static srslte_rf_error_handler_t blade_error_handler = NULL;
|
||||
static srslte_rf_error_handler_t blade_error_handler = NULL;
|
||||
static void* blade_error_handler_arg = NULL;
|
||||
|
||||
void rf_blade_suppress_stdout(UNUSED void* h)
|
||||
{
|
||||
bladerf_log_set_verbosity(BLADERF_LOG_LEVEL_SILENT);
|
||||
}
|
||||
|
||||
void rf_blade_register_error_handler(UNUSED void* ptr, srslte_rf_error_handler_t new_handler)
|
||||
void rf_blade_register_error_handler(UNUSED void* ptr, srslte_rf_error_handler_t new_handler, void* arg)
|
||||
{
|
||||
blade_error_handler = new_handler;
|
||||
blade_error_handler = new_handler;
|
||||
blade_error_handler_arg = arg;
|
||||
}
|
||||
|
||||
const unsigned int num_buffers = 256;
|
||||
|
@ -436,7 +438,7 @@ int rf_blade_recv_with_time(void* h,
|
|||
srslte_rf_error_t error;
|
||||
error.opt = meta.actual_count;
|
||||
error.type = SRSLTE_RF_ERROR_OVERFLOW;
|
||||
blade_error_handler(error);
|
||||
blade_error_handler(blade_error_handler_arg, error);
|
||||
} else {
|
||||
/*ERROR("Overrun detected in scheduled RX. "
|
||||
"%u valid samples were read.\n\n", meta.actual_count);*/
|
||||
|
@ -509,7 +511,7 @@ int rf_blade_send_timed(void* h,
|
|||
if (status == BLADERF_ERR_TIME_PAST) {
|
||||
if (blade_error_handler) {
|
||||
error.type = SRSLTE_RF_ERROR_LATE;
|
||||
blade_error_handler(error);
|
||||
blade_error_handler(blade_error_handler_arg, error);
|
||||
} else {
|
||||
ERROR("TX failed: %s\n", bladerf_strerror(status));
|
||||
}
|
||||
|
@ -519,7 +521,7 @@ int rf_blade_send_timed(void* h,
|
|||
} else if (meta.status == BLADERF_META_STATUS_UNDERRUN) {
|
||||
if (blade_error_handler) {
|
||||
error.type = SRSLTE_RF_ERROR_UNDERFLOW;
|
||||
blade_error_handler(error);
|
||||
blade_error_handler(blade_error_handler_arg, error);
|
||||
} else {
|
||||
ERROR("TX warning: underflow detected.\n");
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
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;
|
||||
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,
|
||||
uint32_t max_frames,
|
||||
int(recv_callback)(void*, cf_t * [SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*),
|
||||
uint32_t nof_rx_antennas,
|
||||
void* stream_handler)
|
||||
int srslte_ue_cellsearch_init_multi(
|
||||
srslte_ue_cellsearch_t* q,
|
||||
uint32_t max_frames,
|
||||
int(recv_callback)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*),
|
||||
uint32_t nof_rx_antennas,
|
||||
void* stream_handler)
|
||||
{
|
||||
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL && nof_rx_antennas > 0) {
|
||||
if (q != NULL && nof_rx_antennas < SRSLTE_MAX_CHANNELS) {
|
||||
ret = SRSLTE_ERROR;
|
||||
srslte_cell_t cell;
|
||||
|
||||
|
|
|
@ -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,13 +185,14 @@ int srslte_ue_sync_init_multi(srslte_ue_sync_t* q,
|
|||
return srslte_ue_sync_init_multi_decim(q, max_prb, search_cell, recv_callback, nof_rx_antennas, stream_handler, 1);
|
||||
}
|
||||
|
||||
int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t* q,
|
||||
uint32_t max_prb,
|
||||
bool search_cell,
|
||||
int(recv_callback)(void*, cf_t * [SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*),
|
||||
uint32_t nof_rx_antennas,
|
||||
void* stream_handler,
|
||||
int decimate)
|
||||
int srslte_ue_sync_init_multi_decim(
|
||||
srslte_ue_sync_t* q,
|
||||
uint32_t max_prb,
|
||||
bool search_cell,
|
||||
int(recv_callback)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*),
|
||||
uint32_t nof_rx_antennas,
|
||||
void* stream_handler,
|
||||
int decimate)
|
||||
{
|
||||
return srslte_ue_sync_init_multi_decim_mode(
|
||||
q, max_prb, search_cell, recv_callback, nof_rx_antennas, stream_handler, 1, SYNC_MODE_PSS);
|
||||
|
@ -201,7 +202,7 @@ int srslte_ue_sync_init_multi_decim_mode(
|
|||
srslte_ue_sync_t* q,
|
||||
uint32_t max_prb,
|
||||
bool search_cell,
|
||||
int(recv_callback)(void*, cf_t* [SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*),
|
||||
int(recv_callback)(void*, cf_t* [SRSLTE_MAX_CHANNELS], uint32_t, srslte_timestamp_t*),
|
||||
uint32_t nof_rx_antennas,
|
||||
void* stream_handler,
|
||||
int decimate,
|
||||
|
@ -209,7 +210,7 @@ int srslte_ue_sync_init_multi_decim_mode(
|
|||
{
|
||||
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL && stream_handler != NULL && nof_rx_antennas <= SRSLTE_MAX_PORTS && recv_callback != NULL) {
|
||||
if (q != NULL && stream_handler != NULL && nof_rx_antennas <= SRSLTE_MAX_CHANNELS && recv_callback != NULL) {
|
||||
ret = SRSLTE_ERROR;
|
||||
// int decimate = q->decimate;
|
||||
bzero(q, sizeof(srslte_ue_sync_t));
|
||||
|
@ -559,7 +560,7 @@ void srslte_ue_sync_set_agc_period(srslte_ue_sync_t* q, uint32_t period)
|
|||
q->agc_period = period;
|
||||
}
|
||||
|
||||
static int find_peak_ok(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PORTS])
|
||||
static int find_peak_ok(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_CHANNELS])
|
||||
{
|
||||
|
||||
if (srslte_sync_sss_detected(&q->sfind)) {
|
||||
|
@ -700,7 +701,7 @@ static int track_peak_no(srslte_ue_sync_t* q)
|
|||
}
|
||||
}
|
||||
|
||||
static int receive_samples(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PORTS], const uint32_t max_num_samples)
|
||||
static int receive_samples(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_CHANNELS], const uint32_t max_num_samples)
|
||||
{
|
||||
///< A negative time offset means there are samples in our buffer for the next subframe bc we are sampling too fast
|
||||
if (q->next_rf_sample_offset < 0) {
|
||||
|
@ -714,7 +715,7 @@ static int receive_samples(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PO
|
|||
}
|
||||
|
||||
///< Get N subframes from the USRP getting more samples and keeping the previous samples, if any
|
||||
cf_t* ptr[SRSLTE_MAX_PORTS] = {NULL};
|
||||
cf_t* ptr[SRSLTE_MAX_CHANNELS] = {NULL};
|
||||
for (int i = 0; i < q->nof_rx_antennas; i++) {
|
||||
ptr[i] = &input_buffer[i][q->next_rf_sample_offset];
|
||||
}
|
||||
|
@ -729,7 +730,9 @@ static int receive_samples(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PO
|
|||
}
|
||||
|
||||
/* Returns 1 if the subframe is synchronized in time, 0 otherwise */
|
||||
int srslte_ue_sync_zerocopy(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PORTS], const uint32_t max_num_samples)
|
||||
int srslte_ue_sync_zerocopy(srslte_ue_sync_t* q,
|
||||
cf_t* input_buffer[SRSLTE_MAX_CHANNELS],
|
||||
const uint32_t max_num_samples)
|
||||
{
|
||||
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
|
@ -830,7 +833,7 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_P
|
|||
return ret;
|
||||
}
|
||||
|
||||
int srslte_ue_sync_run_find_pss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PORTS])
|
||||
int srslte_ue_sync_run_find_pss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_CHANNELS])
|
||||
{
|
||||
int ret = SRSLTE_ERROR;
|
||||
int n = srslte_sync_find(&q->sfind, input_buffer[0], 0, &q->peak_idx);
|
||||
|
@ -867,7 +870,7 @@ int srslte_ue_sync_run_find_pss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRS
|
|||
return ret;
|
||||
};
|
||||
|
||||
int srslte_ue_sync_run_track_pss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PORTS])
|
||||
int srslte_ue_sync_run_track_pss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_CHANNELS])
|
||||
{
|
||||
int ret = SRSLTE_ERROR;
|
||||
uint32_t track_idx = 0;
|
||||
|
@ -930,7 +933,7 @@ int srslte_ue_sync_run_track_pss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SR
|
|||
}
|
||||
|
||||
int srslte_ue_sync_run_find_gnss_mode(srslte_ue_sync_t* q,
|
||||
cf_t* input_buffer[SRSLTE_MAX_PORTS],
|
||||
cf_t* input_buffer[SRSLTE_MAX_CHANNELS],
|
||||
const uint32_t max_num_samples)
|
||||
{
|
||||
INFO("Calibration samples received start at %ld + %f\n", q->last_timestamp.full_secs, q->last_timestamp.frac_secs);
|
||||
|
@ -988,7 +991,7 @@ int srslte_ue_sync_run_find_gnss_mode(srslte_ue_sync_t* q,
|
|||
}
|
||||
|
||||
///< The track function in GNSS mode only needs to increment the system frame number
|
||||
int srslte_ue_sync_run_track_gnss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PORTS])
|
||||
int srslte_ue_sync_run_track_gnss_mode(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_CHANNELS])
|
||||
{
|
||||
INFO("SYNC TRACK: sfn=%d, sf_idx=%d, next_state=%d\n", q->frame_number, q->sf_idx, q->state);
|
||||
|
||||
|
|
|
@ -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];
|
||||
zeros = srslte_vec_cf_malloc(SRSLTE_SF_LEN_MAX);
|
||||
srslte_vec_cf_zero(zeros, SRSLTE_SF_LEN_MAX);
|
||||
}
|
||||
|
||||
radio::radio(srslte::logger* logger_) : logger(logger_), log_h(nullptr), zeros(NULL)
|
||||
{
|
||||
zeros = srslte_vec_cf_malloc(SRSLTE_SF_LEN_MAX);
|
||||
srslte_vec_cf_zero(zeros, SRSLTE_SF_LEN_MAX);
|
||||
}
|
||||
|
||||
radio::~radio()
|
||||
{
|
||||
if (zeros) {
|
||||
free(zeros);
|
||||
zeros = nullptr;
|
||||
}
|
||||
if (srslte_rf_open_devname(&rf_device, devname, mutable_arg_str, nof_channels)) {
|
||||
ERROR("Error opening RF device\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
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 {
|
||||
fprintf(stderr, "Must all radio constructor with either logger or log_filter\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
if (args.nof_antennas > SRSLTE_MAX_PORTS) {
|
||||
log_h->error("Maximum number of antennas exceeded (%d > %d)\n", args.nof_antennas, SRSLTE_MAX_PORTS);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
if (args.nof_carriers > SRSLTE_MAX_CARRIERS) {
|
||||
log_h->error("Maximum number of carriers exceeded (%d > %d)\n", args.nof_carriers, SRSLTE_MAX_CARRIERS);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
nof_channels = args.nof_antennas * args.nof_carriers;
|
||||
nof_antennas = args.nof_antennas;
|
||||
|
||||
// Init and start Radio
|
||||
char* device_args = nullptr;
|
||||
if (args.device_args != "auto") {
|
||||
device_args = (char*)args.device_args.c_str();
|
||||
}
|
||||
char* dev_name = nullptr;
|
||||
if (args.device_name != "auto") {
|
||||
dev_name = (char*)args.device_name.c_str();
|
||||
}
|
||||
log_h->console("Opening %d channels in RF device=%s with args=%s\n",
|
||||
nof_channels,
|
||||
dev_name ? dev_name : "default",
|
||||
device_args ? device_args : "default");
|
||||
if (srslte_rf_open_devname(&rf_device, dev_name, device_args, nof_channels)) {
|
||||
ERROR("Error opening RF device\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
is_start_of_burst = true;
|
||||
is_initialized = true;
|
||||
|
||||
// Set RF options
|
||||
tx_adv_auto = true;
|
||||
if (args.time_adv_nsamples != "auto") {
|
||||
int t = (int)strtol(args.time_adv_nsamples.c_str(), nullptr, 10);
|
||||
set_tx_adv(abs(t));
|
||||
set_tx_adv_neg(t < 0);
|
||||
}
|
||||
continuous_tx = true;
|
||||
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);
|
||||
|
||||
continuous_tx = true;
|
||||
tx_adv_auto = true;
|
||||
// Set default preamble length each known device
|
||||
// We distinguish by device family, maybe we should calibrate per device
|
||||
if (strstr(srslte_rf_name(&rf_device), "uhd")) {
|
||||
} else if (strstr(srslte_rf_name(&rf_device), "bladerf")) {
|
||||
burst_preamble_sec = blade_default_burst_preamble_sec;
|
||||
} else {
|
||||
burst_preamble_sec = 0;
|
||||
log_h->console("\nWarning burst preamble is not calibrated for device %s. Set a value manually\n\n",
|
||||
srslte_rf_name(&rf_device));
|
||||
}
|
||||
// Register handler for processing O/U/L
|
||||
srslte_rf_register_error_handler(&rf_device, rf_msg_callback, this);
|
||||
|
||||
if (args) {
|
||||
strncpy(saved_args, args, 127);
|
||||
}
|
||||
if (devname) {
|
||||
strncpy(saved_devname, devname, 127);
|
||||
}
|
||||
saved_nof_channels = nof_channels;
|
||||
|
||||
is_initialized = true;
|
||||
return true;
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
bool radio::is_init()
|
||||
|
@ -103,21 +164,6 @@ void radio::reset()
|
|||
usleep(100000);
|
||||
}
|
||||
|
||||
void radio::set_tx_rx_gain_offset(float offset)
|
||||
{
|
||||
srslte_rf_set_tx_rx_gain_offset(&rf_device, offset);
|
||||
}
|
||||
|
||||
void radio::set_burst_preamble(double preamble_us)
|
||||
{
|
||||
burst_preamble_sec = (double)preamble_us / 1e6;
|
||||
}
|
||||
|
||||
void radio::set_continuous_tx(bool enable)
|
||||
{
|
||||
continuous_tx = enable;
|
||||
}
|
||||
|
||||
bool radio::is_continuous_tx()
|
||||
{
|
||||
return continuous_tx;
|
||||
|
@ -139,23 +185,22 @@ void radio::set_tx_adv_neg(bool tx_adv_is_neg)
|
|||
|
||||
bool radio::start_agc(bool tx_gain_same_rx)
|
||||
{
|
||||
if (!is_initialized) {
|
||||
return false;
|
||||
}
|
||||
if (srslte_rf_start_gain_thread(&rf_device, tx_gain_same_rx)) {
|
||||
ERROR("Error starting AGC Thread RF device\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
agc_enabled = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool radio::rx_at(cf_t* buffer, uint32_t nof_samples, srslte_timestamp_t rx_time)
|
||||
{
|
||||
ERROR("Not implemented\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool radio::rx_now(cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t* rxd_time)
|
||||
bool radio::rx_now(rf_buffer_interface& buffer, const uint32_t& nof_samples, srslte_timestamp_t* rxd_time)
|
||||
{
|
||||
if (!is_initialized) {
|
||||
return false;
|
||||
}
|
||||
bool ret = true;
|
||||
|
||||
if (!radio_is_streaming) {
|
||||
|
@ -166,7 +211,10 @@ bool radio::rx_now(cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_
|
|||
time_t* full_secs = rxd_time ? &rxd_time->full_secs : NULL;
|
||||
double* frac_secs = rxd_time ? &rxd_time->frac_secs : NULL;
|
||||
|
||||
if (srslte_rf_recv_with_time_multi(&rf_device, (void**)buffer, nof_samples, true, full_secs, frac_secs) > 0) {
|
||||
// Conversion from safe C++ std::array to the unsafe C interface. We must ensure that the RF driver implementation
|
||||
// accepts up to SRSLTE_MAX_CHANNELS buffers
|
||||
|
||||
if (srslte_rf_recv_with_time_multi(&rf_device, buffer.to_void(), nof_samples, true, full_secs, frac_secs) > 0) {
|
||||
ret = true;
|
||||
} else {
|
||||
ret = false;
|
||||
|
@ -177,80 +225,49 @@ bool radio::rx_now(cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_
|
|||
|
||||
void radio::get_time(srslte_timestamp_t* now)
|
||||
{
|
||||
if (!is_initialized) {
|
||||
return;
|
||||
}
|
||||
srslte_rf_get_time(&rf_device, &now->full_secs, &now->frac_secs);
|
||||
}
|
||||
|
||||
float radio::get_max_tx_power()
|
||||
{
|
||||
return 40;
|
||||
}
|
||||
|
||||
float radio::get_rssi()
|
||||
{
|
||||
if (!is_initialized) {
|
||||
return 0.0f;
|
||||
}
|
||||
return srslte_rf_get_rssi(&rf_device);
|
||||
}
|
||||
|
||||
bool radio::has_rssi()
|
||||
{
|
||||
if (!is_initialized) {
|
||||
return false;
|
||||
}
|
||||
return srslte_rf_has_rssi(&rf_device);
|
||||
}
|
||||
|
||||
bool radio::is_first_of_burst()
|
||||
bool radio::tx(rf_buffer_interface& buffer, const uint32_t& nof_samples, const srslte_timestamp_t& tx_time_)
|
||||
{
|
||||
return is_start_of_burst;
|
||||
}
|
||||
|
||||
#define BLOCKING_TX true
|
||||
|
||||
bool radio::tx_single(cf_t* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time)
|
||||
{
|
||||
cf_t* _buffer[SRSLTE_MAX_PORTS];
|
||||
|
||||
_buffer[0] = (buffer) ? buffer : zeros;
|
||||
for (int p = 1; p < SRSLTE_MAX_PORTS; p++) {
|
||||
_buffer[p] = zeros;
|
||||
if (!is_initialized) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this->tx(_buffer, nof_samples, tx_time);
|
||||
}
|
||||
|
||||
bool radio::tx(cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time)
|
||||
{
|
||||
srslte_timestamp_t tx_time = tx_time_;
|
||||
if (!tx_adv_negative) {
|
||||
srslte_timestamp_sub(&tx_time, 0, tx_adv_sec);
|
||||
} else {
|
||||
srslte_timestamp_add(&tx_time, 0, tx_adv_sec);
|
||||
}
|
||||
|
||||
if (is_start_of_burst) {
|
||||
if (burst_preamble_samples != 0) {
|
||||
srslte_timestamp_t tx_time_pad;
|
||||
srslte_timestamp_copy(&tx_time_pad, &tx_time);
|
||||
srslte_timestamp_sub(&tx_time_pad, 0, burst_preamble_time_rounded);
|
||||
srslte_rf_send_timed_multi(&rf_device,
|
||||
(void**)buffer,
|
||||
burst_preamble_samples,
|
||||
tx_time_pad.full_secs,
|
||||
tx_time_pad.frac_secs,
|
||||
true,
|
||||
true,
|
||||
false);
|
||||
is_start_of_burst = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Save possible end of burst time
|
||||
srslte_timestamp_copy(&end_of_burst_time, &tx_time);
|
||||
srslte_timestamp_add(&end_of_burst_time, 0, (double)nof_samples / cur_tx_srate);
|
||||
|
||||
int ret = srslte_rf_send_timed_multi(&rf_device,
|
||||
(void**)buffer,
|
||||
nof_samples,
|
||||
tx_time.full_secs,
|
||||
tx_time.frac_secs,
|
||||
BLOCKING_TX,
|
||||
is_start_of_burst,
|
||||
false);
|
||||
// Conversion from safe C++ std::array to the unsafe C interface. We must ensure that the RF driver implementation
|
||||
// accepts up to SRSLTE_MAX_CHANNELS buffers
|
||||
|
||||
int ret = srslte_rf_send_timed_multi(
|
||||
&rf_device, buffer.to_void(), nof_samples, tx_time.full_secs, tx_time.frac_secs, true, is_start_of_burst, false);
|
||||
is_start_of_burst = false;
|
||||
if (ret > 0) {
|
||||
return true;
|
||||
|
@ -261,6 +278,9 @@ bool radio::tx(cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_time
|
|||
|
||||
void radio::tx_end()
|
||||
{
|
||||
if (!is_initialized) {
|
||||
return;
|
||||
}
|
||||
if (!is_start_of_burst) {
|
||||
srslte_rf_send_timed2(&rf_device, zeros, 0, end_of_burst_time.full_secs, end_of_burst_time.frac_secs, false, true);
|
||||
is_start_of_burst = true;
|
||||
|
@ -272,78 +292,91 @@ bool radio::get_is_start_of_burst()
|
|||
return is_start_of_burst;
|
||||
}
|
||||
|
||||
void radio::set_freq_offset(double freq)
|
||||
void radio::set_rx_freq(const uint32_t& channel_idx, const double& freq)
|
||||
{
|
||||
freq_offset = freq;
|
||||
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;
|
||||
}
|
||||
if ((channel_idx + 1) * nof_antennas <= nof_channels) {
|
||||
for (uint32_t i = 0; i < nof_antennas; i++) {
|
||||
srslte_rf_set_tx_freq(&rf_device, channel_idx * nof_antennas + i, freq + freq_offset);
|
||||
}
|
||||
} else {
|
||||
log_h->error("set_tx_freq: channel_idx=%d for %d antennas exceeds maximum channels (%d)\n",
|
||||
channel_idx,
|
||||
nof_antennas,
|
||||
nof_channels);
|
||||
}
|
||||
}
|
||||
|
||||
void radio::set_tx_gain(float gain)
|
||||
void radio::set_tx_gain(const float& gain)
|
||||
{
|
||||
if (!is_initialized) {
|
||||
return;
|
||||
}
|
||||
srslte_rf_set_tx_gain(&rf_device, gain);
|
||||
}
|
||||
|
||||
double radio::get_rx_freq()
|
||||
{
|
||||
return rx_freq;
|
||||
}
|
||||
|
||||
double radio::get_freq_offset()
|
||||
{
|
||||
return freq_offset;
|
||||
}
|
||||
|
||||
double radio::get_tx_freq()
|
||||
{
|
||||
return tx_freq;
|
||||
}
|
||||
|
||||
float radio::get_tx_gain()
|
||||
{
|
||||
return srslte_rf_get_tx_gain(&rf_device);
|
||||
}
|
||||
|
||||
float radio::get_rx_gain()
|
||||
{
|
||||
if (!is_initialized) {
|
||||
return 0.0f;
|
||||
}
|
||||
return srslte_rf_get_rx_gain(&rf_device);
|
||||
}
|
||||
|
||||
void radio::set_tx_srate(double srate)
|
||||
void radio::set_tx_srate(const double& srate)
|
||||
{
|
||||
cur_tx_srate = srslte_rf_set_tx_srate(&rf_device, srate);
|
||||
burst_preamble_samples = (uint32_t)(cur_tx_srate * burst_preamble_sec);
|
||||
if (burst_preamble_samples > burst_preamble_max_samples) {
|
||||
fprintf(stderr,
|
||||
"Error setting TX srate %.1f MHz. Maximum burst preamble samples: %d, requested: %d\n",
|
||||
srate * 1e-6,
|
||||
burst_preamble_max_samples,
|
||||
burst_preamble_samples);
|
||||
if (!is_initialized) {
|
||||
return;
|
||||
}
|
||||
burst_preamble_time_rounded = (double)burst_preamble_samples / cur_tx_srate;
|
||||
cur_tx_srate = srslte_rf_set_tx_srate(&rf_device, srate);
|
||||
|
||||
int nsamples = 0;
|
||||
/* Set time advance for each known device if in auto mode */
|
||||
|
@ -450,7 +483,7 @@ void radio::set_tx_srate(double srate)
|
|||
cur_tx_srate);
|
||||
tx_adv_sec = blade_default_tx_adv_samples * (1 / cur_tx_srate) + blade_default_tx_adv_offset_sec;
|
||||
}
|
||||
} else {
|
||||
} else if (!strcmp(srslte_rf_name(&rf_device), "zmq")) {
|
||||
log_h->console("\nWarning TX/RX time offset has not been calibrated for device %s. Set a value manually\n\n",
|
||||
srslte_rf_name(&rf_device));
|
||||
}
|
||||
|
@ -467,14 +500,59 @@ void radio::set_tx_srate(double srate)
|
|||
}
|
||||
}
|
||||
|
||||
void radio::register_error_handler(srslte_rf_error_handler_t h)
|
||||
{
|
||||
srslte_rf_register_error_handler(&rf_device, h);
|
||||
}
|
||||
|
||||
srslte_rf_info_t* radio::get_info()
|
||||
{
|
||||
if (!is_initialized) {
|
||||
return NULL;
|
||||
}
|
||||
return srslte_rf_get_info(&rf_device);
|
||||
}
|
||||
|
||||
bool radio::get_metrics(rf_metrics_t* metrics)
|
||||
{
|
||||
*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"
|
||||
|
@ -38,7 +37,7 @@ enb::~enb()
|
|||
{
|
||||
// pool has to be cleaned after enb is deleted
|
||||
stack.reset();
|
||||
srslte::byte_buffer_pool::cleanup();
|
||||
srslte::byte_buffer_pool::cleanup();
|
||||
}
|
||||
|
||||
int enb::init(const all_args_t& args_, srslte::logger* logger_)
|
||||
|
@ -67,7 +66,7 @@ int enb::init(const all_args_t& args_, srslte::logger* logger_)
|
|||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
std::unique_ptr<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")
|
||||
|
|
|
@ -104,21 +104,21 @@ void phy_common::stop()
|
|||
* Each worker uses this function to indicate that all processing is done and data is ready for transmission or
|
||||
* there is no transmission at all (tx_enable). In that case, the end of burst message will be sent to the radio
|
||||
*/
|
||||
void phy_common::worker_end(void* tx_sem_id,
|
||||
cf_t* buffer[SRSLTE_MAX_PORTS],
|
||||
uint32_t nof_samples,
|
||||
srslte_timestamp_t tx_time)
|
||||
void phy_common::worker_end(void* tx_sem_id,
|
||||
srslte::rf_buffer_t& buffer,
|
||||
uint32_t nof_samples,
|
||||
srslte_timestamp_t tx_time)
|
||||
{
|
||||
// Wait for the green light to transmit in the current TTI
|
||||
semaphore.wait(tx_sem_id);
|
||||
|
||||
// Run DL channel emulator if created
|
||||
if (dl_channel) {
|
||||
dl_channel->run(buffer, buffer, nof_samples, tx_time);
|
||||
dl_channel->run(buffer.to_cf_t(), buffer.to_cf_t(), nof_samples, tx_time);
|
||||
}
|
||||
|
||||
// Always transmit on single radio
|
||||
radio->tx(0, buffer, nof_samples, tx_time);
|
||||
radio->tx(buffer, nof_samples, tx_time);
|
||||
|
||||
// Trigger MAC clock
|
||||
stack->tti_clock();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -84,32 +84,27 @@ void txrx::stop()
|
|||
|
||||
void txrx::run_thread()
|
||||
{
|
||||
sf_worker* worker = nullptr;
|
||||
cf_t* buffer[worker_com->get_nof_carriers() * worker_com->get_nof_ports(0)] = {};
|
||||
srslte_timestamp_t rx_time = {};
|
||||
srslte_timestamp_t tx_time = {};
|
||||
uint32_t sf_len = SRSLTE_SF_LEN_PRB(worker_com->get_nof_prb(0));
|
||||
sf_worker* worker = nullptr;
|
||||
srslte::rf_buffer_t buffer = {};
|
||||
srslte_timestamp_t rx_time = {};
|
||||
srslte_timestamp_t tx_time = {};
|
||||
uint32_t sf_len = SRSLTE_SF_LEN_PRB(worker_com->get_nof_prb(0));
|
||||
|
||||
float samp_rate = srslte_sampling_freq_hz(worker_com->get_nof_prb(0));
|
||||
|
||||
// Configure radio
|
||||
radio_h->set_rx_srate(0, samp_rate);
|
||||
radio_h->set_tx_srate(0, samp_rate);
|
||||
radio_h->set_rx_srate(samp_rate);
|
||||
radio_h->set_tx_srate(samp_rate);
|
||||
|
||||
// Set Tx/Rx frequencies
|
||||
for (uint32_t cc_idx = 0; cc_idx < worker_com->get_nof_carriers(); cc_idx++) {
|
||||
float tx_freq_hz = worker_com->get_dl_freq_hz(cc_idx);
|
||||
float rx_freq_hz = worker_com->get_ul_freq_hz(cc_idx);
|
||||
uint32_t rf_port = worker_com->get_rf_port(cc_idx);
|
||||
for (uint32_t i = 0; i < worker_com->get_nof_ports(cc_idx); i++) {
|
||||
radio_h->set_tx_freq(0, rf_port + i, tx_freq_hz);
|
||||
radio_h->set_rx_freq(0, rf_port + i, rx_freq_hz);
|
||||
}
|
||||
log_h->console("RF%d: samp_rate=%.2f MHz, DL=%.1f Mhz, UL=%.1f MHz\n",
|
||||
cc_idx,
|
||||
samp_rate / 1e6f,
|
||||
tx_freq_hz / 1e6f,
|
||||
rx_freq_hz / 1e6f);
|
||||
log_h->console(
|
||||
"Setting frequency: DL=%.1f Mhz, UL=%.1f MHz for cc_idx=%d\n", tx_freq_hz / 1e6f, rx_freq_hz / 1e6f, cc_idx);
|
||||
radio_h->set_tx_freq(rf_port, tx_freq_hz);
|
||||
radio_h->set_rx_freq(rf_port, rx_freq_hz);
|
||||
}
|
||||
|
||||
// Set channel emulator sampling rate
|
||||
|
@ -131,14 +126,15 @@ void txrx::run_thread()
|
|||
for (uint32_t cc = 0; cc < worker_com->get_nof_carriers(); cc++) {
|
||||
uint32_t rf_port = worker_com->get_rf_port(cc);
|
||||
for (uint32_t p = 0; p < worker_com->get_nof_ports(cc); p++) {
|
||||
buffer[rf_port + p] = worker->get_buffer_rx(cc, p);
|
||||
// WARNING: The number of ports for all cells must be the same
|
||||
buffer.set(rf_port, p, worker_com->get_nof_ports(0), worker->get_buffer_rx(cc, p));
|
||||
}
|
||||
}
|
||||
|
||||
radio_h->rx_now(0, buffer, sf_len, &rx_time);
|
||||
radio_h->rx_now(buffer, sf_len, &rx_time);
|
||||
|
||||
if (ul_channel) {
|
||||
ul_channel->run(buffer, buffer, sf_len, rx_time);
|
||||
ul_channel->run(buffer.to_cf_t(), buffer.to_cf_t(), sf_len, rx_time);
|
||||
}
|
||||
|
||||
/* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */
|
||||
|
@ -161,7 +157,7 @@ void txrx::run_thread()
|
|||
|
||||
// Trigger prach worker execution
|
||||
for (uint32_t cc = 0; cc < worker_com->get_nof_carriers(); cc++) {
|
||||
prach->new_tti(cc, tti, buffer[worker_com->get_rf_port(cc) * worker_com->get_nof_ports(cc)]);
|
||||
prach->new_tti(cc, tti, buffer.get(worker_com->get_rf_port(cc), 0, worker_com->get_nof_ports(0)));
|
||||
}
|
||||
} else {
|
||||
// wait_worker() only returns NULL if it's being closed. Quit now to avoid unnecessary loops here
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -109,9 +109,9 @@ private:
|
|||
cf_t* prach_ptr = nullptr;
|
||||
float prach_power = 0;
|
||||
|
||||
uint32_t tti = 0;
|
||||
srslte_timestamp_t tx_time[SRSLTE_MAX_RADIOS] = {};
|
||||
int next_offset[SRSLTE_MAX_RADIOS] = {};
|
||||
uint32_t tti = 0;
|
||||
srslte_timestamp_t tx_time = {};
|
||||
int next_offset = {};
|
||||
|
||||
uint32_t rssi_read_cnt = 0;
|
||||
};
|
||||
|
|
|
@ -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,19 +99,19 @@ private:
|
|||
typedef enum { CELL_NOT_FOUND, CELL_FOUND, ERROR, TIMEOUT } ret_code;
|
||||
|
||||
~search();
|
||||
void init(cf_t* buffer[SRSLTE_MAX_PORTS], srslte::log* log_h, uint32_t nof_rx_antennas, sync* parent);
|
||||
void init(srslte::rf_buffer_t& buffer_, srslte::log* log_h, uint32_t nof_rx_channels, sync* parent);
|
||||
void reset();
|
||||
float get_last_cfo();
|
||||
void set_agc_enable(bool enable);
|
||||
ret_code run(srslte_cell_t* cell, std::array<uint8_t, SRSLTE_BCH_PAYLOAD_LEN>& bch_payload);
|
||||
|
||||
private:
|
||||
sync* p = nullptr;
|
||||
srslte::log* log_h = nullptr;
|
||||
cf_t* buffer[SRSLTE_MAX_PORTS] = {};
|
||||
srslte_ue_cellsearch_t cs = {};
|
||||
srslte_ue_mib_sync_t ue_mib_sync = {};
|
||||
int force_N_id_2 = 0;
|
||||
sync* p = nullptr;
|
||||
srslte::log* log_h = nullptr;
|
||||
srslte::rf_buffer_t buffer = {};
|
||||
srslte_ue_cellsearch_t cs = {};
|
||||
srslte_ue_mib_sync_t ue_mib_sync = {};
|
||||
int force_N_id_2 = 0;
|
||||
};
|
||||
|
||||
// Class to synchronize system frame number
|
||||
|
@ -122,11 +121,11 @@ private:
|
|||
typedef enum { IDLE, SFN_FOUND, SFX0_FOUND, SFN_NOFOUND, ERROR } ret_code;
|
||||
sfn_sync() = default;
|
||||
~sfn_sync();
|
||||
void init(srslte_ue_sync_t* ue_sync,
|
||||
cf_t* buffer[SRSLTE_MAX_PORTS],
|
||||
uint32_t buffer_max_samples_,
|
||||
srslte::log* log_h,
|
||||
uint32_t nof_subframes = SFN_SYNC_NOF_SUBFRAMES);
|
||||
void init(srslte_ue_sync_t* ue_sync,
|
||||
srslte::rf_buffer_t& buffer,
|
||||
uint32_t buffer_max_samples_,
|
||||
srslte::log* log_h,
|
||||
uint32_t nof_subframes = SFN_SYNC_NOF_SUBFRAMES);
|
||||
void reset();
|
||||
bool set_cell(srslte_cell_t cell);
|
||||
ret_code run_subframe(srslte_cell_t* cell,
|
||||
|
@ -135,20 +134,20 @@ private:
|
|||
bool sfidx_only = false);
|
||||
ret_code decode_mib(srslte_cell_t* cell,
|
||||
uint32_t* tti_cnt,
|
||||
cf_t* ext_buffer[SRSLTE_MAX_PORTS],
|
||||
srslte::rf_buffer_t* ext_buffer,
|
||||
std::array<uint8_t, SRSLTE_BCH_PAYLOAD_LEN>& bch_payload,
|
||||
bool sfidx_only = false);
|
||||
|
||||
private:
|
||||
const static int SFN_SYNC_NOF_SUBFRAMES = 100;
|
||||
|
||||
uint32_t cnt = 0;
|
||||
uint32_t timeout = 0;
|
||||
srslte::log* log_h = nullptr;
|
||||
srslte_ue_sync_t* ue_sync = nullptr;
|
||||
cf_t* buffer[SRSLTE_MAX_PORTS] = {};
|
||||
uint32_t buffer_max_samples = 0;
|
||||
srslte_ue_mib_t ue_mib = {};
|
||||
uint32_t cnt = 0;
|
||||
uint32_t timeout = 0;
|
||||
srslte::log* log_h = nullptr;
|
||||
srslte_ue_sync_t* ue_sync = nullptr;
|
||||
srslte::rf_buffer_t mib_buffer = {};
|
||||
uint32_t buffer_max_samples = 0;
|
||||
srslte_ue_mib_t ue_mib = {};
|
||||
};
|
||||
|
||||
/* TODO: Intra-freq measurements can be improved by capturing 200 ms length signal and run cell search +
|
||||
|
@ -176,9 +175,9 @@ private:
|
|||
sfn_sync sfn_p;
|
||||
std::vector<std::unique_ptr<scell::intra_measure> > intra_freq_meas;
|
||||
|
||||
uint32_t current_sflen = 0;
|
||||
int next_offset = 0; // Sample offset triggered by Time aligment commands
|
||||
int next_radio_offset[SRSLTE_MAX_RADIOS] = {}; // Sample offset triggered by SFO compensation
|
||||
uint32_t current_sflen = 0;
|
||||
int next_offset = 0; // Sample offset triggered by Time aligment commands
|
||||
int next_radio_offset = 0; // Sample offset triggered by SFO compensation
|
||||
|
||||
// Pointers to other classes
|
||||
stack_interface_phy_lte* stack = nullptr;
|
||||
|
@ -188,14 +187,14 @@ private:
|
|||
srslte::radio_interface_phy* radio_h = nullptr;
|
||||
phy_common* worker_com = nullptr;
|
||||
prach* prach_buffer = nullptr;
|
||||
scell::async_recv_vector* scell_sync = nullptr;
|
||||
srslte::channel_ptr channel_emulator = nullptr;
|
||||
|
||||
// Object for synchronization of the primary cell
|
||||
srslte_ue_sync_t ue_sync = {};
|
||||
|
||||
// Buffer for primary and secondary cell samples
|
||||
cf_t* sf_buffer[SRSLTE_MAX_RADIOS][SRSLTE_MAX_PORTS] = {};
|
||||
const static uint32_t sync_nof_rx_subframes = 5;
|
||||
srslte::rf_buffer_t sf_buffer = {};
|
||||
|
||||
// Sync metrics
|
||||
sync_metrics_t metrics = {};
|
||||
|
@ -349,10 +348,10 @@ private:
|
|||
uint32_t tti = 0;
|
||||
srslte_timestamp_t tti_ts = {};
|
||||
srslte_timestamp_t radio_ts = {};
|
||||
std::array<uint8_t, SRSLTE_BCH_PAYLOAD_LEN> mib;
|
||||
|
||||
uint32_t nof_workers = 0;
|
||||
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)
|
||||
|
||||
########################################################################
|
||||
|
|
|
@ -78,22 +78,18 @@ static int parse_args(all_args_t* args, int argc, char* argv[])
|
|||
("ue.phy", bpo::value<string>(&args->phy.type)->default_value("lte"), "Type of the PHY [lte]")
|
||||
("ue.stack", bpo::value<string>(&args->stack.type)->default_value("lte"), "Type of the upper stack [lte]")
|
||||
|
||||
("rf.dl_earfcn", bpo::value<string>(&args->phy.dl_earfcn)->default_value("3400"), "Downlink EARFCN list")
|
||||
("rf.freq_offset", bpo::value<float>(&args->rf.freq_offset)->default_value(0), "(optional) Frequency offset")
|
||||
("rf.dl_freq", bpo::value<float>(&args->phy.dl_freq)->default_value(-1), "Downlink Frequency (if positive overrides EARFCN)")
|
||||
("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.dl_earfcn", bpo::value<string>(&args->phy.dl_earfcn)->default_value("3400"), "Downlink EARFCN list")
|
||||
("rf.freq_offset", bpo::value<float>(&args->rf.freq_offset)->default_value(0), "(optional) Frequency offset")
|
||||
("rf.dl_freq", bpo::value<float>(&args->phy.dl_freq)->default_value(-1), "Downlink Frequency (if positive overrides EARFCN)")
|
||||
("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_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)
|
||||
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;
|
||||
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)
|
||||
bool phy::check_args(const phy_args_t& args_)
|
||||
{
|
||||
if (args.nof_phy_threads > MAX_WORKERS) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
// Change frequency only if the earfcn was modified
|
||||
if (common.scell_cfg[cc_idx].earfcn != earfcn) {
|
||||
float dl_freq = srslte_band_fd(earfcn) * 1e6f;
|
||||
float ul_freq = srslte_band_fu(srslte_band_ul_earfcn(earfcn)) * 1e6f;
|
||||
radio->set_rx_freq(cc_idx, dl_freq);
|
||||
radio->set_tx_freq(cc_idx, ul_freq);
|
||||
}
|
||||
|
||||
// Store SCell earfcn and pci
|
||||
|
|
|
@ -42,8 +42,7 @@ using namespace asn1::rrc;
|
|||
|
||||
namespace srsue {
|
||||
|
||||
static cf_t zeros[50000] = {};
|
||||
static cf_t* zeros_multi[SRSLTE_MAX_PORTS] = {zeros, zeros, zeros, zeros};
|
||||
static srslte::rf_buffer_t zeros_multi(1);
|
||||
|
||||
phy_common::phy_common()
|
||||
{
|
||||
|
@ -73,8 +72,7 @@ void phy_common::init(phy_args_t* _args,
|
|||
|
||||
// Instantiate UL channel emulator
|
||||
if (args->ul_channel_args.enable) {
|
||||
ul_channel =
|
||||
srslte::channel_ptr(new srslte::channel(args->ul_channel_args, args->nof_rf_channels * args->nof_rx_ant));
|
||||
ul_channel = srslte::channel_ptr(new srslte::channel(args->ul_channel_args, args->nof_carriers * args->nof_rx_ant));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -525,45 +523,41 @@ bool phy_common::get_dl_pending_ack(srslte_ul_sf_cfg_t* sf, uint32_t cc_idx, srs
|
|||
* Each worker uses this function to indicate that all processing is done and data is ready for transmission or
|
||||
* there is no transmission at all (tx_enable). In that case, the end of burst message will be sent to the radio
|
||||
*/
|
||||
void phy_common::worker_end(void* tx_sem_id,
|
||||
bool tx_enable,
|
||||
cf_t* buffer[SRSLTE_MAX_RADIOS][SRSLTE_MAX_PORTS],
|
||||
uint32_t nof_samples[SRSLTE_MAX_RADIOS],
|
||||
srslte_timestamp_t tx_time[SRSLTE_MAX_RADIOS])
|
||||
void phy_common::worker_end(void* tx_sem_id,
|
||||
bool tx_enable,
|
||||
srslte::rf_buffer_t& buffer,
|
||||
uint32_t nof_samples,
|
||||
srslte_timestamp_t tx_time)
|
||||
{
|
||||
// Wait for the green light to transmit in the current TTI
|
||||
semaphore.wait(tx_sem_id);
|
||||
|
||||
// For each radio, transmit
|
||||
for (uint32_t i = 0; i < args->nof_radios; i++) {
|
||||
if (tx_enable && !srslte_timestamp_iszero(&tx_time[i])) {
|
||||
if (tx_enable && !srslte_timestamp_iszero(&tx_time)) {
|
||||
|
||||
if (ul_channel) {
|
||||
ul_channel->run(buffer[i], buffer[i], nof_samples[i], tx_time[i]);
|
||||
}
|
||||
if (ul_channel) {
|
||||
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]);
|
||||
} else {
|
||||
if (radio_h->is_continuous_tx()) {
|
||||
if (is_pending_tx_end) {
|
||||
radio_h->tx_end();
|
||||
is_pending_tx_end = false;
|
||||
} else {
|
||||
if (!radio_h->get_is_start_of_burst(i)) {
|
||||
|
||||
if (ul_channel && !srslte_timestamp_iszero(&tx_time[i])) {
|
||||
bzero(zeros_multi[0], sizeof(cf_t) * nof_samples[i]);
|
||||
ul_channel->run(zeros_multi, zeros_multi, nof_samples[i], tx_time[i]);
|
||||
}
|
||||
|
||||
radio_h->tx(i, zeros_multi, nof_samples[i], tx_time[i]);
|
||||
}
|
||||
}
|
||||
radio_h->tx(buffer, nof_samples, tx_time);
|
||||
} else {
|
||||
if (radio_h->is_continuous_tx()) {
|
||||
if (is_pending_tx_end) {
|
||||
radio_h->tx_end();
|
||||
is_pending_tx_end = false;
|
||||
} else {
|
||||
if (i == 0) {
|
||||
radio_h->tx_end();
|
||||
if (!radio_h->get_is_start_of_burst()) {
|
||||
|
||||
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(zeros_multi, nof_samples, tx_time);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
radio_h->tx_end();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -622,9 +616,9 @@ void phy_common::set_ul_metrics(const ul_metrics_t m, uint32_t cc_idx)
|
|||
}
|
||||
}
|
||||
|
||||
void phy_common::get_ul_metrics(ul_metrics_t m[SRSLTE_MAX_RADIOS])
|
||||
void phy_common::get_ul_metrics(ul_metrics_t m[SRSLTE_MAX_CARRIERS])
|
||||
{
|
||||
memcpy(m, ul_metrics, sizeof(ul_metrics_t) * SRSLTE_MAX_RADIOS);
|
||||
memcpy(m, ul_metrics, sizeof(ul_metrics_t) * SRSLTE_MAX_CARRIERS);
|
||||
ul_metrics_read = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 *******/
|
||||
|
@ -227,12 +228,8 @@ void sf_worker::work_imp()
|
|||
|
||||
/***** Uplink Generation + Transmission *******/
|
||||
|
||||
bool tx_signal_ready = false;
|
||||
cf_t* tx_signal_ptr[SRSLTE_MAX_RADIOS][SRSLTE_MAX_PORTS] = {};
|
||||
uint32_t nof_samples[SRSLTE_MAX_RADIOS] = {};
|
||||
for (uint32_t i = 0; i < phy->args->nof_radios; i++) {
|
||||
nof_samples[i] = SRSLTE_SF_LEN_PRB(cell.nof_prb);
|
||||
}
|
||||
bool tx_signal_ready = false;
|
||||
uint32_t nof_samples = SRSLTE_SF_LEN_PRB(cell.nof_prb);
|
||||
|
||||
/* If TTI+4 is an uplink subframe (TODO: Support short PRACH and SRS in UpPts special subframes) */
|
||||
if ((srslte_sfidx_tdd_type(tdd_config, TTI_TX(tti) % 10) == SRSLTE_TDD_SF_U) || cell.frame_type == SRSLTE_FDD) {
|
||||
|
@ -247,15 +244,12 @@ void sf_worker::work_imp()
|
|||
for (int carrier_idx = phy->args->nof_carriers - 1; carrier_idx >= 0; carrier_idx--) {
|
||||
tx_signal_ready = cc_workers[carrier_idx]->work_ul(&uci_data);
|
||||
|
||||
// Get carrier mapping
|
||||
carrier_map_t* m = &phy->args->carrier_map[carrier_idx];
|
||||
|
||||
// Set signal pointer based on offset
|
||||
cf_t* b = cc_workers[carrier_idx]->get_tx_buffer(0);
|
||||
if (next_offset[m->radio_idx] > 0) {
|
||||
tx_signal_ptr[m->radio_idx][m->channel_idx] = b;
|
||||
if (next_offset > 0) {
|
||||
tx_signal_ptr.set(carrier_idx, 0, phy->args->nof_rx_ant, b);
|
||||
} else {
|
||||
tx_signal_ptr[m->radio_idx][m->channel_idx] = &b[-next_offset[m->radio_idx]];
|
||||
tx_signal_ptr.set(carrier_idx, 0, phy->args->nof_rx_ant, &b[-next_offset]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -263,13 +257,11 @@ void sf_worker::work_imp()
|
|||
|
||||
// Set PRACH buffer signal pointer
|
||||
if (prach_ptr) {
|
||||
tx_signal_ready = true;
|
||||
tx_signal_ptr[0][0] = prach_ptr;
|
||||
prach_ptr = nullptr;
|
||||
tx_signal_ready = true;
|
||||
tx_signal_ptr.set(0, prach_ptr);
|
||||
prach_ptr = nullptr;
|
||||
} else {
|
||||
for (uint32_t i = 0; i < phy->args->nof_radios; i++) {
|
||||
nof_samples[i] += next_offset[i];
|
||||
}
|
||||
nof_samples += next_offset;
|
||||
}
|
||||
|
||||
// Call worker_end to transmit the signal
|
||||
|
@ -317,7 +309,7 @@ void sf_worker::update_measurements()
|
|||
}
|
||||
|
||||
if (!rssi_read_cnt) {
|
||||
phy->rx_gain_offset = phy->get_radio()->get_rx_gain(0) + phy->args->rx_gain_offset;
|
||||
phy->rx_gain_offset = phy->get_radio()->get_rx_gain() + phy->args->rx_gain_offset;
|
||||
}
|
||||
rssi_read_cnt++;
|
||||
if (rssi_read_cnt == 1000) {
|
||||
|
|
|
@ -42,9 +42,11 @@
|
|||
|
||||
namespace srsue {
|
||||
|
||||
static int radio_recv_callback(void* obj, cf_t* data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t* rx_time)
|
||||
static int
|
||||
radio_recv_callback(void* obj, cf_t* data[SRSLTE_MAX_CHANNELS], uint32_t nsamples, srslte_timestamp_t* rx_time)
|
||||
{
|
||||
return ((sync*)obj)->radio_recv_fnc(data, nsamples, rx_time);
|
||||
srslte::rf_buffer_t x(data);
|
||||
return ((sync*)obj)->radio_recv_fnc(x, nsamples, rx_time);
|
||||
}
|
||||
|
||||
static SRSLTE_AGC_CALLBACK(callback_set_rx_gain)
|
||||
|
@ -59,7 +61,6 @@ void sync::init(srslte::radio_interface_phy* _radio,
|
|||
phy_common* _worker_com,
|
||||
srslte::log* _log_h,
|
||||
srslte::log* _log_phy_lib_h,
|
||||
scell::async_recv_vector* scell_sync_,
|
||||
uint32_t prio,
|
||||
int sync_cpu_affinity)
|
||||
{
|
||||
|
@ -67,16 +68,14 @@ void sync::init(srslte::radio_interface_phy* _radio,
|
|||
log_h = _log_h;
|
||||
log_phy_lib_h = _log_phy_lib_h;
|
||||
stack = _stack;
|
||||
scell_sync = scell_sync_;
|
||||
workers_pool = _workers_pool;
|
||||
worker_com = _worker_com;
|
||||
prach_buffer = _prach_buffer;
|
||||
|
||||
uint32_t nof_rf_channels = worker_com->args->nof_rf_channels * worker_com->args->nof_rx_ant;
|
||||
for (uint32_t r = 0; r < worker_com->args->nof_radios; r++) {
|
||||
for (uint32_t p = 0; p < nof_rf_channels; p++) {
|
||||
sf_buffer[r][p] = srslte_vec_cf_malloc(SF_BUFFER_MAX_SAMPLES);
|
||||
}
|
||||
nof_rf_channels = worker_com->args->nof_carriers * worker_com->args->nof_rx_ant;
|
||||
if (nof_rf_channels == 0 || nof_rf_channels > SRSLTE_MAX_CHANNELS) {
|
||||
Error("SYNC: Invalid number of RF channels (%d)\n", nof_rf_channels);
|
||||
return;
|
||||
}
|
||||
|
||||
if (srslte_ue_sync_init_multi(&ue_sync, SRSLTE_MAX_PRB, false, radio_recv_callback, nof_rf_channels, this)) {
|
||||
|
@ -92,10 +91,10 @@ void sync::init(srslte::radio_interface_phy* _radio,
|
|||
worker_com->set_nof_workers(nof_workers);
|
||||
|
||||
// Initialize cell searcher
|
||||
search_p.init(sf_buffer[0], log_h, nof_rf_channels, this);
|
||||
search_p.init(sf_buffer, log_h, nof_rf_channels, this);
|
||||
|
||||
// Initialize SFN synchronizer, it uses only pcell buffer
|
||||
sfn_p.init(&ue_sync, sf_buffer[0], SF_BUFFER_MAX_SAMPLES, log_h);
|
||||
sfn_p.init(&ue_sync, sf_buffer, sf_buffer.size(), log_h);
|
||||
|
||||
// Start intra-frequency measurement
|
||||
for (uint32_t i = 0; i < worker_com->args->nof_carriers; i++) {
|
||||
|
@ -110,13 +109,6 @@ void sync::init(srslte::radio_interface_phy* _radio,
|
|||
// Enable AGC for primary cell receiver
|
||||
set_agc_enable(worker_com->args->agc_enable);
|
||||
|
||||
// Enable AGC for secondary asynchronous receiver
|
||||
if (scell_sync) {
|
||||
for (auto& q : *scell_sync) {
|
||||
q->set_agc_enable(worker_com->args->agc_enable);
|
||||
}
|
||||
}
|
||||
|
||||
// Start main thread
|
||||
if (sync_cpu_affinity < 0) {
|
||||
start(prio);
|
||||
|
@ -127,13 +119,6 @@ void sync::init(srslte::radio_interface_phy* _radio,
|
|||
|
||||
sync::~sync()
|
||||
{
|
||||
for (uint32_t r = 0; r < SRSLTE_MAX_RADIOS; r++) {
|
||||
for (uint32_t p = 0; p < SRSLTE_MAX_PORTS; p++) {
|
||||
if (sf_buffer[r][p]) {
|
||||
free(sf_buffer[r][p]);
|
||||
}
|
||||
}
|
||||
}
|
||||
srslte_ue_sync_free(&ue_sync);
|
||||
}
|
||||
|
||||
|
@ -155,9 +140,9 @@ void sync::reset()
|
|||
out_of_sync_cnt = 0;
|
||||
time_adv_sec = 0;
|
||||
next_offset = 0;
|
||||
next_radio_offset = 0;
|
||||
current_earfcn = -1;
|
||||
srate_mode = SRATE_NONE;
|
||||
ZERO_OBJECT(next_radio_offset);
|
||||
current_earfcn = -1;
|
||||
sfn_p.reset();
|
||||
search_p.reset();
|
||||
}
|
||||
|
@ -215,8 +200,8 @@ phy_interface_rrc_lte::cell_search_ret_t sync::cell_search(phy_interface_rrc_lte
|
|||
|
||||
if (srate_mode != SRATE_FIND) {
|
||||
srate_mode = SRATE_FIND;
|
||||
radio_h->set_rx_srate(0, 1.92e6);
|
||||
radio_h->set_tx_srate(0, 1.92e6);
|
||||
radio_h->set_rx_srate(1.92e6);
|
||||
radio_h->set_tx_srate(1.92e6);
|
||||
Info("SYNC: Setting Cell Search sampling rate\n");
|
||||
}
|
||||
|
||||
|
@ -372,22 +357,14 @@ bool sync::cell_is_camping()
|
|||
|
||||
void sync::run_thread()
|
||||
{
|
||||
sf_worker* worker = nullptr;
|
||||
cf_t* buffer[SRSLTE_MAX_RADIOS][SRSLTE_MAX_PORTS] = {};
|
||||
srslte_cell_t temp_cell = {};
|
||||
sf_worker* worker = nullptr;
|
||||
srslte_cell_t temp_cell = {};
|
||||
|
||||
bool is_end_of_burst = false;
|
||||
bool force_camping_sfn_sync = false;
|
||||
|
||||
cf_t* dummy_buffer[SRSLTE_MAX_PORTS];
|
||||
uint32_t nof_rf_channels = worker_com->args->nof_rf_channels * worker_com->args->nof_rx_ant;
|
||||
if (nof_rf_channels > SRSLTE_MAX_PORTS) {
|
||||
fprintf(stderr, "Fatal error: nof_rf_channels x nof_rx_ant must be lower than %d\n", SRSLTE_MAX_PORTS);
|
||||
return;
|
||||
}
|
||||
for (uint32_t i = 0; i < nof_rf_channels; i++) {
|
||||
dummy_buffer[i] = srslte_vec_cf_malloc(3 * SRSLTE_SF_LEN_PRB(100));
|
||||
}
|
||||
srslte::rf_buffer_t dummy_buffer(sync_nof_rx_subframes);
|
||||
srslte::rf_buffer_t sync_buffer = {};
|
||||
|
||||
uint32_t prach_nof_sf = 0;
|
||||
uint32_t prach_sf_cnt = 0;
|
||||
|
@ -448,17 +425,15 @@ void sync::run_thread()
|
|||
|
||||
worker = (sf_worker*)workers_pool->wait_worker(tti);
|
||||
if (worker) {
|
||||
// For each carrier...
|
||||
// Map carrier/antenna buffers to worker buffers
|
||||
for (uint32_t c = 0; c < worker_com->args->nof_carriers; c++) {
|
||||
// get carrier mapping
|
||||
carrier_map_t* m = &worker_com->args->carrier_map[c];
|
||||
for (uint32_t i = 0; i < worker_com->args->nof_rx_ant; i++) {
|
||||
buffer[m->radio_idx][m->channel_idx + i] = worker->get_buffer(c, i);
|
||||
sync_buffer.set(c, i, worker_com->args->nof_rx_ant, worker->get_buffer(c, i));
|
||||
}
|
||||
}
|
||||
|
||||
// Primary Cell (PCell) Synchronization
|
||||
switch (srslte_ue_sync_zerocopy(&ue_sync, buffer[0], worker->get_buffer_len())) {
|
||||
switch (srslte_ue_sync_zerocopy(&ue_sync, sync_buffer.to_cf_t(), worker->get_buffer_len())) {
|
||||
case 1:
|
||||
|
||||
// Check tti is synched with ue_sync
|
||||
|
@ -474,7 +449,7 @@ void sync::run_thread()
|
|||
if (force_camping_sfn_sync) {
|
||||
uint32_t _tti = 0;
|
||||
temp_cell = cell;
|
||||
sync::sfn_sync::ret_code ret = sfn_p.decode_mib(&temp_cell, &_tti, buffer[0], mib);
|
||||
sync::sfn_sync::ret_code ret = sfn_p.decode_mib(&temp_cell, &_tti, &sf_buffer, mib);
|
||||
if (ret == sfn_sync::SFN_FOUND) {
|
||||
// Force tti
|
||||
tti = _tti;
|
||||
|
@ -493,30 +468,11 @@ void sync::run_thread()
|
|||
|
||||
Debug("SYNC: Worker %d synchronized\n", worker->get_id());
|
||||
|
||||
// Read Asynchronous SCell, for each asynch active object
|
||||
for (uint32_t i = 0; i < worker_com->args->nof_radios - 1; i++) {
|
||||
srslte_timestamp_t tx_time;
|
||||
srslte_timestamp_init(&tx_time, 0, 0);
|
||||
|
||||
// Request TTI aligment
|
||||
if (scell_sync->at(i)->tti_align(tti)) {
|
||||
scell_sync->at(i)->read_sf(buffer[i + 1], &tx_time, &next_radio_offset[i + 1]);
|
||||
srslte_timestamp_add(&tx_time, 0, TX_DELAY * 1e-3 - time_adv_sec);
|
||||
} else {
|
||||
// Failed, keep default Timestamp
|
||||
// Error("SCell asynchronous failed to synchronise (%d)\n", i);
|
||||
}
|
||||
|
||||
worker->set_tx_time(i + 1, tx_time, next_radio_offset[i + 1] + next_offset);
|
||||
}
|
||||
|
||||
metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync);
|
||||
metrics.cfo = srslte_ue_sync_get_cfo(&ue_sync);
|
||||
metrics.ta_us = time_adv_sec * 1e6f;
|
||||
for (uint32_t i = 0; i < worker_com->args->nof_carriers; i++) {
|
||||
if (worker_com->args->carrier_map[i].radio_idx == 0) {
|
||||
worker_com->set_sync_metrics(i, metrics);
|
||||
}
|
||||
worker_com->set_sync_metrics(i, metrics);
|
||||
}
|
||||
|
||||
// Check if we need to TX a PRACH
|
||||
|
@ -538,24 +494,11 @@ void sync::run_thread()
|
|||
|
||||
// Set CFO for all Carriers
|
||||
for (uint32_t cc = 0; cc < worker_com->args->nof_carriers; cc++) {
|
||||
float cfo;
|
||||
|
||||
// Get radio index for the given carrier
|
||||
uint32_t radio_idx = worker_com->args->carrier_map[cc].radio_idx;
|
||||
|
||||
if (radio_idx == 0) {
|
||||
// Use local CFO
|
||||
cfo = get_tx_cfo();
|
||||
} else {
|
||||
// Request CFO in the asynchronous receiver
|
||||
cfo = scell_sync->at(radio_idx - 1)->get_tx_cfo();
|
||||
}
|
||||
|
||||
worker->set_cfo(cc, cfo);
|
||||
worker->set_cfo(cc, get_tx_cfo());
|
||||
}
|
||||
|
||||
worker->set_tti(tti);
|
||||
worker->set_tx_time(0, tx_time, next_radio_offset[0] + next_offset);
|
||||
worker->set_tx_time(tx_time, next_radio_offset + next_offset);
|
||||
next_offset = 0;
|
||||
ZERO_OBJECT(next_radio_offset);
|
||||
|
||||
|
@ -669,12 +612,6 @@ void sync::run_thread()
|
|||
// Increase TTI counter
|
||||
tti = (tti + 1) % 10240;
|
||||
}
|
||||
|
||||
for (uint32_t p = 0; p < nof_rf_channels; p++) {
|
||||
if (dummy_buffer[p]) {
|
||||
free(dummy_buffer[p]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***************
|
||||
|
@ -728,10 +665,10 @@ void sync::set_agc_enable(bool enable)
|
|||
{
|
||||
if (enable) {
|
||||
if (running && radio_h) {
|
||||
srslte_rf_info_t* rf_info = radio_h->get_info(0);
|
||||
srslte_rf_info_t* rf_info = radio_h->get_info();
|
||||
if (rf_info) {
|
||||
srslte_ue_sync_start_agc(
|
||||
&ue_sync, callback_set_rx_gain, rf_info->min_rx_gain, rf_info->max_rx_gain, radio_h->get_rx_gain(0));
|
||||
&ue_sync, callback_set_rx_gain, rf_info->min_rx_gain, rf_info->max_rx_gain, radio_h->get_rx_gain());
|
||||
search_p.set_agc_enable(true);
|
||||
} else {
|
||||
ERROR("Error: Radio does not provide RF information\n");
|
||||
|
@ -887,13 +824,11 @@ bool sync::set_frequency()
|
|||
set_dl_freq / 1e6,
|
||||
set_ul_freq / 1e6);
|
||||
|
||||
carrier_map_t* m = &worker_com->args->carrier_map[0];
|
||||
for (uint32_t i = 0; i < worker_com->args->nof_rx_ant; i++) {
|
||||
radio_h->set_rx_freq(m->radio_idx, m->channel_idx + i, set_dl_freq);
|
||||
radio_h->set_tx_freq(m->radio_idx, m->channel_idx + i, set_ul_freq);
|
||||
}
|
||||
// Logical channel is 0
|
||||
radio_h->set_rx_freq(0, set_dl_freq);
|
||||
radio_h->set_tx_freq(0, set_ul_freq);
|
||||
|
||||
ul_dl_factor = (float)(radio_h->get_tx_freq(m->radio_idx) / radio_h->get_rx_freq(m->radio_idx));
|
||||
ul_dl_factor = (float)(set_ul_freq / set_dl_freq);
|
||||
|
||||
srslte_ue_sync_reset(&ue_sync);
|
||||
|
||||
|
@ -918,8 +853,8 @@ void sync::set_sampling_rate()
|
|||
Info("SYNC: Setting sampling rate %.2f MHz\n", current_srate / 1000000);
|
||||
|
||||
srate_mode = SRATE_CAMP;
|
||||
radio_h->set_rx_srate(0, current_srate);
|
||||
radio_h->set_tx_srate(0, current_srate);
|
||||
radio_h->set_rx_srate(current_srate);
|
||||
radio_h->set_tx_srate(current_srate);
|
||||
} else {
|
||||
Error("Error setting sampling rate for cell with %d PRBs\n", cell.nof_prb);
|
||||
}
|
||||
|
@ -940,7 +875,7 @@ void sync::get_current_cell(srslte_cell_t* cell_, uint32_t* earfcn_)
|
|||
}
|
||||
}
|
||||
|
||||
int sync::radio_recv_fnc(cf_t* data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t* rx_time)
|
||||
int sync::radio_recv_fnc(srslte::rf_buffer_t& data, uint32_t nsamples, srslte_timestamp_t* rx_time)
|
||||
{
|
||||
srslte_timestamp_t ts = {};
|
||||
|
||||
|
@ -950,7 +885,7 @@ int sync::radio_recv_fnc(cf_t* data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte
|
|||
}
|
||||
|
||||
// Receive
|
||||
if (radio_h->rx_now(0, data, nsamples, rx_time)) {
|
||||
if (radio_h->rx_now(data, nsamples, rx_time)) {
|
||||
// Detect Radio Timestamp reset
|
||||
if (srslte_timestamp_compare(rx_time, &radio_ts) < 0) {
|
||||
srslte_timestamp_init(&radio_ts, 0, 0.0);
|
||||
|
@ -968,14 +903,14 @@ int sync::radio_recv_fnc(cf_t* data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte
|
|||
|
||||
if (channel_emulator && rx_time) {
|
||||
channel_emulator->set_srate((uint32_t)current_srate);
|
||||
channel_emulator->run(data, data, nsamples, *rx_time);
|
||||
channel_emulator->run(data.to_cf_t(), data.to_cf_t(), nsamples, *rx_time);
|
||||
}
|
||||
|
||||
int offset = nsamples - current_sflen;
|
||||
if (abs(offset) < 10 && offset != 0) {
|
||||
next_radio_offset[0] = offset;
|
||||
next_radio_offset = offset;
|
||||
} else if (nsamples < 10) {
|
||||
next_radio_offset[0] = nsamples;
|
||||
next_radio_offset = nsamples;
|
||||
}
|
||||
|
||||
log_h->debug("SYNC: received %d samples from radio\n", nsamples);
|
||||
|
@ -1000,21 +935,19 @@ sync::search::~search()
|
|||
srslte_ue_cellsearch_free(&cs);
|
||||
}
|
||||
|
||||
void sync::search::init(cf_t* buffer_[SRSLTE_MAX_PORTS], srslte::log* log_h_, uint32_t nof_rx_antennas, sync* parent)
|
||||
void sync::search::init(srslte::rf_buffer_t& buffer_, srslte::log* log_h_, uint32_t nof_rx_channels, sync* parent)
|
||||
{
|
||||
log_h = log_h_;
|
||||
p = parent;
|
||||
|
||||
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
|
||||
buffer[i] = buffer_[i];
|
||||
}
|
||||
buffer = buffer_;
|
||||
|
||||
if (srslte_ue_cellsearch_init_multi(&cs, 8, radio_recv_callback, nof_rx_antennas, parent)) {
|
||||
if (srslte_ue_cellsearch_init_multi(&cs, 8, radio_recv_callback, nof_rx_channels, parent)) {
|
||||
Error("SYNC: Initiating UE cell search\n");
|
||||
}
|
||||
srslte_ue_cellsearch_set_nof_valid_frames(&cs, 4);
|
||||
|
||||
if (srslte_ue_mib_sync_init_multi(&ue_mib_sync, radio_recv_callback, nof_rx_antennas, parent)) {
|
||||
if (srslte_ue_mib_sync_init_multi(&ue_mib_sync, radio_recv_callback, nof_rx_channels, parent)) {
|
||||
Error("SYNC: Initiating UE MIB synchronization\n");
|
||||
}
|
||||
|
||||
|
@ -1037,12 +970,12 @@ float sync::search::get_last_cfo()
|
|||
void sync::search::set_agc_enable(bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
srslte_rf_info_t* rf_info = p->radio_h->get_info(0);
|
||||
srslte_rf_info_t* rf_info = p->radio_h->get_info();
|
||||
srslte_ue_sync_start_agc(&ue_mib_sync.ue_sync,
|
||||
callback_set_rx_gain,
|
||||
rf_info->min_rx_gain,
|
||||
rf_info->max_rx_gain,
|
||||
p->radio_h->get_rx_gain(0));
|
||||
p->radio_h->get_rx_gain());
|
||||
} else {
|
||||
ERROR("Error stop AGC not implemented\n");
|
||||
}
|
||||
|
@ -1154,22 +1087,21 @@ sync::sfn_sync::~sfn_sync()
|
|||
srslte_ue_mib_free(&ue_mib);
|
||||
}
|
||||
|
||||
void sync::sfn_sync::init(srslte_ue_sync_t* ue_sync_,
|
||||
cf_t* buffer_[SRSLTE_MAX_PORTS],
|
||||
uint32_t buffer_max_samples_,
|
||||
srslte::log* log_h_,
|
||||
uint32_t nof_subframes)
|
||||
void sync::sfn_sync::init(srslte_ue_sync_t* ue_sync_,
|
||||
srslte::rf_buffer_t& buffer,
|
||||
uint32_t buffer_max_samples_,
|
||||
srslte::log* log_h_,
|
||||
uint32_t nof_subframes)
|
||||
{
|
||||
log_h = log_h_;
|
||||
ue_sync = ue_sync_;
|
||||
timeout = nof_subframes;
|
||||
|
||||
for (int p = 0; p < SRSLTE_MAX_PORTS; p++) {
|
||||
buffer[p] = buffer_[p];
|
||||
}
|
||||
mib_buffer = buffer;
|
||||
buffer_max_samples = buffer_max_samples_;
|
||||
|
||||
if (srslte_ue_mib_init(&ue_mib, buffer, SRSLTE_MAX_PRB)) {
|
||||
// MIB decoder uses a single receiver antenna in logical channel 0
|
||||
if (srslte_ue_mib_init(&ue_mib, buffer.get(0), SRSLTE_MAX_PRB)) {
|
||||
Error("SYNC: Initiating UE MIB decoder\n");
|
||||
}
|
||||
}
|
||||
|
@ -1195,14 +1127,14 @@ sync::sfn_sync::ret_code sync::sfn_sync::run_subframe(srslte_cell_t*
|
|||
std::array<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;
|
||||
}
|
||||
|
@ -1219,15 +1151,15 @@ sync::sfn_sync::ret_code sync::sfn_sync::run_subframe(srslte_cell_t*
|
|||
return IDLE;
|
||||
}
|
||||
|
||||
sync::sfn_sync::ret_code sync::sfn_sync::decode_mib(srslte_cell_t* cell_,
|
||||
uint32_t* tti_cnt,
|
||||
cf_t* ext_buffer[SRSLTE_MAX_PORTS],
|
||||
sync::sfn_sync::ret_code sync::sfn_sync::decode_mib(srslte_cell_t* cell_,
|
||||
uint32_t* tti_cnt,
|
||||
srslte::rf_buffer_t* ext_buffer,
|
||||
std::array<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…
Reference in New Issue