mirror of https://github.com/pvnis/srsRAN_4G.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
275 lines
7.5 KiB
C++
275 lines
7.5 KiB
C++
/**
|
|
*
|
|
* \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"
|
|
#include "srsran/common/standard_streams.h"
|
|
#include "srsran/srsran.h"
|
|
|
|
namespace srsue {
|
|
|
|
static void srsran_phy_handler(phy_logger_level_t log_level, void* ctx, char* str)
|
|
{
|
|
phy_nr_sa* r = (phy_nr_sa*)ctx;
|
|
r->srsran_phy_logger(log_level, str);
|
|
}
|
|
|
|
void phy_nr_sa::srsran_phy_logger(phy_logger_level_t log_level, char* str)
|
|
{
|
|
switch (log_level) {
|
|
case LOG_LEVEL_INFO_S:
|
|
logger_phy_lib.info(" %s", str);
|
|
break;
|
|
case LOG_LEVEL_DEBUG_S:
|
|
logger_phy_lib.debug(" %s", str);
|
|
break;
|
|
case LOG_LEVEL_ERROR_S:
|
|
logger_phy_lib.error(" %s", str);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void phy_nr_sa::set_default_args(phy_args_nr_t& args_)
|
|
{
|
|
args_.nof_phy_threads = DEFAULT_WORKERS;
|
|
// TODO
|
|
}
|
|
|
|
bool phy_nr_sa::check_args(const phy_args_nr_t& args_)
|
|
{
|
|
if (args_.nof_phy_threads > MAX_WORKERS) {
|
|
srsran::console("Error in PHY args: nof_phy_threads must be 1, 2 or 3\n");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
phy_nr_sa::phy_nr_sa(const char* logname) :
|
|
logger(srslog::fetch_basic_logger(logname)),
|
|
logger_phy_lib(srslog::fetch_basic_logger("PHY_LIB")),
|
|
sync(logger, workers),
|
|
workers(logger, 4)
|
|
{}
|
|
|
|
int phy_nr_sa::init(const phy_args_nr_t& args_, stack_interface_phy_nr* stack_, srsran::radio_interface_phy* radio_)
|
|
{
|
|
args = args_;
|
|
stack = stack_;
|
|
radio = radio_;
|
|
|
|
// Add PHY lib log
|
|
auto lib_log_level = srslog::str_to_basic_level(args.log.phy_lib_level);
|
|
logger_phy_lib.set_level(lib_log_level);
|
|
logger_phy_lib.set_hex_dump_max_size(args.log.phy_hex_limit);
|
|
if (lib_log_level != srslog::basic_levels::none) {
|
|
srsran_phy_log_register_handler(this, srsran_phy_handler);
|
|
}
|
|
|
|
// set default logger
|
|
logger.set_level(srslog::str_to_basic_level(args.log.phy_level));
|
|
logger.set_hex_dump_max_size(args.log.phy_hex_limit);
|
|
|
|
logger.set_context(0);
|
|
|
|
if (!check_args(args)) {
|
|
return SRSRAN_ERROR;
|
|
}
|
|
|
|
is_configured = false;
|
|
std::thread t([this]() { init_background(); });
|
|
init_thread = std::move(t);
|
|
|
|
return SRSRAN_SUCCESS;
|
|
}
|
|
|
|
void phy_nr_sa::init_background()
|
|
{
|
|
nr::sync_sa::args_t sync_args = {};
|
|
sync_args.srate_hz = args.srate_hz;
|
|
sync_args.thread_priority = args.slot_recv_thread_prio;
|
|
if (not sync.init(sync_args, stack, radio)) {
|
|
logger.error("Error initialising SYNC");
|
|
return;
|
|
}
|
|
workers.init(args, sync, stack);
|
|
|
|
is_configured = true;
|
|
}
|
|
|
|
void phy_nr_sa::stop()
|
|
{
|
|
cmd_worker.stop();
|
|
cmd_worker_cell.stop();
|
|
if (is_configured) {
|
|
sync.stop();
|
|
workers.stop();
|
|
is_configured = false;
|
|
}
|
|
}
|
|
|
|
bool phy_nr_sa::is_initialized()
|
|
{
|
|
return is_configured;
|
|
}
|
|
|
|
void phy_nr_sa::wait_initialize()
|
|
{
|
|
init_thread.join();
|
|
}
|
|
|
|
phy_interface_rrc_nr::phy_nr_state_t phy_nr_sa::get_state()
|
|
{
|
|
{
|
|
switch (sync.get_state()) {
|
|
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 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;
|
|
}
|
|
|
|
void phy_nr_sa::reset_nr()
|
|
{
|
|
sync.reset();
|
|
|
|
sync.cell_go_idle();
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
// TODO: verify arguments are valid before starting procedure
|
|
|
|
cmd_worker_cell.add_cmd([this, req]() {
|
|
logger.info("Cell Search: Going to IDLE");
|
|
sync.cell_go_idle();
|
|
|
|
// Prepare cell search configuration from the request
|
|
nr::cell_search::cfg_t cfg = {};
|
|
cfg.srate_hz = 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;
|
|
|
|
// 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);
|
|
});
|
|
|
|
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 and push the result directly to the stack
|
|
stack->cell_select_completed(sync.cell_select_run(req));
|
|
});
|
|
|
|
return true;
|
|
}
|
|
|
|
bool phy_nr_sa::has_valid_sr_resource(uint32_t sr_id)
|
|
{
|
|
return workers.has_valid_sr_resource(sr_id);
|
|
}
|
|
|
|
void phy_nr_sa::clear_pending_grants()
|
|
{
|
|
workers.clear_pending_grants();
|
|
}
|
|
|
|
void phy_nr_sa::send_prach(const uint32_t prach_occasion,
|
|
const int preamble_index,
|
|
const float preamble_received_target_power,
|
|
const float ta_base_sec)
|
|
{
|
|
workers.send_prach(prach_occasion, preamble_index, preamble_received_target_power);
|
|
}
|
|
|
|
void phy_nr_sa::set_timeadv_rar(uint32_t tti, uint32_t ta_cmd)
|
|
{
|
|
sync.add_ta_cmd_rar(tti, ta_cmd);
|
|
}
|
|
|
|
void phy_nr_sa::set_timeadv(uint32_t tti, uint32_t ta_cmd)
|
|
{
|
|
sync.add_ta_cmd_new(tti, ta_cmd);
|
|
}
|
|
|
|
int phy_nr_sa::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)
|
|
{
|
|
return workers.set_rar_grant(rar_slot_idx, packed_ul_grant, rnti, rnti_type);
|
|
}
|
|
|
|
bool phy_nr_sa::set_config(const srsran::phy_cfg_nr_t& cfg)
|
|
{
|
|
// Stash NR configuration
|
|
config_nr = cfg;
|
|
|
|
// Setup carrier configuration asynchronously
|
|
cmd_worker.add_cmd([this]() {
|
|
// Set UE configuration
|
|
bool ret = workers.set_config(config_nr);
|
|
|
|
// Pass n_ta_offset to sync
|
|
sync.add_ta_offset(config_nr.t_offset);
|
|
|
|
// Notify PHY config completion
|
|
if (stack != nullptr) {
|
|
stack->set_phy_config_complete(ret);
|
|
}
|
|
|
|
return ret;
|
|
});
|
|
return true;
|
|
}
|
|
|
|
} // namespace srsue
|