Initial UE NR SA PHY classes

This commit is contained in:
Xavier Arteaga 2021-08-31 15:11:39 +02:00 committed by Ismael Gomez
parent cfa614226e
commit b1bcc1a8c0
14 changed files with 909 additions and 6 deletions

View File

@ -31,6 +31,26 @@ public:
virtual void set_phy_config_complete(bool status) = 0;
};
class rrc_interface_phy_sa_nr
{
public:
/**
* @brief Describes a cell search result
*/
struct cell_search_result_t {
uint32_t pci = 0; ///< Physical Cell Identifier
bool barred = false; ///< Set to true if the cell is barred
bool intra_freq_meas = false; ///< Set to true if intra frequency measurement is enabled
srsran_csi_trs_measurements_t measurements = {}; ///< Measurements from SSB block
};
/**
* @brief Informs RRC about cell search process completion
* @param result Cell search result completion
*/
virtual void cell_search_found_cell(const cell_search_result_t& result) = 0;
};
class mac_interface_phy_nr
{
public:
@ -249,16 +269,80 @@ public:
virtual bool set_config(const srsran::phy_cfg_nr_t& cfg) = 0;
};
class phy_interface_rrc_sa_nr
{
public:
/**
* @brief Describe the possible NR standalone physical layer possible states
*/
typedef enum {
PHY_NR_SA_STATE_IDLE = 0, ///< There is no process going on
PHY_NR_SA_STATE_CELL_SEARCH, ///< Cell search is currently in progress
PHY_NR_SA_STATE_CELL_SELECT, ///< Cell selection is in progress or it is camped on a cell
} phy_nr_sa_state_t;
/**
* @brief Retrieves the physical layer state
* @return
*/
virtual phy_nr_sa_state_t get_state() const = 0;
/**
* @brief Stops the ongoing process and transitions to IDLE
*/
virtual void reset() = 0;
/**
* @brief Describes cell search arguments
*/
struct cell_search_args_t {
// TBD
};
/**
* @brief Start cell search
* @param args Cell Search arguments
* @return true if the physical layer started successfully the cell search process
*/
virtual bool start_cell_search(const cell_search_args_t& req) = 0;
/**
* @brief Describes cell select arguments
*/
struct cell_select_args_t {
srsran::phy_cfg_nr_t phy_cfg; ///< Serving cell configuration
};
/**
* @brief Start cell search
* @param args Cell Search arguments
* @return true if the physical layer started successfully the cell search process
*/
virtual bool start_cell_select(const cell_search_args_t& req) = 0;
};
// Combined interface for PHY to access stack (MAC and RRC)
class stack_interface_phy_nr : public mac_interface_phy_nr,
public rrc_interface_phy_nr,
public srsran::stack_interface_phy_nr
{};
/**
* @brief Combines the stack interfaces for PHY to access stack (MAC and RRC) including the standalone interface
*/
class stack_interface_phy_sa_nr : public stack_interface_phy_nr, public rrc_interface_phy_sa_nr
{};
// Combined interface for stack (MAC and RRC) to access PHY
class phy_interface_stack_nr : public phy_interface_mac_nr, public phy_interface_rrc_nr
{};
/**
* @brief Combines the PHY interfaces for stack (MAC and RRC) to access PHY for NSA including the standalone interfaces
*/
class phy_interface_stack_sa_nr : public phy_interface_stack_nr, public phy_interface_rrc_sa_nr
{};
} // namespace srsue
#endif // SRSRAN_UE_NR_INTERFACES_H

View File

@ -116,9 +116,10 @@ typedef struct SRSRAN_API {
* @note if pbch.crc is true, SSB transmission is found and decoded. Otherwise, no SSB transmission has been decoded
*/
typedef struct {
uint32_t N_id; ///< Most suitable physical cell identifier
uint32_t t_offset; ///< Time offset in the input samples
srsran_pbch_msg_nr_t pbch_msg; ///< Physical broadcast channel message of the most suitable SSB candidate
uint32_t N_id; ///< Most suitable physical cell identifier
uint32_t t_offset; ///< Time offset in the input samples
srsran_pbch_msg_nr_t pbch_msg; ///< Physical broadcast channel message of the most suitable SSB candidate
srsran_csi_trs_measurements_t measurements; ///< Measurements
} srsran_ssb_search_res_t;
/**

View File

@ -113,6 +113,7 @@ extern "C" {
#include "srsran/phy/ue/ue_dl_nr.h"
#include "srsran/phy/ue/ue_mib.h"
#include "srsran/phy/ue/ue_sync.h"
#include "srsran/phy/ue/ue_sync_nr.h"
#include "srsran/phy/ue/ue_ul.h"
#include "srsran/phy/ue/ue_ul_nr.h"

View File

@ -1121,10 +1121,17 @@ int srsran_ssb_search(srsran_ssb_t* q, const cf_t* in, uint32_t nof_samples, srs
return SRSRAN_ERROR;
}
srsran_csi_trs_measurements_t measurements = {};
if (ssb_measure(q, ssb_grid, N_id, &measurements) < SRSRAN_SUCCESS) {
ERROR("Error measuring");
return SRSRAN_ERROR;
}
// Save result
res->N_id = N_id;
res->t_offset = t_offset;
res->pbch_msg = pbch_msg;
res->N_id = N_id;
res->t_offset = t_offset;
res->pbch_msg = pbch_msg;
res->measurements = measurements;
return SRSRAN_SUCCESS;
}

View File

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

View File

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

117
srsue/hdr/phy/nr/sync_sa.h Normal file
View File

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

68
srsue/hdr/phy/phy_nr_sa.h Normal file
View File

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

View File

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

View File

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

View File

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

149
srsue/src/phy/sync_sa.cc Normal file
View File

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

View File

@ -65,6 +65,15 @@ add_nr_test(nr_cell_search_test_delay nr_cell_search_test --duration=1 --ssb_per
add_executable(nr_cell_search_rf nr_cell_search_rf.cc)
target_link_libraries(nr_cell_search_rf
srsue_phy
srsran_common
srsran_phy
srsran_radio
${CMAKE_THREAD_LIBS_INIT}
${Boost_LIBRARIES})
add_executable(nr_sa_cell_search_test nr_sa_cell_search_test.cc)
target_link_libraries(nr_sa_cell_search_test
srsue_phy
srsran_common
srsran_phy

View File

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