ue,sa: add minimal cell selection and setup request procedure

skeleton based on EUTRA procedures
This commit is contained in:
Andre Puschmann 2021-11-30 17:11:43 +01:00
parent cfa614226e
commit 28bd93be40
4 changed files with 342 additions and 16 deletions

View File

@ -132,7 +132,9 @@ public:
private:
// senders
void send_setup_request(srsran::nr_establishment_cause_t cause);
void send_ul_info_transfer(srsran::unique_byte_buffer_t nas_msg);
void send_ul_ccch_msg(const asn1::rrc_nr::ul_ccch_msg_s& msg);
srsran::task_sched_handle task_sched;
struct cmd_msg_t {
@ -159,6 +161,10 @@ private:
meas_cell_list<meas_cell_nr> meas_cells;
// PLMN
bool plmn_is_selected = false;
srsran::unique_byte_buffer_t dedicated_info_nas;
const uint32_t sim_measurement_timer_duration_ms = 250;
uint32_t sim_measurement_carrier_freq_r15;
srsran::timer_handler::unique_timer sim_measurement_timer;
@ -173,7 +179,7 @@ private:
const static char* rrc_nr_state_text[RRC_NR_STATE_N_ITEMS];
rrc_nr_state_t state = RRC_NR_STATE_IDLE;
// Stores the state of the PHy configuration setting
// Stores the state of the PHY configuration setting
enum {
PHY_CFG_STATE_NONE = 0,
PHY_CFG_STATE_APPLY_SP_CELL,
@ -219,9 +225,14 @@ private:
typedef enum { mcg_srb1, en_dc_srb3, nr } reconf_initiator_t;
// RRC procedures
enum class cell_search_result_t { changed_cell, same_cell, no_cell };
class cell_selection_proc;
class connection_reconf_no_ho_proc;
class setup_request_proc;
srsran::proc_t<connection_reconf_no_ho_proc> conn_recfg_proc;
srsran::proc_t<cell_selection_proc, cell_search_result_t> cell_selector;
srsran::proc_t<connection_reconf_no_ho_proc> conn_recfg_proc;
srsran::proc_t<setup_request_proc> setup_req_proc;
srsran::proc_manager_list_t callback_list;
};

View File

@ -22,10 +22,65 @@ namespace srsue {
* Procedures
*******************************/
class rrc_nr::cell_selection_proc
{
public:
using cell_selection_complete_ev = srsran::proc_result_t<cell_search_result_t>;
explicit cell_selection_proc(rrc_nr& parent_);
srsran::proc_outcome_t init();
srsran::proc_outcome_t step();
cell_search_result_t get_result() const { return cell_search_ret; }
static const char* name() { return "Cell Selection"; }
srsran::proc_outcome_t react(const bool& event);
void then(const srsran::proc_result_t<cell_search_result_t>& proc_result) const;
private:
bool is_serv_cell_suitable() const;
srsran::proc_outcome_t set_proc_complete();
// consts
rrc_nr& rrc_handle;
meas_cell_list<meas_cell_nr>& meas_cells;
// state variables
enum class search_state_t { cell_selection, serv_cell_camp, cell_config, cell_search };
cell_search_result_t cell_search_ret;
search_state_t state;
srsran::proc_future_t<rrc_interface_phy_lte::cell_search_ret_t> cell_search_fut;
srsran::proc_future_t<void> serv_cell_cfg_fut;
phy_cell_t init_serv_cell;
};
class rrc_nr::setup_request_proc
{
public:
explicit setup_request_proc(rrc_nr& parent_);
srsran::proc_outcome_t init(srsran::nr_establishment_cause_t cause_,
srsran::unique_byte_buffer_t dedicated_info_nas_);
srsran::proc_outcome_t step();
void then(const srsran::proc_state_t& result);
srsran::proc_outcome_t react(const cell_selection_proc::cell_selection_complete_ev& e);
static const char* name() { return "Setup Request"; }
private:
// const
rrc_nr& rrc_handle;
srslog::basic_logger& logger;
// args
srsran::nr_establishment_cause_t cause;
srsran::unique_byte_buffer_t dedicated_info_nas;
// state variables
enum class state_t { cell_selection, config_serving_cell, wait_t300 } state;
cell_search_result_t cell_search_ret;
srsran::proc_future_t<void> serv_cfg_fut;
};
class rrc_nr::connection_reconf_no_ho_proc
{
public:
explicit connection_reconf_no_ho_proc(rrc_nr* parent_);
explicit connection_reconf_no_ho_proc(rrc_nr& parent_);
srsran::proc_outcome_t init(const reconf_initiator_t initiator_,
const bool endc_release_and_add_r15,
const bool nr_secondary_cell_group_cfg_r15_present,
@ -41,7 +96,7 @@ public:
private:
// const
rrc_nr* rrc_ptr = nullptr;
rrc_nr& rrc_handle;
reconf_initiator_t initiator;
asn1::rrc_nr::rrc_recfg_s rrc_recfg;
asn1::rrc_nr::cell_group_cfg_s cell_group_cfg;

View File

@ -27,7 +27,12 @@ namespace srsue {
const char* rrc_nr::rrc_nr_state_text[] = {"IDLE", "CONNECTED", "CONNECTED-INACTIVE"};
rrc_nr::rrc_nr(srsran::task_sched_handle task_sched_) :
logger(srslog::fetch_basic_logger("RRC-NR")), task_sched(task_sched_), conn_recfg_proc(this), meas_cells(task_sched_)
logger(srslog::fetch_basic_logger("RRC-NR")),
task_sched(task_sched_),
conn_recfg_proc(*this),
setup_req_proc(*this),
cell_selector(*this),
meas_cells(task_sched_)
{}
rrc_nr::~rrc_nr() = default;
@ -53,6 +58,8 @@ int rrc_nr::init(phy_interface_rrc_nr* phy_,
stack = stack_;
args = args_;
plmn_is_selected = true; // short-cut SA test
running = true;
sim_measurement_timer = task_sched.get_unique_timer();
return SRSRAN_SUCCESS;
@ -221,8 +228,13 @@ bool rrc_nr::is_connected()
return false;
}
int rrc_nr::connection_request(srsran::nr_establishment_cause_t cause, srsran::unique_byte_buffer_t sdu)
int rrc_nr::connection_request(srsran::nr_establishment_cause_t cause, srsran::unique_byte_buffer_t dedicated_info_nas_)
{
if (not setup_req_proc.launch(cause, std::move(dedicated_info_nas_))) {
logger.error("Failed to initiate setup request procedure");
return SRSRAN_ERROR;
}
callback_list.add_proc(setup_req_proc);
return SRSRAN_SUCCESS;
}
@ -242,6 +254,58 @@ void rrc_nr::send_ul_info_transfer(unique_byte_buffer_t nas_msg)
logger.warning("%s not implemented yet.", __FUNCTION__);
}
void rrc_nr::send_setup_request(srsran::nr_establishment_cause_t cause)
{
logger.debug("Preparing RRC Setup Request");
// Prepare SetupRequest packet
ul_ccch_msg_s ul_ccch_msg;
rrc_setup_request_ies_s* rrc_setup_req = &ul_ccch_msg.msg.set_c1().set_rrc_setup_request().rrc_setup_request;
// TODO: implement ng_minus5_g_s_tmsi_part1
rrc_setup_req->ue_id.set_random_value();
// TODO use proper RNG
uint64_t random_id = 0;
for (uint i = 0; i < 5; i++) { // fill random ID bytewise, 40 bits = 5 bytes
random_id |= ((uint64_t)rand() & 0xFF) << i * 8;
}
rrc_setup_req->ue_id.random_value().from_number(random_id);
rrc_setup_req->establishment_cause = (establishment_cause_opts::options)cause;
send_ul_ccch_msg(ul_ccch_msg);
}
void rrc_nr::send_ul_ccch_msg(const asn1::rrc_nr::ul_ccch_msg_s& msg)
{
unique_byte_buffer_t pdu = srsran::make_byte_buffer();
if (pdu == nullptr) {
logger.error("Couldn't allocate PDU in %s().", __FUNCTION__);
return;
}
asn1::bit_ref bref(pdu->msg, pdu->get_tailroom());
msg.pack(bref);
bref.align_bytes_zero();
pdu->N_bytes = (uint32_t)bref.distance_bytes(pdu->msg);
pdu->set_timestamp();
// Set UE contention resolution ID in MAC
uint64_t uecri = 0;
uint8_t* ue_cri_ptr = (uint8_t*)&uecri;
uint32_t nbytes = 6;
for (uint32_t i = 0; i < nbytes; i++) {
ue_cri_ptr[nbytes - i - 1] = pdu->msg[i];
}
logger.debug("Setting UE contention resolution ID: %" PRIu64 "", uecri);
mac->set_contention_id(uecri);
uint32_t lcid = 0;
log_rrc_message(get_rb_name(lcid), Tx, pdu.get(), msg, msg.msg.c1().type().to_string());
rlc->write_sdu(lcid, std::move(pdu));
}
// EUTRA-RRC interface
int rrc_nr::get_eutra_nr_capabilities(srsran::byte_buffer_t* eutra_nr_caps_pdu)
{
@ -1542,6 +1606,7 @@ bool rrc_nr::apply_radio_bearer_cfg(const radio_bearer_cfg_s& radio_bearer_cfg)
}
return true;
}
// RLC interface
void rrc_nr::max_retx_attempted() {}
void rrc_nr::protocol_failure() {}
@ -1553,6 +1618,7 @@ void rrc_nr::ra_completed()
phy->set_config(phy_cfg);
phy_cfg_state = PHY_CFG_STATE_RA_COMPLETED;
}
void rrc_nr::ra_problem()
{
rrc_eutra->nr_scg_failure_information(scg_failure_cause_t::random_access_problem);

View File

@ -13,10 +13,10 @@
#include "srsue/hdr/stack/rrc_nr/rrc_nr_procedures.h"
#include "srsran/common/standard_streams.h"
#define Error(fmt, ...) rrc_ptr->logger.error("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
#define Warning(fmt, ...) rrc_ptr->logger.warning("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
#define Info(fmt, ...) rrc_ptr->logger.info("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
#define Debug(fmt, ...) rrc_ptr->logger.debug("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
#define Error(fmt, ...) rrc_handle.logger.error("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
#define Warning(fmt, ...) rrc_handle.logger.warning("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
#define Info(fmt, ...) rrc_handle.logger.info("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
#define Debug(fmt, ...) rrc_handle.logger.debug("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
using namespace asn1::rrc_nr;
using namespace asn1;
@ -24,7 +24,8 @@ using namespace srsran;
namespace srsue {
rrc_nr::connection_reconf_no_ho_proc::connection_reconf_no_ho_proc(rrc_nr* parent_) : rrc_ptr(parent_), initiator(nr) {}
rrc_nr::connection_reconf_no_ho_proc::connection_reconf_no_ho_proc(rrc_nr& parent_) : rrc_handle(parent_), initiator(nr)
{}
proc_outcome_t rrc_nr::connection_reconf_no_ho_proc::init(const reconf_initiator_t initiator_,
const bool endc_release_and_add_r15,
@ -55,6 +56,7 @@ proc_outcome_t rrc_nr::connection_reconf_no_ho_proc::init(const reconf_initiator
rrc_ptr->log_rrc_message(
"RRC NR Reconfiguration", Rx, nr_secondary_cell_group_cfg_r15, rrc_recfg, "NR Secondary Cell Group Cfg R15");
#endif
if (rrc_recfg.crit_exts.type() != asn1::rrc_nr::rrc_recfg_s::crit_exts_c_::types::rrc_recfg) {
Error("Reconfiguration does not contain Secondary Cell Group Config");
return proc_outcome_t::error;
@ -83,14 +85,14 @@ proc_outcome_t rrc_nr::connection_reconf_no_ho_proc::init(const reconf_initiator
#endif
Info("Applying Cell Group Cfg");
if (!rrc_ptr->apply_cell_group_cfg(cell_group_cfg)) {
if (!rrc_handle.apply_cell_group_cfg(cell_group_cfg)) {
return proc_outcome_t::error;
}
}
if (sk_counter_r15_present) {
Info("Applying Cell Group Cfg");
if (!rrc_ptr->configure_sk_counter((uint16_t)sk_counter_r15)) {
if (!rrc_handle.configure_sk_counter((uint16_t)sk_counter_r15)) {
return proc_outcome_t::error;
}
}
@ -110,7 +112,7 @@ proc_outcome_t rrc_nr::connection_reconf_no_ho_proc::init(const reconf_initiator
#endif
Info("Applying Radio Bearer Cfg");
if (!rrc_ptr->apply_radio_bearer_cfg(radio_bearer_cfg)) {
if (!rrc_handle.apply_radio_bearer_cfg(radio_bearer_cfg)) {
return proc_outcome_t::error;
}
}
@ -140,12 +142,12 @@ void rrc_nr::connection_reconf_no_ho_proc::then(const srsran::proc_state_t& resu
if (result.is_success()) {
Info("Finished %s successfully", name());
srsran::console("RRC NR reconfiguration successful.\n");
rrc_ptr->rrc_eutra->nr_rrc_con_reconfig_complete(true);
rrc_handle.rrc_eutra->nr_rrc_con_reconfig_complete(true);
} else {
// 5.3.5.8.2 Inability to comply with RRCReconfiguration
switch (initiator) {
case reconf_initiator_t::mcg_srb1:
rrc_ptr->rrc_eutra->nr_notify_reconfiguration_failure();
rrc_handle.rrc_eutra->nr_notify_reconfiguration_failure();
break;
default:
Warning("Reconfiguration failure not implemented for initiator %d", initiator);
@ -157,4 +159,196 @@ void rrc_nr::connection_reconf_no_ho_proc::then(const srsran::proc_state_t& resu
return;
}
/**************************************
* RRC Setup Request Procedure
*************************************/
rrc_nr::setup_request_proc::setup_request_proc(rrc_nr& parent_) :
rrc_handle(parent_), logger(srslog::fetch_basic_logger("RRC"))
{}
proc_outcome_t rrc_nr::setup_request_proc::init(srsran::nr_establishment_cause_t cause_,
srsran::unique_byte_buffer_t dedicated_info_nas_)
{
cause = cause_;
dedicated_info_nas = std::move(dedicated_info_nas_);
if (!rrc_handle.plmn_is_selected) {
Error("Trying to connect but PLMN not selected.");
return proc_outcome_t::error;
}
if (rrc_handle.state != RRC_NR_STATE_IDLE) {
logger.warning("Requested RRC connection establishment while not in IDLE");
return proc_outcome_t::error;
}
// TODO: add T302 handling
Info("Initiation of Connection establishment procedure");
cell_search_ret = cell_search_result_t::no_cell;
state = state_t::cell_selection;
if (rrc_handle.cell_selector.is_idle()) {
// No one is running cell selection
if (not rrc_handle.cell_selector.launch()) {
Error("Failed to initiate cell selection procedure...");
return proc_outcome_t::error;
}
rrc_handle.callback_list.add_proc(rrc_handle.cell_selector);
} else {
Info("Cell selection proc already on-going. Wait for its result");
}
return proc_outcome_t::yield;
}
proc_outcome_t rrc_nr::setup_request_proc::step()
{
if (state == state_t::cell_selection) {
// NOTE: cell selection will signal back with an event trigger
return proc_outcome_t::yield;
}
if (state == state_t::config_serving_cell) {
// TODO: start serving cell config and start T300
// Send setup request message to lower layers
rrc_handle.send_setup_request(cause);
Info("Waiting for RRCSetup/Reject or expiry");
state = state_t::wait_t300;
return step();
} else if (state == state_t::wait_t300) {
// TODO: add T300 waiting
}
return proc_outcome_t::error;
}
void rrc_nr::setup_request_proc::then(const srsran::proc_state_t& result)
{
if (result.is_error()) {
logger.warning("Could not establish connection. Deallocating dedicatedInfoNAS PDU");
dedicated_info_nas.reset();
rrc_handle.dedicated_info_nas.reset();
} else {
Info("Finished connection request procedure successfully.");
}
// TODO: signal back to NAS
// rrc_handle.nas->connection_request_completed(result.is_success());
}
srsran::proc_outcome_t rrc_nr::setup_request_proc::react(const cell_selection_proc::cell_selection_complete_ev& e)
{
if (state != state_t::cell_selection) {
// ignore if we are not expecting an cell selection result
return proc_outcome_t::yield;
}
if (e.is_error()) {
return proc_outcome_t::error;
}
cell_search_ret = *e.value();
// .. and SI acquisition
// TODO @ismagom use appropiate PHY interface
if (true /*rrc_handle.phy->cell_is_camping()*/) {
// TODO: Set default configurations
// rrc_handle.set_phy_default();
// rrc_handle.set_mac_default();
// CCCH configuration applied already at start
// timeAlignmentCommon applied in configure_serving_cell
Info("Configuring serving cell...");
state = state_t::config_serving_cell;
// Skip SI acquisition
return step();
} else {
switch (cell_search_ret) {
case cell_search_result_t::same_cell:
logger.warning("Did not reselect cell but serving cell is out-of-sync.");
break;
case cell_search_result_t::changed_cell:
logger.warning("Selected a new cell but could not camp on. Setting out-of-sync.");
break;
default:
logger.warning("Could not find any suitable cell to connect");
}
return proc_outcome_t::error;
}
}
/**************************************
* Basic Cell Selection Procedure
*************************************/
rrc_nr::cell_selection_proc::cell_selection_proc(rrc_nr& parent_) :
rrc_handle(parent_), meas_cells(rrc_handle.meas_cells)
{}
/// Verifies if serving cell passes selection criteria, UE is camping, and required SIBs were obtained
bool rrc_nr::cell_selection_proc::is_serv_cell_suitable() const
{
// TODO: add selection criteria
return true;
}
/// Called on procedure exit to set result
proc_outcome_t rrc_nr::cell_selection_proc::set_proc_complete()
{
if (is_serv_cell_suitable()) {
cell_search_ret = is_same_cell(init_serv_cell, meas_cells.serving_cell()) ? cell_search_result_t::same_cell
: cell_search_result_t::changed_cell;
return proc_outcome_t::success;
}
cell_search_ret = cell_search_result_t::no_cell;
return proc_outcome_t::error;
}
proc_outcome_t rrc_nr::cell_selection_proc::init()
{
init_serv_cell = meas_cells.serving_cell().phy_cell;
// Skip cell selection if serving cell is suitable and there are no stronger neighbours in same earfcn
if (is_serv_cell_suitable()) {
Debug("Skipping cell selection procedure as there are no stronger neighbours in same EARFCN.");
return set_proc_complete();
}
// TODO: add full cell selection
return set_proc_complete();
}
proc_outcome_t rrc_nr::cell_selection_proc::step()
{
switch (state) {
case search_state_t::cell_selection:
// this state waits for phy event
return proc_outcome_t::yield;
case search_state_t::serv_cell_camp:
// this state waits for phy event
return proc_outcome_t::yield;
case search_state_t::cell_config:
// return step_cell_config();
return proc_outcome_t::yield;
case search_state_t::cell_search:
// return step_cell_search();
return proc_outcome_t::yield;
}
return proc_outcome_t::error;
}
void rrc_nr::cell_selection_proc::then(const srsran::proc_result_t<cell_search_result_t>& proc_result) const
{
Info("Completed with %s.", proc_result.is_success() ? "success" : "failure");
// Inform Connection Request Procedure
rrc_handle.task_sched.defer_task([this, proc_result]() {
if (rrc_handle.setup_req_proc.is_busy()) {
rrc_handle.setup_req_proc.trigger(proc_result);
}
});
}
} // namespace srsue