mirror of https://github.com/pvnis/srsRAN_4G.git
Initial UE NR SA PHY classes
parent
cfa614226e
commit
b1bcc1a8c0
@ -0,0 +1,62 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSUE_CELL_SEARCH_H
|
||||
#define SRSUE_CELL_SEARCH_H
|
||||
|
||||
#include "srsran/interfaces/radio_interfaces.h"
|
||||
#include "srsran/interfaces/ue_nr_interfaces.h"
|
||||
#include "srsran/srsran.h"
|
||||
|
||||
namespace srsue {
|
||||
namespace nr {
|
||||
class cell_search
|
||||
{
|
||||
public:
|
||||
struct args_t {
|
||||
double max_srate_hz;
|
||||
srsran_subcarrier_spacing_t ssb_min_scs = srsran_subcarrier_spacing_15kHz;
|
||||
};
|
||||
|
||||
struct cfg_t {
|
||||
double srate_hz;
|
||||
double center_freq_hz;
|
||||
double ssb_freq_hz;
|
||||
srsran_subcarrier_spacing_t ssb_scs;
|
||||
srsran_ssb_patern_t ssb_pattern;
|
||||
srsran_duplex_mode_t duplex_mode;
|
||||
};
|
||||
|
||||
cell_search(stack_interface_phy_sa_nr& stack_, srsran::radio_interface_phy& radio_);
|
||||
|
||||
~cell_search();
|
||||
|
||||
bool init(const args_t& args);
|
||||
|
||||
bool start(const cfg_t& cfg);
|
||||
|
||||
bool run();
|
||||
|
||||
void reset();
|
||||
|
||||
private:
|
||||
srslog::basic_logger& logger;
|
||||
stack_interface_phy_sa_nr& stack;
|
||||
srsran::radio_interface_phy& radio;
|
||||
srsran_ssb_t ssb = {};
|
||||
uint32_t sf_sz = 0; ///< subframe size in samples (1 ms)
|
||||
cf_t* buffer = nullptr; ///< Receive buffer
|
||||
};
|
||||
} // namespace nr
|
||||
} // namespace srsue
|
||||
|
||||
#endif // SRSUE_CELL_SEARCH_H
|
@ -0,0 +1,62 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSUE_SLOT_SYNC_H
|
||||
#define SRSUE_SLOT_SYNC_H
|
||||
|
||||
#include "srsran/interfaces/radio_interfaces.h"
|
||||
#include "srsran/interfaces/ue_nr_interfaces.h"
|
||||
#include "srsran/radio/rf_buffer.h"
|
||||
#include "srsran/radio/rf_timestamp.h"
|
||||
#include "srsran/srsran.h"
|
||||
|
||||
namespace srsue {
|
||||
namespace nr {
|
||||
class slot_sync
|
||||
{
|
||||
public:
|
||||
struct args_t {
|
||||
double max_srate_hz = 1.92e6;
|
||||
uint32_t nof_rx_channels = 1;
|
||||
srsran_subcarrier_spacing_t ssb_min_scs = srsran_subcarrier_spacing_15kHz;
|
||||
bool disable_cfo = false;
|
||||
float pbch_dmrs_thr = 0.0f; ///< PBCH DMRS correlation detection threshold (0 means auto)
|
||||
float cfo_alpha = 0.0f; ///< CFO averaging alpha (0 means auto)
|
||||
int thread_priority = -1;
|
||||
};
|
||||
|
||||
slot_sync(stack_interface_phy_sa_nr& stack_, srsran::radio_interface_phy& radio_);
|
||||
~slot_sync();
|
||||
|
||||
bool init(const args_t& args);
|
||||
|
||||
int recv_callback(srsran::rf_buffer_t& rf_buffer, srsran_timestamp_t* timestamp);
|
||||
void run_stack_tti();
|
||||
|
||||
private:
|
||||
const static int MIN_TTI_JUMP = 1; ///< Time gap reported to stack after receiving subframe
|
||||
const static int MAX_TTI_JUMP = 1000; ///< Maximum time gap tolerance in RF stream metadata
|
||||
enum { SEARCHING = 0, CAMPING } state = SEARCHING;
|
||||
srslog::basic_logger& logger;
|
||||
stack_interface_phy_sa_nr& stack;
|
||||
srsran::radio_interface_phy& radio;
|
||||
srsran_ue_sync_nr_t ue_sync_nr = {};
|
||||
srsran::rf_timestamp_t last_rx_time;
|
||||
srsran_timestamp_t stack_tti_ts_new = {};
|
||||
srsran_timestamp_t stack_tti_ts = {};
|
||||
bool forced_rx_time_init = true; // Rx time sync after first receive from radio
|
||||
uint32_t tti = 0;
|
||||
};
|
||||
} // namespace nr
|
||||
} // namespace srsue
|
||||
|
||||
#endif // SRSUE_SLOT_SYNC_H
|
@ -0,0 +1,117 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSUE_SYNC_NR_SA_H
|
||||
#define SRSUE_SYNC_NR_SA_H
|
||||
|
||||
#include "cell_search.h"
|
||||
#include "slot_sync.h"
|
||||
#include "srsran/common/threads.h"
|
||||
#include "srsran/interfaces/radio_interfaces.h"
|
||||
#include "srsran/interfaces/ue_nr_interfaces.h"
|
||||
#include "srsran/radio/rf_buffer.h"
|
||||
#include "srsran/radio/rf_timestamp.h"
|
||||
#include "srsran/srslog/logger.h"
|
||||
#include "srsran/srsran.h"
|
||||
#include "worker_pool.h"
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <srsran/common/tti_sempahore.h>
|
||||
|
||||
namespace srsue {
|
||||
namespace nr {
|
||||
|
||||
/**
|
||||
* @brief NR Standalone synchronization class
|
||||
*/
|
||||
class sync_sa : public srsran::thread, public srsran::phy_common_interface
|
||||
{
|
||||
public:
|
||||
struct args_t {
|
||||
double srate_hz = 61.44e6;
|
||||
srsran_subcarrier_spacing_t ssb_min_scs = srsran_subcarrier_spacing_15kHz;
|
||||
uint32_t nof_rx_channels = 1;
|
||||
bool disable_cfo = false;
|
||||
float pbch_dmrs_thr = 0.0f; ///< PBCH DMRS correlation detection threshold (0 means auto)
|
||||
float cfo_alpha = 0.0f; ///< CFO averaging alpha (0 means auto)
|
||||
int thread_priority = -1;
|
||||
|
||||
cell_search::args_t get_cell_search() const
|
||||
{
|
||||
cell_search::args_t ret = {};
|
||||
ret.max_srate_hz = srate_hz;
|
||||
return ret;
|
||||
}
|
||||
|
||||
slot_sync::args_t get_slot_sync() const
|
||||
{
|
||||
slot_sync::args_t ret = {};
|
||||
ret.max_srate_hz = srate_hz;
|
||||
ret.nof_rx_channels = nof_rx_channels;
|
||||
ret.ssb_min_scs = ssb_min_scs;
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
STATE_IDLE = 0, ///< No process is in progress
|
||||
STATE_CELL_SEARCH,
|
||||
STATE_CELL_SELECT
|
||||
} state_t;
|
||||
|
||||
sync_sa(stack_interface_phy_sa_nr& stack_, srsran::radio_interface_phy& radio_, worker_pool& workers_);
|
||||
~sync_sa();
|
||||
|
||||
bool init(const args_t& args_);
|
||||
|
||||
// The following methods control the SYNC state machine
|
||||
bool start_cell_search(const cell_search::cfg_t& cfg);
|
||||
bool start_cell_select();
|
||||
bool go_idle();
|
||||
|
||||
void stop();
|
||||
|
||||
void worker_end(const worker_context_t& w_ctx, const bool& tx_enable, srsran::rf_buffer_t& buffer) override;
|
||||
|
||||
private:
|
||||
stack_interface_phy_sa_nr& stack; ///< Stand-Alone RRC interface
|
||||
srsran::radio_interface_phy& radio; ///< Radio object
|
||||
srslog::basic_logger& logger; ///< General PHY logger
|
||||
worker_pool& workers;
|
||||
|
||||
state_t state = STATE_IDLE;
|
||||
state_t next_state = STATE_IDLE;
|
||||
std::mutex state_mutex;
|
||||
std::condition_variable state_cvar;
|
||||
std::atomic<bool> running = {false};
|
||||
uint32_t sf_sz = 0; ///< Subframe size (1-ms)
|
||||
srsran::tti_semaphore<void*> tti_semaphore;
|
||||
|
||||
cell_search searcher;
|
||||
slot_sync slot_synchronizer;
|
||||
|
||||
// FSM States
|
||||
void run_state_idle();
|
||||
void run_state_cell_search();
|
||||
void run_state_cell_select();
|
||||
|
||||
// FSM transitions
|
||||
void enter_state_idle();
|
||||
|
||||
void run_thread() override;
|
||||
};
|
||||
|
||||
} // namespace nr
|
||||
} // namespace srsue
|
||||
|
||||
#endif // SRSUE_SYNC_NR_SA_H
|
@ -0,0 +1,68 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSUE_PHY_NR_SA_H
|
||||
#define SRSUE_PHY_NR_SA_H
|
||||
|
||||
#include "srsran/interfaces/ue_nr_interfaces.h"
|
||||
#include "srsue/hdr/phy/nr/sync_sa.h"
|
||||
|
||||
namespace srsue {
|
||||
|
||||
/**
|
||||
* @brief NR Standalone PHY
|
||||
*/
|
||||
class phy_nr_sa : public phy_interface_stack_sa_nr
|
||||
{
|
||||
public:
|
||||
struct args_t {
|
||||
std::string log_level = "info"; ///< General PHY logging level
|
||||
double srate_hz = 61.44e6; ///< Sampling rate in Hz
|
||||
|
||||
// Frequency allocation parameters
|
||||
uint32_t pointA_arfcn = 0; ///< Resource grid PointA ARFCN
|
||||
float pointA_Hz = 0; ///< Resource grid PointA frequency in Hz. Overrides pointA_arfcn if valid
|
||||
uint32_t ssb_arfcn = 0; ///< SS/PBCH block center point ARFCN
|
||||
float ssb_Hz = 0; ///< SS/PBCH block center point ARFCN. Overrides ssb_arfcn if valid
|
||||
};
|
||||
|
||||
phy_nr_sa(stack_interface_phy_sa_nr& stack_, srsran::radio_interface_phy& radio_);
|
||||
|
||||
bool init(const args_t& args);
|
||||
|
||||
int set_ul_grant(std::array<uint8_t, 27> packed_ul_grant, uint16_t rnti, srsran_rnti_type_t rnti_type) override
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int tx_request(const tx_request_t& request) override { return 0; }
|
||||
void send_prach(const uint32_t prach_occasion,
|
||||
const int preamble_index,
|
||||
const float preamble_received_target_power,
|
||||
const float ta_base_sec) override
|
||||
{}
|
||||
bool has_valid_sr_resource(uint32_t sr_id) override { return false; }
|
||||
void clear_pending_grants() override {}
|
||||
bool set_config(const srsran::phy_cfg_nr_t& cfg) override { return false; }
|
||||
|
||||
phy_nr_sa_state_t get_state() const override { return PHY_NR_SA_STATE_CELL_SELECT; }
|
||||
void reset() override {}
|
||||
bool start_cell_search(const cell_search_args_t& req) override { return false; }
|
||||
bool start_cell_select(const cell_search_args_t& req) override { return false; }
|
||||
|
||||
private:
|
||||
nr::worker_pool workers;
|
||||
nr::sync_sa sync;
|
||||
srslog::basic_logger& logger;
|
||||
};
|
||||
|
||||
} // namespace srsue
|
||||
#endif // SRSUE_PHY_NR_SA_H
|
@ -0,0 +1,126 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "srsue/hdr/phy/nr/cell_search.h"
|
||||
#include "srsran/common/band_helper.h"
|
||||
#include "srsran/common/buffer_pool.h"
|
||||
#include "srsran/radio/rf_buffer.h"
|
||||
#include "srsran/radio/rf_timestamp.h"
|
||||
|
||||
namespace srsue {
|
||||
namespace nr {
|
||||
cell_search::cell_search(stack_interface_phy_sa_nr& stack_, srsran::radio_interface_phy& radio_) :
|
||||
logger(srslog::fetch_basic_logger("PHY")),
|
||||
stack(stack_),
|
||||
radio(radio_)
|
||||
{}
|
||||
|
||||
cell_search::~cell_search()
|
||||
{
|
||||
srsran_ssb_free(&ssb);
|
||||
if (buffer != nullptr) {
|
||||
free(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
bool cell_search::init(const args_t& args)
|
||||
{
|
||||
// Compute subframe size
|
||||
sf_sz = (uint32_t)(args.max_srate_hz / 1000.0f);
|
||||
|
||||
// Allocate receive buffer
|
||||
buffer = srsran_vec_cf_malloc(2 * sf_sz);
|
||||
if (buffer == nullptr) {
|
||||
logger.error("Error allocating buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prepare SSB initialization arguments
|
||||
srsran_ssb_args_t ssb_args = {};
|
||||
ssb_args.max_srate_hz = args.max_srate_hz;
|
||||
ssb_args.min_scs = args.ssb_min_scs;
|
||||
ssb_args.enable_search = true;
|
||||
ssb_args.enable_decode = true;
|
||||
|
||||
// Initialise SSB
|
||||
if (srsran_ssb_init(&ssb, &ssb_args) < SRSRAN_SUCCESS) {
|
||||
logger.error("Cell search: Error initiating SSB");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cell_search::start(const cfg_t& cfg)
|
||||
{
|
||||
// Prepare SSB configuration
|
||||
srsran_ssb_cfg_t ssb_cfg = {};
|
||||
ssb_cfg.srate_hz = cfg.srate_hz;
|
||||
ssb_cfg.center_freq_hz = cfg.center_freq_hz;
|
||||
ssb_cfg.ssb_freq_hz = cfg.ssb_freq_hz;
|
||||
ssb_cfg.scs = cfg.ssb_scs;
|
||||
ssb_cfg.pattern = cfg.ssb_pattern;
|
||||
ssb_cfg.duplex_mode = cfg.duplex_mode;
|
||||
|
||||
// Configure SSB
|
||||
if (srsran_ssb_set_cfg(&ssb, &ssb_cfg) < SRSRAN_SUCCESS) {
|
||||
logger.error("Cell search: Error setting SSB configuration");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set RX frequency
|
||||
radio.set_rx_freq(0, cfg.center_freq_hz);
|
||||
|
||||
// Zero receive buffer
|
||||
srsran_vec_zero(buffer, sf_sz);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cell_search::run()
|
||||
{
|
||||
// Setup RF buffer for 1ms worth of samples
|
||||
srsran::rf_buffer_t rf_buffer = {};
|
||||
rf_buffer.set_nof_samples(sf_sz);
|
||||
rf_buffer.set(0, buffer + ssb.ssb_sz);
|
||||
|
||||
// Receive
|
||||
srsran::rf_timestamp_t rf_timestamp = {};
|
||||
if (not radio.rx_now(rf_buffer, rf_timestamp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Search for SSB
|
||||
srsran_ssb_search_res_t res = {};
|
||||
if (srsran_ssb_search(&ssb, buffer, sf_sz + ssb.ssb_sz, &res) < SRSRAN_SUCCESS) {
|
||||
logger.error("Error occurred searching SSB");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Consider the SSB is found and decoded if the PBCH CRC matched
|
||||
if (res.pbch_msg.crc) {
|
||||
rrc_interface_phy_sa_nr::cell_search_result_t cs_res = {};
|
||||
cs_res.pci = res.N_id;
|
||||
cs_res.barred = false;
|
||||
cs_res.intra_freq_meas = false;
|
||||
cs_res.measurements = res.measurements;
|
||||
stack.cell_search_found_cell(cs_res);
|
||||
}
|
||||
|
||||
// Advance stack TTI
|
||||
stack.run_tti(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace nr
|
||||
} // namespace srsue
|
@ -0,0 +1,132 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "srsue/hdr/phy/nr/slot_sync.h"
|
||||
|
||||
namespace srsue {
|
||||
namespace nr {
|
||||
|
||||
slot_sync::slot_sync(stack_interface_phy_sa_nr& stack_, srsran::radio_interface_phy& radio_) :
|
||||
logger(srslog::fetch_basic_logger("PHY")),
|
||||
stack(stack_),
|
||||
radio(radio_)
|
||||
{}
|
||||
|
||||
slot_sync::~slot_sync()
|
||||
{
|
||||
srsran_ue_sync_nr_free(&ue_sync_nr);
|
||||
}
|
||||
|
||||
int sync_sa_recv_callback(void* ptr, cf_t** buffer, uint32_t nsamples, srsran_timestamp_t* ts)
|
||||
{
|
||||
if (ptr == nullptr) {
|
||||
return SRSRAN_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
slot_sync* sync = (slot_sync*)ptr;
|
||||
srsran::rf_buffer_t rf_buffer(buffer, nsamples);
|
||||
|
||||
return sync->recv_callback(rf_buffer, ts);
|
||||
}
|
||||
|
||||
bool slot_sync::init(const args_t& args)
|
||||
{
|
||||
srsran_ue_sync_nr_args_t ue_sync_nr_args = {};
|
||||
ue_sync_nr_args.max_srate_hz = args.max_srate_hz;
|
||||
ue_sync_nr_args.min_scs = args.ssb_min_scs;
|
||||
ue_sync_nr_args.nof_rx_channels = args.nof_rx_channels;
|
||||
ue_sync_nr_args.disable_cfo = args.disable_cfo;
|
||||
ue_sync_nr_args.pbch_dmrs_thr = args.pbch_dmrs_thr;
|
||||
ue_sync_nr_args.cfo_alpha = args.cfo_alpha;
|
||||
|
||||
if (srsran_ue_sync_nr_init(&ue_sync_nr, &ue_sync_nr_args) < SRSRAN_SUCCESS) {
|
||||
logger.error("Error initiating UE SYNC NR object");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int slot_sync::recv_callback(srsran::rf_buffer_t& data, srsran_timestamp_t* rx_time)
|
||||
{
|
||||
// This function is designed for being called from the UE sync object which will pass a null rx_time in case
|
||||
// receive dummy samples. So, rf_timestamp points at dummy timestamp in case rx_time is not provided
|
||||
srsran::rf_timestamp_t dummy_ts = {};
|
||||
srsran::rf_timestamp_t& rf_timestamp = (rx_time == nullptr) ? dummy_ts : last_rx_time;
|
||||
|
||||
// Receive
|
||||
if (not radio.rx_now(data, rf_timestamp)) {
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
srsran_timestamp_t dummy_flat_ts = {};
|
||||
|
||||
// Load flat timestamp
|
||||
if (rx_time == nullptr) {
|
||||
rx_time = &dummy_flat_ts;
|
||||
}
|
||||
*rx_time = rf_timestamp.get(0);
|
||||
|
||||
// Save RF timestamp for the stack
|
||||
stack_tti_ts_new = rf_timestamp.get(0);
|
||||
|
||||
// Run stack if the sync state is not in camping
|
||||
if (state == SEARCHING) {
|
||||
logger.debug("run_stack_tti: from recv");
|
||||
run_stack_tti();
|
||||
}
|
||||
|
||||
logger.debug("SYNC: received %d samples from radio", data.get_nof_samples());
|
||||
|
||||
return data.get_nof_samples();
|
||||
}
|
||||
|
||||
void slot_sync::run_stack_tti()
|
||||
{ // check timestamp reset
|
||||
if (forced_rx_time_init || srsran_timestamp_iszero(&stack_tti_ts) ||
|
||||
srsran_timestamp_compare(&stack_tti_ts_new, &stack_tti_ts) < 0) {
|
||||
if (srsran_timestamp_compare(&stack_tti_ts_new, &stack_tti_ts) < 0) {
|
||||
logger.warning("SYNC: radio time seems to be going backwards (rx_time=%f, tti_ts=%f)",
|
||||
srsran_timestamp_real(&stack_tti_ts_new),
|
||||
srsran_timestamp_real(&stack_tti_ts));
|
||||
// time-stamp will be set to rx time below and run_tti() will be called with MIN_TTI_JUMP
|
||||
}
|
||||
|
||||
// init tti_ts with last rx time
|
||||
logger.debug("SYNC: Setting initial TTI time to %f", srsran_timestamp_real(&stack_tti_ts_new));
|
||||
srsran_timestamp_copy(&stack_tti_ts, &stack_tti_ts_new);
|
||||
forced_rx_time_init = false;
|
||||
}
|
||||
|
||||
// Advance stack in time
|
||||
if (srsran_timestamp_compare(&stack_tti_ts_new, &stack_tti_ts) >= 0) {
|
||||
srsran_timestamp_t temp = {};
|
||||
srsran_timestamp_copy(&temp, &stack_tti_ts_new);
|
||||
srsran_timestamp_sub(&temp, stack_tti_ts.full_secs, stack_tti_ts.frac_secs);
|
||||
int32_t tti_jump = static_cast<int32_t>(srsran_timestamp_uint64(&temp, 1e3));
|
||||
tti_jump = SRSRAN_MAX(tti_jump, MIN_TTI_JUMP);
|
||||
if (tti_jump > MAX_TTI_JUMP) {
|
||||
logger.warning("SYNC: TTI jump of %d limited to %d", tti_jump, int(MAX_TTI_JUMP));
|
||||
tti_jump = SRSRAN_MIN(tti_jump, MAX_TTI_JUMP);
|
||||
}
|
||||
|
||||
// Run stack
|
||||
logger.debug("run_stack_tti: calling stack tti=%d, tti_jump=%d", tti, tti_jump);
|
||||
stack.run_tti(tti);
|
||||
logger.debug("run_stack_tti: stack called");
|
||||
}
|
||||
|
||||
// update timestamp
|
||||
srsran_timestamp_copy(&stack_tti_ts, &stack_tti_ts_new);
|
||||
}
|
||||
|
||||
} // namespace nr
|
||||
} // namespace srsue
|
@ -0,0 +1,34 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
#include "srsue/hdr/phy/phy_nr_sa.h"
|
||||
|
||||
namespace srsue {
|
||||
|
||||
phy_nr_sa::phy_nr_sa(stack_interface_phy_sa_nr& stack_, srsran::radio_interface_phy& radio_) :
|
||||
logger(srslog::fetch_basic_logger("PHY-NR")),
|
||||
sync(stack_, radio_, workers),
|
||||
workers(4)
|
||||
{}
|
||||
|
||||
bool phy_nr_sa::init(const args_t& args)
|
||||
{
|
||||
nr::sync_sa::args_t sync_args = {};
|
||||
sync_args.srate_hz = args.srate_hz;
|
||||
if (not sync.init(sync_args)) {
|
||||
logger.error("Error initialising SYNC");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace srsue
|
@ -0,0 +1,149 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
#include "srsue/hdr/phy/nr/sync_sa.h"
|
||||
#include "srsran/radio/rf_buffer.h"
|
||||
|
||||
namespace srsue {
|
||||
namespace nr {
|
||||
sync_sa::sync_sa(stack_interface_phy_sa_nr& stack_, srsran::radio_interface_phy& radio_, worker_pool& workers_) :
|
||||
logger(srslog::fetch_basic_logger("PHY-NR")),
|
||||
stack(stack_),
|
||||
radio(radio_),
|
||||
workers(workers_),
|
||||
srsran::thread("SYNC"),
|
||||
searcher(stack_, radio_),
|
||||
slot_synchronizer(stack_, radio_)
|
||||
{}
|
||||
|
||||
sync_sa::~sync_sa() {}
|
||||
|
||||
bool sync_sa::init(const args_t& args)
|
||||
{
|
||||
sf_sz = (uint32_t)(args.srate_hz / 1000.0f);
|
||||
|
||||
// Initialise cell search internal object
|
||||
if (not searcher.init(args.get_cell_search())) {
|
||||
logger.error("Error initialising cell searcher");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialise slot synchronizer object
|
||||
if (not slot_synchronizer.init(args.get_slot_sync())) {
|
||||
logger.error("Error initialising slot synchronizer");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Thread control
|
||||
running = true;
|
||||
start(args.thread_priority);
|
||||
|
||||
// If reached here it was successful
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sync_sa::start_cell_search(const cell_search::cfg_t& cfg)
|
||||
{
|
||||
// Make sure current state is IDLE
|
||||
std::unique_lock<std::mutex> lock(state_mutex);
|
||||
if (state != STATE_IDLE or next_state != STATE_IDLE) {
|
||||
logger.error("Sync: trying to start cell search but state is not IDLE");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Configure searcher without locking state
|
||||
lock.unlock();
|
||||
if (not searcher.start(cfg)) {
|
||||
logger.error("Sync: failed to start cell search");
|
||||
return false;
|
||||
}
|
||||
lock.lock();
|
||||
|
||||
// Transition to search
|
||||
next_state = STATE_CELL_SEARCH;
|
||||
|
||||
// Wait for state transition
|
||||
while (state != STATE_CELL_SEARCH) {
|
||||
state_cvar.wait(lock);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sync_sa::start_cell_select()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sync_sa::go_idle()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(state_mutex);
|
||||
|
||||
// Force transition to IDLE
|
||||
while (state != STATE_IDLE) {
|
||||
next_state = STATE_IDLE;
|
||||
state_cvar.wait(lock);
|
||||
}
|
||||
|
||||
// Wait worker pool to finish any processing
|
||||
tti_semaphore.wait_all();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void sync_sa::stop()
|
||||
{
|
||||
running = false;
|
||||
}
|
||||
|
||||
void sync_sa::run_state_idle()
|
||||
{
|
||||
srsran::rf_buffer_t rf_buffer = {};
|
||||
rf_buffer.set_nof_samples(sf_sz);
|
||||
|
||||
srsran::rf_timestamp_t ts = {};
|
||||
|
||||
radio.rx_now(rf_buffer, ts);
|
||||
}
|
||||
|
||||
void sync_sa::run_state_cell_search() {}
|
||||
|
||||
void sync_sa::run_thread()
|
||||
{
|
||||
while (running) {
|
||||
state_mutex.lock();
|
||||
// Detect state transition
|
||||
if (next_state != state) {
|
||||
state = next_state;
|
||||
state_cvar.notify_all();
|
||||
}
|
||||
state_t current_state = state;
|
||||
state_mutex.unlock();
|
||||
|
||||
switch (current_state) {
|
||||
case STATE_IDLE:
|
||||
run_state_idle();
|
||||
break;
|
||||
case STATE_CELL_SEARCH:
|
||||
run_state_cell_search();
|
||||
break;
|
||||
case STATE_CELL_SELECT:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void sync_sa::worker_end(const srsran::phy_common_interface::worker_context_t& w_ctx,
|
||||
const bool& tx_enable,
|
||||
srsran::rf_buffer_t& buffer)
|
||||
{}
|
||||
|
||||
} // namespace nr
|
||||
} // namespace srsue
|
@ -0,0 +1,51 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "srsue/hdr/phy/phy_nr_sa.h"
|
||||
|
||||
struct test_args_t {};
|
||||
|
||||
class gnb_emulator : public srsran::radio_interface_phy
|
||||
{
|
||||
private:
|
||||
// srsran_ssb_t ssb = {};
|
||||
|
||||
public:
|
||||
struct args_t {
|
||||
double srate_hz;
|
||||
};
|
||||
gnb_emulator() {}
|
||||
void tx_end() override {}
|
||||
bool tx(srsran::rf_buffer_interface& buffer, const srsran::rf_timestamp_interface& tx_time) override { return false; }
|
||||
bool rx_now(srsran::rf_buffer_interface& buffer, srsran::rf_timestamp_interface& rxd_time) override { return false; }
|
||||
void set_tx_freq(const uint32_t& carrier_idx, const double& freq) override {}
|
||||
void set_rx_freq(const uint32_t& carrier_idx, const double& freq) override {}
|
||||
void release_freq(const uint32_t& carrier_idx) override {}
|
||||
void set_tx_gain(const float& gain) override {}
|
||||
void set_rx_gain_th(const float& gain) override {}
|
||||
void set_rx_gain(const float& gain) override {}
|
||||
void set_tx_srate(const double& srate) override {}
|
||||
void set_rx_srate(const double& srate) override {}
|
||||
void set_channel_rx_offset(uint32_t ch, int32_t offset_samples) override {}
|
||||
double get_freq_offset() override { return 0; }
|
||||
float get_rx_gain() override { return 0; }
|
||||
bool is_continuous_tx() override { return false; }
|
||||
bool get_is_start_of_burst() override { return false; }
|
||||
bool is_init() override { return false; }
|
||||
void reset() override {}
|
||||
srsran_rf_info_t* get_info() override { return nullptr; }
|
||||
};
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue