Completed basic sync module with bypass camping. Removed ue_phy_nr and ue_phy_lte base classes

master
Ismael Gomez 3 years ago
parent 6947f87bcb
commit c71ab70b83

@ -34,6 +34,7 @@ public:
* @brief Describes a cell search result
*/
struct cell_search_result_t {
bool cell_found = false;
uint32_t pci = 0; ///< Physical Cell Identifier
srsran_pbch_msg_nr_t pbch_msg; ///< Packed PBCH message for the upper layers
srsran_csi_trs_measurements_t measurements = {}; ///< Measurements from SSB block
@ -262,13 +263,14 @@ public:
PHY_NR_STATE_IDLE = 0, ///< There is no process going on
PHY_NR_STATE_CELL_SEARCH, ///< Cell search is currently in progress
PHY_NR_STATE_CELL_SELECT, ///< Cell selection is in progress or it is camped on a cell
PHY_NR_STATE_CAMPING
} phy_nr_state_t;
/**
* @brief Retrieves the physical layer state
* @return
*/
virtual phy_nr_state_t get_state() const = 0;
virtual phy_nr_state_t get_state() = 0;
/**
* @brief Stops the ongoing process and transitions to IDLE
@ -279,6 +281,7 @@ public:
* @brief Describes cell search arguments
*/
struct cell_search_args_t {
double srate_hz;
double center_freq_hz;
double ssb_freq_hz;
srsran_subcarrier_spacing_t ssb_scs;
@ -297,7 +300,8 @@ public:
* @brief Describes cell select arguments
*/
struct cell_select_args_t {
srsran::phy_cfg_nr_t phy_cfg; ///< Serving cell configuration
srsran_ssb_cfg_t ssb_cfg;
srsran_carrier_nr_t carrier;
};
/**
@ -305,7 +309,7 @@ public:
* @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;
virtual bool start_cell_select(const cell_select_args_t& req) = 0;
};
// Combined interface for PHY to access stack (MAC and RRC)

@ -36,24 +36,24 @@ public:
srsran_duplex_mode_t duplex_mode;
};
struct ret_t {
enum { CELL_FOUND = 1, CELL_NOT_FOUND = 0, ERROR = -1 } result;
srsran_ssb_search_res_t ssb_res;
};
cell_search(srslog::basic_logger& logger);
~cell_search();
bool init(const args_t& args, stack_interface_phy_nr* stack_, srsran::radio_interface_phy* radio_);
bool start(const cfg_t& cfg);
bool init(const args_t& args);
bool run();
bool start(const cfg_t& cfg);
ret_t run_slot(const cf_t* buffer, uint32_t slot_sz);
void reset();
private:
srslog::basic_logger& logger;
stack_interface_phy_nr* stack = nullptr;
srsran::radio_interface_phy* radio = nullptr;
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

@ -22,6 +22,7 @@
#include "srsran/radio/rf_timestamp.h"
#include "srsran/srslog/logger.h"
#include "srsran/srsran.h"
#include "srsue/hdr/phy/sync_state.h"
#include "worker_pool.h"
#include <condition_variable>
#include <mutex>
@ -63,25 +64,18 @@ public:
}
};
typedef enum {
STATE_IDLE = 0, ///< No process is in progress
STATE_CELL_SEARCH,
STATE_CELL_SELECT
} state_t;
sync_sa(srslog::basic_logger& logger, worker_pool& workers_);
~sync_sa();
bool init(const args_t& args_, stack_interface_phy_nr* stack_, srsran::radio_interface_phy* radio_);
// 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();
bool reset();
void stop();
sync_state::state_t get_state();
state_t get_state() const;
// The following methods control the SYNC state machine
void cell_go_idle();
cell_search::ret_t cell_search_run(const cell_search::cfg_t& cfg);
bool cell_select_run(const phy_interface_rrc_nr::cell_select_args_t& req);
void worker_end(const worker_context_t& w_ctx, const bool& tx_enable, srsran::rf_buffer_t& buffer) override;
@ -91,25 +85,31 @@ private:
srslog::basic_logger& logger; ///< General PHY logger
worker_pool& workers;
state_t state = STATE_IDLE;
state_t next_state = STATE_IDLE;
mutable std::mutex state_mutex;
std::condition_variable state_cvar;
std::atomic<bool> running = {false};
uint32_t sf_sz = 0; ///< Subframe size (1-ms)
// FSM that manages RRC commands for cell search/select/sync procedures
std::mutex rrc_mutex;
enum { PROC_IDLE = 0, PROC_SELECT_RUNNING, PROC_SEARCH_RUNNING } rrc_proc_state = PROC_IDLE;
sync_state phy_state;
std::atomic<bool> running = {false};
cf_t* rx_buffer = nullptr;
uint32_t slot_sz = 0; ///< Subframe size (1-ms)
uint32_t tti = 0;
srsran::tti_semaphore<void*> tti_semaphore;
srsran_slot_cfg_t slot_cfg = {};
srsran::rf_timestamp_t last_rx_time;
bool is_pending_tx_end = false;
uint32_t cell_search_nof_trials = 0;
const static uint32_t cell_search_max_trials = 100;
cell_search searcher;
slot_sync slot_synchronizer;
cell_search::ret_t cs_ret;
cell_search searcher;
slot_sync slot_synchronizer;
// FSM States
bool wait_idle();
void run_state_idle();
void run_state_cell_search();
void run_state_cell_select();
// FSM transitions
void enter_state_idle();
void run_state_cell_camping();
void run_thread() override;
};

@ -25,15 +25,18 @@
#include "srsran/srsran.h"
#include "srsue/hdr/phy/lte/worker_pool.h"
#include "srsue/hdr/phy/nr/worker_pool.h"
#include "srsue/hdr/phy/ue_lte_phy_base.h"
#include "srsue/hdr/phy/ue_nr_phy_base.h"
#include "srsue/hdr/phy/ue_phy_base.h"
#include "sync.h"
namespace srsue {
typedef _Complex float cf_t;
class phy final : public ue_lte_phy_base, public ue_nr_phy_base, public srsran::thread
class phy final : public ue_phy_base,
public phy_interface_stack_lte,
public phy_interface_stack_nr,
public srsran::phy_interface_radio,
public srsran::thread
{
public:
explicit phy() :
@ -50,7 +53,7 @@ public:
~phy() final { stop(); }
// Init for LTE PHYs
int init(const phy_args_t& args_, stack_interface_phy_lte* stack_, srsran::radio_interface_phy* radio_) final;
int init(const phy_args_t& args_, stack_interface_phy_lte* stack_, srsran::radio_interface_phy* radio_);
void stop() final;
@ -130,23 +133,23 @@ public:
std::string get_type() final { return "lte_soft"; }
/********** NR INTERFACE ********************/
int init(const phy_args_nr_t& args_, stack_interface_phy_nr* stack_, srsran::radio_interface_phy* radio_) final;
int init(const phy_args_nr_t& args_, stack_interface_phy_nr* stack_, srsran::radio_interface_phy* radio_);
bool set_config(const srsran::phy_cfg_nr_t& cfg) final;
void send_prach(const uint32_t prach_occasion,
const int preamble_index,
const float preamble_received_target_power,
const float ta_base_sec = 0.0f) final;
void set_earfcn(std::vector<uint32_t> earfcns) final;
void set_earfcn(std::vector<uint32_t> earfcns);
bool has_valid_sr_resource(uint32_t sr_id) final;
void clear_pending_grants() final;
int set_rar_grant(uint32_t rar_slot_idx,
std::array<uint8_t, SRSRAN_RAR_UL_GRANT_NBITS> packed_ul_grant,
uint16_t rnti,
srsran_rnti_type_t rnti_type) final;
phy_nr_state_t get_state() const override { return PHY_NR_STATE_IDLE; };
phy_nr_state_t get_state() override { return PHY_NR_STATE_IDLE; };
void reset_nr() 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; };
bool start_cell_select(const cell_select_args_t& req) override { return false; };
private:
void run_thread() final;

@ -16,19 +16,19 @@
#include "phy_common.h"
#include "srsran/interfaces/ue_nr_interfaces.h"
#include "srsue/hdr/phy/nr/sync_sa.h"
#include "srsue/hdr/phy/ue_nr_phy_base.h"
#include "srsue/hdr/phy/ue_phy_base.h"
namespace srsue {
/**
* @brief NR Standalone PHY
*/
class phy_nr_sa final : public ue_nr_phy_base
class phy_nr_sa final : public ue_phy_base, public phy_interface_stack_nr
{
public:
phy_nr_sa(const char* logname);
int init(const phy_args_nr_t& args_, stack_interface_phy_nr* stack_, srsran::radio_interface_phy* radio_) final;
int init(const phy_args_nr_t& args_, stack_interface_phy_nr* stack_, srsran::radio_interface_phy* radio_);
void wait_initialize() final;
bool is_initialized() final;
void stop() final;
@ -46,14 +46,14 @@ public:
const int preamble_index,
const float preamble_received_target_power,
const float ta_base_sec) final;
void set_earfcn(std::vector<uint32_t> earfcns) final{};
void set_earfcn(std::vector<uint32_t> earfcns);
bool has_valid_sr_resource(uint32_t sr_id) final;
void clear_pending_grants() final;
bool set_config(const srsran::phy_cfg_nr_t& cfg) final;
phy_nr_state_t get_state() const final;
phy_nr_state_t get_state() final;
bool start_cell_search(const cell_search_args_t& req) final;
bool start_cell_select(const cell_search_args_t& req) final { return false; }
bool start_cell_select(const cell_select_args_t& req) final;
void get_metrics(const srsran::srsran_rat_t& rat, phy_metrics_t* m) final{};
void srsran_phy_logger(phy_logger_level_t log_level, char* str);
@ -64,11 +64,11 @@ private:
nr::worker_pool workers;
phy_common common;
prach prach_buffer;
nr::sync_sa sync;
srsran::phy_cfg_nr_t config_nr = {};
phy_args_nr_t args = {};
srsran::phy_cfg_nr_t config_nr = {};
phy_args_nr_t args = {};
srsran_carrier_nr_t selected_cell = {};
srsran::radio_interface_phy* radio = nullptr;
stack_interface_phy_nr* stack = nullptr;

@ -13,6 +13,9 @@
#ifndef SRSUE_SYNC_STATE_H
#define SRSUE_SYNC_STATE_H
#include <condition_variable>
#include <mutex>
namespace srsue {
class sync_state
@ -58,6 +61,12 @@ public:
next_state = SFN_SYNC;
}
state_t get_state()
{
std::lock_guard<std::mutex> lock(mutex);
return cur_state;
}
/* Functions to be called from outside the STM thread to instruct the STM to switch state.
* The functions change the state and wait until it has changed it.
*

@ -1,46 +0,0 @@
/**
*
* \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.
*
*/
/******************************************************************************
* File: ue_lte_phy_base.h
* Description: Base class for UE LTE PHYs.
*****************************************************************************/
#ifndef SRSUE_UE_LTE_PHY_BASE_H
#define SRSUE_UE_LTE_PHY_BASE_H
#include "srsran/interfaces/radio_interfaces.h"
#include "srsue/hdr/phy/ue_phy_base.h"
namespace srsue {
class stack_interface_phy_lte;
class ue_lte_phy_base : public ue_phy_base, public phy_interface_stack_lte, public srsran::phy_interface_radio
{
public:
ue_lte_phy_base(){};
virtual ~ue_lte_phy_base(){};
virtual std::string get_type() = 0;
virtual int init(const phy_args_t& args_, stack_interface_phy_lte* stack_, srsran::radio_interface_phy* radio_) = 0;
virtual void stop() = 0;
virtual void start_plot() = 0;
virtual void get_metrics(const srsran::srsran_rat_t& rat, phy_metrics_t* m) = 0;
};
} // namespace srsue
#endif // SRSUE_UE_LTE_PHY_BASE_H

@ -1,45 +0,0 @@
/**
*
* \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.
*
*/
/******************************************************************************
* File: ue_nr_phy_base.h
* Description: Base class for UE NR PHYs.
*****************************************************************************/
#ifndef SRSUE_UE_NR_PHY_BASE_H
#define SRSUE_UE_NR_PHY_BASE_H
#include "srsran/interfaces/radio_interfaces.h"
#include "srsran/interfaces/ue_nr_interfaces.h"
#include "srsue/hdr/phy/ue_phy_base.h"
namespace srsue {
class ue_nr_phy_base : public ue_phy_base, public phy_interface_stack_nr
{
public:
ue_nr_phy_base(){};
virtual ~ue_nr_phy_base() {}
virtual std::string get_type() = 0;
virtual int init(const phy_args_nr_t& args_, stack_interface_phy_nr* stack_, srsran::radio_interface_phy* radio_) = 0;
virtual void stop() = 0;
virtual void set_earfcn(std::vector<uint32_t> earfcns) = 0;
virtual void get_metrics(const srsran::srsran_rat_t& rat, phy_metrics_t* m) = 0;
};
} // namespace srsue
#endif // SRSUE_UE_NR_PHY_BASE_H

@ -23,26 +23,10 @@ cell_search::cell_search(srslog::basic_logger& logger_) : logger(logger_) {}
cell_search::~cell_search()
{
srsran_ssb_free(&ssb);
if (buffer != nullptr) {
free(buffer);
}
}
bool cell_search::init(const args_t& args, stack_interface_phy_nr* stack_, srsran::radio_interface_phy* radio_)
bool cell_search::init(const args_t& args)
{
stack = stack_;
radio = radio_;
// 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;
@ -75,54 +59,24 @@ bool cell_search::start(const cfg_t& cfg)
logger.error("Cell search: Error setting SSB configuration");
return false;
}
logger.info("Cell search: starting in center frequency %.2f and SSB frequency %.2f with subcarrier spacing of %s",
cfg.center_freq_hz / 1e6,
cfg.ssb_freq_hz / 1e6,
srsran_subcarrier_spacing_to_str(cfg.ssb_scs));
// 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()
cell_search::ret_t cell_search::run_slot(const cf_t* buffer, uint32_t slot_sz)
{
// 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;
}
cell_search::ret_t ret = {};
// Search for SSB
srsran_ssb_search_res_t res = {};
if (srsran_ssb_search(&ssb, buffer, sf_sz + ssb.ssb_sz, &res) < SRSRAN_SUCCESS) {
if (srsran_ssb_search(&ssb, buffer, slot_sz + ssb.ssb_sz, &ret.ssb_res) < SRSRAN_SUCCESS) {
logger.error("Error occurred searching SSB");
return false;
ret.result = ret_t::ERROR;
} else if (ret.ssb_res.measurements.snr_dB >= -10.0f and ret.ssb_res.pbch_msg.crc) {
// Consider the SSB is found and decoded if the PBCH CRC matched
ret.result = ret_t::CELL_FOUND;
} else {
ret.result = ret_t::CELL_NOT_FOUND;
}
// Consider the SSB is found and decoded if the PBCH CRC matched
if (res.measurements.snr_dB >= -10.0f and res.pbch_msg.crc) {
rrc_interface_phy_nr::cell_search_result_t cs_res = {};
cs_res.pci = res.N_id;
cs_res.pbch_msg = res.pbch_msg;
cs_res.measurements = res.measurements;
stack->cell_search_found_cell(cs_res);
}
// Advance stack TTI
stack->run_tti(0);
return true;
return ret;
}
} // namespace nr

@ -11,7 +11,6 @@
*/
#include "srsue/hdr/phy/phy_nr_sa.h"
#include "srsran/common/band_helper.h"
#include "srsran/common/standard_streams.h"
#include "srsran/srsran.h"
@ -60,8 +59,7 @@ phy_nr_sa::phy_nr_sa(const char* logname) :
logger_phy_lib(srslog::fetch_basic_logger("PHY_LIB")),
sync(logger, workers),
workers(logger, 4),
common(logger),
prach_buffer(logger)
common(logger)
{}
int phy_nr_sa::init(const phy_args_nr_t& args_, stack_interface_phy_nr* stack_, srsran::radio_interface_phy* radio_)
@ -100,7 +98,6 @@ void phy_nr_sa::init_background()
logger.error("Error initialising SYNC");
return;
}
prach_buffer.init(SRSRAN_MAX_PRB);
workers.init(args, sync, stack, WORKERS_THREAD_PRIO);
is_configured = true;
@ -113,7 +110,6 @@ void phy_nr_sa::stop()
if (is_configured) {
sync.stop();
workers.stop();
prach_buffer.stop();
is_configured = false;
}
}
@ -128,16 +124,18 @@ void phy_nr_sa::wait_initialize()
init_thread.join();
}
phy_interface_rrc_nr::phy_nr_state_t phy_nr_sa::get_state() const
phy_interface_rrc_nr::phy_nr_state_t phy_nr_sa::get_state()
{
{
switch (sync.get_state()) {
case nr::sync_sa::STATE_IDLE:
break;
case nr::sync_sa::STATE_CELL_SEARCH:
case sync_state::state_t::IDLE:
return phy_interface_rrc_nr::PHY_NR_STATE_IDLE;
case sync_state::state_t::CELL_SEARCH:
return phy_interface_rrc_nr::PHY_NR_STATE_CELL_SEARCH;
case nr::sync_sa::STATE_CELL_SELECT:
case sync_state::state_t::SFN_SYNC:
return phy_interface_rrc_nr::PHY_NR_STATE_CELL_SELECT;
case sync_state::state_t::CAMPING:
return phy_interface_rrc_nr::PHY_NR_STATE_CAMPING;
}
}
return phy_interface_rrc_nr::PHY_NR_STATE_IDLE;
@ -145,22 +143,68 @@ phy_interface_rrc_nr::phy_nr_state_t phy_nr_sa::get_state() const
void phy_nr_sa::reset_nr()
{
sync.go_idle();
sync.reset();
}
// This function executes one part of the procedure immediately and returns to continue in the background.
// When it returns, the caller thread can expect the PHY to have switched to IDLE and have stopped all DL/UL/PRACH
// processing.
// It will perform cell search procedure in the background and will signal stack with function cell_search_found_cell()
// when finished
bool phy_nr_sa::start_cell_search(const cell_search_args_t& req)
{
// Prepare cell search configuration from the request
nr::cell_search::cfg_t cfg = {};
cfg.srate_hz = 0; // args.srate_hz;
cfg.center_freq_hz = req.center_freq_hz;
cfg.ssb_freq_hz = req.ssb_freq_hz;
cfg.ssb_scs = req.ssb_scs;
cfg.ssb_pattern = req.ssb_pattern;
cfg.duplex_mode = req.duplex_mode;
// TODO: verify arguments are valid before starting procedure
logger.info("Cell Search: Going to IDLE");
sync.cell_go_idle();
cmd_worker_cell.add_cmd([this, req]() {
// Prepare cell search configuration from the request
nr::cell_search::cfg_t cfg = {};
cfg.srate_hz = req.srate_hz;
cfg.center_freq_hz = req.center_freq_hz;
cfg.ssb_freq_hz = req.ssb_freq_hz;
cfg.ssb_scs = req.ssb_scs;
cfg.ssb_pattern = req.ssb_pattern;
cfg.duplex_mode = req.duplex_mode;
// Request cell search to lower synchronization instance.
nr::cell_search::ret_t ret = sync.cell_search_run(cfg);
// Pass result to stack
rrc_interface_phy_nr::cell_search_result_t rrc_cs_ret = {};
rrc_cs_ret.cell_found = ret.result == nr::cell_search::ret_t::CELL_FOUND;
if (rrc_cs_ret.cell_found) {
rrc_cs_ret.pci = ret.ssb_res.N_id;
rrc_cs_ret.pbch_msg = ret.ssb_res.pbch_msg;
rrc_cs_ret.measurements = ret.ssb_res.measurements;
}
stack->cell_search_found_cell(rrc_cs_ret);
});
// Request cell search to lower synchronization instance
return sync.start_cell_search(cfg);
return true;
}
// This function executes one part of the procedure immediately and returns to continue in the background.
// When it returns, the caller thread can expect the PHY to have switched to IDLE and have stopped all DL/UL/PRACH
// processing.
// It will perform cell search procedure in the background and will signal stack with function cell_search_found_cell()
// when finished
bool phy_nr_sa::start_cell_select(const cell_select_args_t& req)
{
// TODO: verify arguments are valid before starting procedure
logger.info("Cell Select: Going to IDLE");
sync.cell_go_idle();
selected_cell = req.carrier;
cmd_worker_cell.add_cmd([this, req]() {
// Request cell search to lower synchronization instance.
start_cell_select(req);
});
return true;
}
bool phy_nr_sa::has_valid_sr_resource(uint32_t sr_id)
@ -196,8 +240,6 @@ bool phy_nr_sa::set_config(const srsran::phy_cfg_nr_t& cfg)
// Setup carrier configuration asynchronously
cmd_worker.add_cmd([this]() {
srsran::srsran_band_helper band_helper;
// tune radio
for (uint32_t i = 0; i < common.args->nof_nr_carriers; i++) {
logger.info("Tuning Rx channel %d to %.2f MHz",

@ -9,6 +9,7 @@
* the distribution.
*
*/
#include "srsue/hdr/phy/nr/sync_sa.h"
#include "srsran/radio/rf_buffer.h"
@ -22,12 +23,12 @@ sync_sa::~sync_sa() {}
bool sync_sa::init(const args_t& args, stack_interface_phy_nr* stack_, srsran::radio_interface_phy* radio_)
{
stack = stack_;
radio = radio_;
sf_sz = (uint32_t)(args.srate_hz / 1000.0f);
stack = stack_;
radio = radio_;
slot_sz = (uint32_t)(args.srate_hz / 1000.0f);
// Initialise cell search internal object
if (not searcher.init(args.get_cell_search(), stack, radio)) {
if (not searcher.init(args.get_cell_search())) {
logger.error("Error initialising cell searcher");
return false;
}
@ -38,6 +39,16 @@ bool sync_sa::init(const args_t& args, stack_interface_phy_nr* stack_, srsran::r
return false;
}
// Compute subframe size
slot_sz = (uint32_t)(args.srate_hz / 1000.0f);
// Allocate receive buffer
rx_buffer = srsran_vec_cf_malloc(2 * slot_sz);
if (rx_buffer == nullptr) {
logger.error("Error allocating buffer");
return false;
}
// Thread control
running = true;
start(args.thread_priority);
@ -46,116 +57,250 @@ bool sync_sa::init(const args_t& args, stack_interface_phy_nr* stack_, srsran::r
return true;
}
bool sync_sa::start_cell_search(const cell_search::cfg_t& cfg)
void sync_sa::stop()
{
running = false;
wait_thread_finish();
radio->reset();
}
bool sync_sa::reset()
{
// Wait worker pool to finish any processing
tti_semaphore.wait_all();
return true;
}
void sync_sa::cell_go_idle()
{
std::unique_lock<std::mutex> ul(rrc_mutex);
phy_state.go_idle();
}
bool sync_sa::wait_idle()
{
// 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");
// Wait for SYNC thread to transition to IDLE (max. 2000ms)
if (!phy_state.wait_idle(100)) {
return false;
}
// Reset UE sync. Attention: doing this reset when the FSM is NOT IDLE can cause PSS/SSS out-of-sync
//...
// Wait for workers to finish PHY processing
tti_semaphore.wait_all();
// As workers have finished, make sure the Tx burst is ended
radio->tx_end();
return phy_state.is_idle();
}
cell_search::ret_t sync_sa::cell_search_run(const cell_search::cfg_t& cfg)
{
std::unique_lock<std::mutex> ul(rrc_mutex);
cs_ret = {};
cs_ret.result = cell_search::ret_t::ERROR;
// Wait the FSM to transition to IDLE
if (!wait_idle()) {
logger.error("Cell Search: SYNC thread didn't transition to IDLE after 100 ms\n");
return cs_ret;
}
rrc_proc_state = PROC_SEARCH_RUNNING;
// Configure searcher without locking state for avoiding stalling the Rx stream
lock.unlock();
logger.info("Cell search: starting in center frequency %.2f and SSB frequency %.2f with subcarrier spacing of %s",
cfg.center_freq_hz / 1e6,
cfg.ssb_freq_hz / 1e6,
srsran_subcarrier_spacing_to_str(cfg.ssb_scs));
if (not searcher.start(cfg)) {
logger.error("Sync: failed to start cell search");
return false;
return cs_ret;
}
lock.lock();
// Transition to search
next_state = STATE_CELL_SEARCH;
// Set RX frequency
radio->set_rx_freq(0, cfg.center_freq_hz);
return true;
}
// Zero receive buffer
srsran_vec_zero(rx_buffer, slot_sz);
bool sync_sa::start_cell_select()
{
return true;
logger.info("Cell Search: Running Cell search state");
cell_search_nof_trials = 0;
phy_state.run_cell_search();
rrc_proc_state = PROC_IDLE;
return cs_ret;
}
bool sync_sa::go_idle()
bool sync_sa::cell_select_run(const phy_interface_rrc_nr::cell_select_args_t& req)
{
std::unique_lock<std::mutex> lock(state_mutex);
std::unique_lock<std::mutex> ul(rrc_mutex);
// Force transition to IDLE
while (state != STATE_IDLE) {
next_state = STATE_IDLE;
state_cvar.wait(lock);
// Wait the FSM to transition to IDLE
if (!wait_idle()) {
logger.error("Cell Search: SYNC thread didn't transition to IDLE after 100 ms\n");
return false;
}
// Wait worker pool to finish any processing
tti_semaphore.wait_all();
rrc_proc_state = PROC_SELECT_RUNNING;
// Reconfigure cell if necessary
// SFN synchronization
phy_state.run_sfn_sync();
if (phy_state.is_camping()) {
logger.info("Cell Select: SFN synchronized. CAMPING...");
} else {
logger.info("Cell Select: Could not synchronize SFN");
}
rrc_proc_state = PROC_IDLE;
return true;
}
void sync_sa::stop()
sync_state::state_t sync_sa::get_state()
{
running = false;
wait_thread_finish();
return phy_state.get_state();
}
sync_sa::state_t sync_sa::get_state() const
void sync_sa::run_state_idle()
{
std::unique_lock<std::mutex> lock(state_mutex);
return state;
if (radio->is_init()) {
logger.debug("Discarding samples and sending tx_end");
radio->tx_end();
} else {
logger.debug("Sleeping 1 ms");
usleep(1000);
}
}
void sync_sa::run_state_idle()
void sync_sa::run_state_cell_search()
{
srsran::rf_buffer_t rf_buffer = {};
rf_buffer.set_nof_samples(sf_sz);
// Run Searcher
cs_ret = searcher.run_slot(rx_buffer, slot_sz);
if (cs_ret.result < 0) {
logger.error("Failed to run searcher. Transitioning to IDLE...");
}
srsran::rf_timestamp_t ts = {};
cell_search_nof_trials++;
// Receives from radio 1 slot
radio->rx_now(rf_buffer, ts);
// Leave CELL_SEARCH state if error or success and transition to IDLE
if (cs_ret.result || cell_search_nof_trials >= cell_search_max_trials) {
phy_state.state_exit();
}
}
stack->run_tti(slot_cfg.idx);
void sync_sa::run_state_cell_select()
{
// TODO
tti = 0;
}
void sync_sa::run_state_cell_search()
void sync_sa::run_state_cell_camping()
{
// Run Searcher
if (not searcher.run()) {
logger.error("Failed to run searcher. Transitioning to IDLE...");
// Update logging TTI
logger.set_context(tti);
// Transition to IDLE if fails to run
state_mutex.lock();
next_state = STATE_IDLE;
state_mutex.unlock();
last_rx_time.add(FDD_HARQ_DELAY_DL_MS * 1e-3);
nr::sf_worker* nr_worker = nullptr;
nr_worker = workers.wait_worker(tti);
if (nr_worker == nullptr) {
running = false;
return;
}
srsran::phy_common_interface::worker_context_t context;
context.sf_idx = tti;
context.worker_ptr = nr_worker;
context.last = true; // Set last if standalone
context.tx_time.copy(last_rx_time);
nr_worker->set_context(context);
// NR worker needs to be launched first, phy_common::worker_end expects first the NR worker and the LTE worker.
tti_semaphore.push(nr_worker);
workers.start_worker(nr_worker);
tti = TTI_ADD(tti, 1);
}
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();
while (running.load(std::memory_order_relaxed)) {
logger.debug("SYNC: state=%s, tti=%d", phy_state.to_string(), tti);
// Setup RF buffer for 1ms worth of samples
if (radio->is_init()) {
srsran::rf_buffer_t rf_buffer = {};
rf_buffer.set_nof_samples(slot_sz);
rf_buffer.set(0, rx_buffer);
switch (current_state) {
case STATE_IDLE:
if (not radio->rx_now(rf_buffer, last_rx_time)) {
logger.error("SYNC: receiving from radio\n");
}
}
switch (phy_state.run_state()) {
case sync_state::IDLE:
run_state_idle();
break;
case STATE_CELL_SEARCH:
case sync_state::CELL_SEARCH:
run_state_cell_search();
break;
case STATE_CELL_SELECT:
case sync_state::SFN_SYNC:
run_state_cell_select();
case sync_state::CAMPING:
run_state_cell_camping();
break;
}
}
// Advance stack TTI
stack->run_tti(tti);
}
void sync_sa::worker_end(const srsran::phy_common_interface::worker_context_t& w_ctx,
const bool& tx_enable,
srsran::rf_buffer_t& buffer)
{}
srsran::rf_buffer_t& tx_buffer)
{
// Wait for the green light to transmit in the current TTI
tti_semaphore.wait(w_ctx.worker_ptr);
// Add current time alignment
srsran::rf_timestamp_t tx_time = w_ctx.tx_time; // get transmit time from the last worker
// todo: tx_time.sub((double)ta.get_sec());
// Check if any worker had a transmission
if (tx_enable) {
// Actual baseband transmission
radio->tx(tx_buffer, tx_time);
} else {
if (radio->is_continuous_tx()) {
if (is_pending_tx_end) {
radio->tx_end();
is_pending_tx_end = false;
} else {
if (!radio->get_is_start_of_burst()) {
// TODO
/*
zeros_multi.set_nof_samples(buffer.get_nof_samples());
radio->tx(zeros_multi, tx_time);
*/
}
}
} else {
radio->tx_end();
}
}
// Allow next TTI to transmit
tti_semaphore.release();
}
} // namespace nr
} // namespace srsue

@ -302,11 +302,13 @@ int main(int argc, char** argv)
// Create dummy UE
dummy_ue::args_t ue_args = {};
ue_args.phy.log.phy_level = args.phy_log_level;
ue_args.stack.log_level = args.stack_log_level;
dummy_ue ue(ue_args, radio.get());
// Transition PHY to cell search
srsue::phy_nr_sa::cell_search_args_t cell_search_req = {};
cell_search_req.srate_hz = args.srate_hz;
cell_search_req.center_freq_hz = args.base_carrier.dl_center_frequency_hz;
cell_search_req.ssb_freq_hz = args.base_carrier.ssb_center_freq_hz;
cell_search_req.ssb_scs = args.ssb_scs;

@ -23,10 +23,10 @@ using namespace srsue;
class dummy_phy : public phy_interface_rrc_nr
{
bool set_config(const srsran::phy_cfg_nr_t& cfg) override { return true; }
phy_nr_state_t get_state() const override { return PHY_NR_STATE_IDLE; };
phy_nr_state_t get_state() override { return PHY_NR_STATE_IDLE; };
void reset_nr() 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; };
bool start_cell_select(const cell_select_args_t& req) override { return false; };
};
class dummy_mac : public mac_interface_rrc_nr

@ -16,7 +16,7 @@
#include "srsran/common/task_scheduler.h"
#include "srsran/interfaces/ue_interfaces.h"
#include "srsran/interfaces/ue_phy_interfaces.h"
#include "srsue/hdr/phy/ue_lte_phy_base.h"
#include "srsue/hdr/phy/ue_phy_base.h"
#include "srsue/hdr/ue.h"
#include "ttcn3_interfaces.h"
#include <srsran/phy/phch/dci.h>
@ -26,7 +26,7 @@ using namespace srsran;
namespace srsue {
class lte_ttcn3_phy : public ue_lte_phy_base
class lte_ttcn3_phy : public ue_phy_base, public phy_interface_stack_lte
{
public:
void set_cells_to_meas(uint32_t earfcn, const std::set<uint32_t>& pci) override;
@ -42,10 +42,9 @@ public:
int init(const phy_args_t& args_, stack_interface_phy_lte* stack_, syssim_interface_phy* syssim_);
int init(const phy_args_t& args_, stack_interface_phy_lte* stack_, srsran::radio_interface_phy* radio_) override;
void stop() override;
void wait_initialize() override;
bool is_initialized() override;
void start_plot() override;
void get_metrics(const srsran::srsran_rat_t& rat, phy_metrics_t* m) override;
std::string get_type() override;
@ -94,10 +93,6 @@ public:
void new_grant_ul(mac_interface_phy_lte::mac_grant_ul_t ul_mac_grant);
void new_tb(const srsue::mac_interface_phy_lte::mac_grant_dl_t, const uint8_t* data);
// Radio interface
void radio_overflow() override;
void radio_failure() override;
void run_tti();
private:

@ -33,18 +33,13 @@ int lte_ttcn3_phy::init(const phy_args_t& args_, stack_interface_phy_lte* stack_
return SRSRAN_SUCCESS;
}
int lte_ttcn3_phy::init(const phy_args_t& args_, stack_interface_phy_lte* stack_, srsran::radio_interface_phy* radio_)
{
stack = stack_;
logger.set_level(srslog::str_to_basic_level(args_.log.phy_level));
logger.set_hex_dump_max_size(-1);
void lte_ttcn3_phy::stop(){};
return SRSRAN_SUCCESS;
bool lte_ttcn3_phy::is_initialized()
{
return true;
}
void lte_ttcn3_phy::stop(){};
void lte_ttcn3_phy::wait_initialize() {}
void lte_ttcn3_phy::start_plot() {}
@ -334,16 +329,6 @@ void lte_ttcn3_phy::new_tb(const srsue::mac_interface_phy_lte::mac_grant_dl_t dl
stack->tb_decoded(cc_idx, dl_grant, dl_ack);
}
void lte_ttcn3_phy::radio_overflow()
{
logger.debug("%s not implemented.", __FUNCTION__);
}
void lte_ttcn3_phy::radio_failure()
{
logger.debug("%s not implemented.", __FUNCTION__);
}
// Calling function set_tti() is holding mutex
void lte_ttcn3_phy::run_tti()
{

@ -141,31 +141,33 @@ public:
void cell_search_found_cell(const cell_search_result_t& result) override
{
#if 0
// Unpack MIB with ASN1
asn1::rrc_nr::mib_s mib_asn1;
asn1::cbit_ref cbit(result.pbch_msg.payload, SRSRAN_PBCH_MSG_NR_SZ);
mib_asn1.unpack(cbit);
// Convert MIB to JSON
asn1::json_writer json;
mib_asn1.to_json(json);
// Unpack MIB with C lib
srsran_mib_nr_t mib_c = {};
srsran_pbch_msg_nr_mib_unpack(&result.pbch_msg, &mib_c);
// Convert MIB from C lib to info
std::array<char, 512> mib_info = {};
srsran_pbch_msg_nr_mib_info(&mib_c, mib_info.data(), (uint32_t)mib_info.size());
// Convert CSI to string
std::array<char, 512> csi_info = {};
srsran_csi_meas_info_short(&result.measurements, csi_info.data(), (uint32_t)csi_info.size());
logger.info(
"Cell found pci=%d %s %s ASN1: %s", result.pci, mib_info.data(), csi_info.data(), json.to_string().c_str());
#endif
if (result.cell_found) {
// Unpack MIB with ASN1
asn1::rrc_nr::mib_s mib_asn1;
asn1::cbit_ref cbit(result.pbch_msg.payload, SRSRAN_PBCH_MSG_NR_SZ);
mib_asn1.unpack(cbit);
// Convert MIB to JSON
asn1::json_writer json;
mib_asn1.to_json(json);
// Unpack MIB with C lib
srsran_mib_nr_t mib_c = {};
srsran_pbch_msg_nr_mib_unpack(&result.pbch_msg, &mib_c);
// Convert MIB from C lib to info
std::array<char, 512> mib_info = {};
srsran_pbch_msg_nr_mib_info(&mib_c, mib_info.data(), (uint32_t)mib_info.size());
// Convert CSI to string
std::array<char, 512> csi_info = {};
srsran_csi_meas_info_short(&result.measurements, csi_info.data(), (uint32_t)csi_info.size());
logger.info(
"Cell found pci=%d %s %s ASN1: %s", result.pci, mib_info.data(), csi_info.data(), json.to_string().c_str());
} else {
logger.info("Cell not found\n");
}
}
};

Loading…
Cancel
Save