Add RLF-Reportv9 to srsUE

master
Ismael Gomez 3 years ago committed by Francisco Paisana
parent a366982e06
commit 7839ab09dc

@ -16,6 +16,7 @@
#include "rrc_cell.h" #include "rrc_cell.h"
#include "rrc_common.h" #include "rrc_common.h"
#include "rrc_metrics.h" #include "rrc_metrics.h"
#include "rrc_rlf_report.h"
#include "srsran/asn1/rrc_utils.h" #include "srsran/asn1/rrc_utils.h"
#include "srsran/common/bcd_helpers.h" #include "srsran/common/bcd_helpers.h"
#include "srsran/common/block_queue.h" #include "srsran/common/block_queue.h"
@ -218,6 +219,9 @@ private:
const char* get_rb_name(uint32_t lcid) { return srsran::is_lte_rb(lcid) ? rb_id_str[lcid].c_str() : "invalid RB"; } const char* get_rb_name(uint32_t lcid) { return srsran::is_lte_rb(lcid) ? rb_id_str[lcid].c_str() : "invalid RB"; }
// Var-RLF-Report class
rrc_rlf_report var_rlf_report;
// Measurements private subclass // Measurements private subclass
class rrc_meas; class rrc_meas;
std::unique_ptr<rrc_meas> measurements; std::unique_ptr<rrc_meas> measurements;
@ -375,6 +379,7 @@ private:
void handle_con_reest(const asn1::rrc::rrc_conn_reest_s& setup); void handle_con_reest(const asn1::rrc::rrc_conn_reest_s& setup);
void handle_rrc_con_reconfig(uint32_t lcid, const asn1::rrc::rrc_conn_recfg_s& reconfig); void handle_rrc_con_reconfig(uint32_t lcid, const asn1::rrc::rrc_conn_recfg_s& reconfig);
void handle_ue_capability_enquiry(const asn1::rrc::ue_cap_enquiry_s& enquiry); void handle_ue_capability_enquiry(const asn1::rrc::ue_cap_enquiry_s& enquiry);
void handle_ue_info_request(const ue_info_request_r9_s& request);
void add_srb(const asn1::rrc::srb_to_add_mod_s& srb_cnfg); void add_srb(const asn1::rrc::srb_to_add_mod_s& srb_cnfg);
void add_drb(const asn1::rrc::drb_to_add_mod_s& drb_cnfg); void add_drb(const asn1::rrc::drb_to_add_mod_s& drb_cnfg);
void release_drb(uint32_t drb_id); void release_drb(uint32_t drb_id);

@ -147,6 +147,7 @@ public:
bool has_plmn_id(asn1::rrc::plmn_id_s plmn_id) const; bool has_plmn_id(asn1::rrc::plmn_id_s plmn_id) const;
uint32_t nof_plmns() const { return has_sib1() ? sib1.cell_access_related_info.plmn_id_list.size() : 0; } uint32_t nof_plmns() const { return has_sib1() ? sib1.cell_access_related_info.plmn_id_list.size() : 0; }
srsran::plmn_id_t get_plmn(uint32_t idx) const; srsran::plmn_id_t get_plmn(uint32_t idx) const;
asn1::rrc::plmn_id_s get_plmn_asn1(uint32_t idx) const;
uint16_t get_tac() const { return has_sib1() ? (uint16_t)sib1.cell_access_related_info.tac.to_number() : 0; } uint16_t get_tac() const { return has_sib1() ? (uint16_t)sib1.cell_access_related_info.tac.to_number() : 0; }
@ -161,6 +162,7 @@ public:
const asn1::rrc::sib_type13_r9_s* sib13ptr() const { return has_sib13() ? &sib13 : nullptr; } const asn1::rrc::sib_type13_r9_s* sib13ptr() const { return has_sib13() ? &sib13 : nullptr; }
uint32_t get_cell_id() const { return (uint32_t)sib1.cell_access_related_info.cell_id.to_number(); } uint32_t get_cell_id() const { return (uint32_t)sib1.cell_access_related_info.cell_id.to_number(); }
asn1::fixed_bitstring<28> get_cell_id_bit() const { return sib1.cell_access_related_info.cell_id; }
bool has_sib13() const { return has_valid_sib13; } bool has_sib13() const { return has_valid_sib13; }

@ -15,6 +15,8 @@
namespace srsue { namespace srsue {
#include <stdint.h>
// RRC states (3GPP 36.331 v10.0.0) // RRC states (3GPP 36.331 v10.0.0)
typedef enum { typedef enum {
RRC_STATE_IDLE = 0, RRC_STATE_IDLE = 0,
@ -23,6 +25,11 @@ typedef enum {
} rrc_state_t; } rrc_state_t;
static const char rrc_state_text[RRC_STATE_N_ITEMS][100] = {"IDLE", "CONNECTED"}; static const char rrc_state_text[RRC_STATE_N_ITEMS][100] = {"IDLE", "CONNECTED"};
enum quant_s { quant_rsrp, quant_rsrq };
uint8_t rrc_value_to_range(quant_s quant, const float value);
float rrc_range_to_value(quant_s quant, const uint8_t range);
} // namespace srsue } // namespace srsue
#endif // SRSUE_RRC_COMMON_H #endif // SRSUE_RRC_COMMON_H

@ -192,8 +192,6 @@ private:
rrc* rrc_ptr = nullptr; rrc* rrc_ptr = nullptr;
// Static functions // Static functions
static uint8_t value_to_range(const report_cfg_eutra_s::trigger_quant_opts::options q, float value);
static float range_to_value(const report_cfg_eutra_s::trigger_quant_opts::options q, const uint8_t range);
static uint8_t value_to_range_nr(const asn1::rrc::thres_nr_r15_c::types_opts::options type, const float value); static uint8_t value_to_range_nr(const asn1::rrc::thres_nr_r15_c::types_opts::options type, const float value);
static float range_to_value_nr(const asn1::rrc::thres_nr_r15_c::types_opts::options type, const uint8_t range); static float range_to_value_nr(const asn1::rrc::thres_nr_r15_c::types_opts::options type, const uint8_t range);
static uint8_t offset_val(const meas_obj_eutra_s& meas_obj); static uint8_t offset_val(const meas_obj_eutra_s& meas_obj);

@ -0,0 +1,58 @@
/**
*
* \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 SRSRAN_RRC_RLF_REPORT_H_
#define SRSRAN_RRC_RLF_REPORT_H_
#include "rrc_cell.h"
#include "srsran/asn1/rrc.h"
#include "srsran/common/common.h"
namespace srsue {
using namespace asn1::rrc;
// RRC RLF-Report class
class rrc_rlf_report
{
public:
enum failure_type_t { rlf, hof };
void init(srsran::task_sched_handle task_sched);
// Returns true if VarRLF-Report structure has info available
bool has_info();
// Called upon T304 expiry (type == hof) or Detection of radio link failure (type == rlf)
void set_failure(meas_cell_list<meas_cell_eutra>& meas_cells, failure_type_t type);
// Called upon transmission of ReestablishmentRequest message
void set_reest_gci(const asn1::fixed_bitstring<28>& gci, const asn1::rrc::plmn_id_s& plmn_id);
// Called upon initiation of RadioReconfiguration message including MobilityInfo IE
void received_ho_command(const asn1::fixed_bitstring<28>& current_gci);
// Returns a copy of the rlf_report_r9 ASN1 struct
rlf_report_r9_s get_report();
// Clears VarRLF-Report contents
void clear();
private:
asn1::fixed_bitstring<28> ho_gci;
bool has_event = false;
rlf_report_r9_s rlf_report = {};
srsran::timer_handler::unique_timer timer_conn_failure = {};
};
} // namespace srsue
#endif // SRSRAN_RRC_RLF_REPORT_H_

@ -8,7 +8,7 @@
add_subdirectory(test) add_subdirectory(test)
set(SOURCES rrc.cc rrc_procedures.cc rrc_meas.cc rrc_cell.cc phy_controller.cc) set(SOURCES rrc.cc rrc_procedures.cc rrc_meas.cc rrc_cell.cc rrc_common.cc rrc_rlf_report.cc phy_controller.cc)
add_library(srsue_rrc STATIC ${SOURCES}) add_library(srsue_rrc STATIC ${SOURCES})
set(SOURCES rrc_nr.cc) set(SOURCES rrc_nr.cc)

@ -139,6 +139,8 @@ void rrc::init(phy_interface_rrc_lte* phy_,
t311 = task_sched.get_unique_timer(); t311 = task_sched.get_unique_timer();
t304 = task_sched.get_unique_timer(); t304 = task_sched.get_unique_timer();
var_rlf_report.init(task_sched);
transaction_id = 0; transaction_id = 0;
cell_clean_cnt = 0; cell_clean_cnt = 0;
@ -674,6 +676,9 @@ void rrc::radio_link_failure_process()
// TODO: Generate and store failure report // TODO: Generate and store failure report
srsran::console("Warning: Detected Radio-Link Failure\n"); srsran::console("Warning: Detected Radio-Link Failure\n");
// Store the information in VarRLF-Report
var_rlf_report.set_failure(meas_cells, rrc_rlf_report::rlf);
if (state == RRC_STATE_CONNECTED) { if (state == RRC_STATE_CONNECTED) {
if (security_is_activated) { if (security_is_activated) {
logger.info("Detected Radio-Link Failure with active AS security. Starting ConnectionReestablishment..."); logger.info("Detected Radio-Link Failure with active AS security. Starting ConnectionReestablishment...");
@ -857,6 +862,9 @@ void rrc::send_con_restablish_request(reest_cause_e cause, uint16_t crnti, uint1
// Clean reestablishment type // Clean reestablishment type
reestablishment_successful = false; reestablishment_successful = false;
// set the reestablishmentCellId in the VarRLF-Report to the global cell identity of the selected cell;
var_rlf_report.set_reest_gci(meas_cells.serving_cell().get_cell_id_bit(), meas_cells.serving_cell().get_plmn_asn1(0));
if (cause.value != reest_cause_opts::ho_fail) { if (cause.value != reest_cause_opts::ho_fail) {
if (cause.value != reest_cause_opts::other_fail) { if (cause.value != reest_cause_opts::other_fail) {
pci = meas_cells.serving_cell().get_pci(); pci = meas_cells.serving_cell().get_pci();
@ -945,6 +953,15 @@ void rrc::send_con_restablish_complete()
ul_dcch_msg.msg.set_c1().set_rrc_conn_reest_complete().crit_exts.set_rrc_conn_reest_complete_r8(); ul_dcch_msg.msg.set_c1().set_rrc_conn_reest_complete().crit_exts.set_rrc_conn_reest_complete_r8();
ul_dcch_msg.msg.c1().rrc_conn_reest_complete().rrc_transaction_id = transaction_id; ul_dcch_msg.msg.c1().rrc_conn_reest_complete().rrc_transaction_id = transaction_id;
// Include rlf-InfoAvailable
if (var_rlf_report.has_info()) {
ul_dcch_msg.msg.c1().rrc_conn_reest_complete().crit_exts.rrc_conn_reest_complete_r8().non_crit_ext_present = true;
ul_dcch_msg.msg.c1()
.rrc_conn_reest_complete()
.crit_exts.rrc_conn_reest_complete_r8()
.non_crit_ext.rlf_info_available_r9_present = true;
}
send_ul_dcch_msg(srb_to_lcid(lte_srb::srb1), ul_dcch_msg); send_ul_dcch_msg(srb_to_lcid(lte_srb::srb1), ul_dcch_msg);
reestablishment_successful = true; reestablishment_successful = true;
@ -961,6 +978,13 @@ void rrc::send_con_setup_complete(srsran::unique_byte_buffer_t nas_msg)
ul_dcch_msg.msg.c1().rrc_conn_setup_complete().rrc_transaction_id = transaction_id; ul_dcch_msg.msg.c1().rrc_conn_setup_complete().rrc_transaction_id = transaction_id;
// Include rlf-InfoAvailable
if (var_rlf_report.has_info()) {
rrc_conn_setup_complete->non_crit_ext_present = true;
rrc_conn_setup_complete->non_crit_ext.non_crit_ext_present = true;
rrc_conn_setup_complete->non_crit_ext.non_crit_ext.rlf_info_available_r10_present = true;
}
rrc_conn_setup_complete->sel_plmn_id = 1; rrc_conn_setup_complete->sel_plmn_id = 1;
rrc_conn_setup_complete->ded_info_nas.resize(nas_msg->N_bytes); rrc_conn_setup_complete->ded_info_nas.resize(nas_msg->N_bytes);
memcpy(rrc_conn_setup_complete->ded_info_nas.data(), nas_msg->msg, nas_msg->N_bytes); // TODO Check! memcpy(rrc_conn_setup_complete->ded_info_nas.data(), nas_msg->msg, nas_msg->N_bytes); // TODO Check!
@ -1005,6 +1029,13 @@ void rrc::send_rrc_con_reconfig_complete(bool contains_nr_complete)
&ul_dcch_msg.msg.set_c1().set_rrc_conn_recfg_complete().crit_exts.set_rrc_conn_recfg_complete_r8(); &ul_dcch_msg.msg.set_c1().set_rrc_conn_recfg_complete().crit_exts.set_rrc_conn_recfg_complete_r8();
ul_dcch_msg.msg.c1().rrc_conn_recfg_complete().rrc_transaction_id = transaction_id; ul_dcch_msg.msg.c1().rrc_conn_recfg_complete().rrc_transaction_id = transaction_id;
// Include rlf-InfoAvailable
if (var_rlf_report.has_info()) {
rrc_conn_recfg_complete_r8->non_crit_ext_present = true;
rrc_conn_recfg_complete_r8->non_crit_ext.non_crit_ext_present = true;
rrc_conn_recfg_complete_r8->non_crit_ext.non_crit_ext.rlf_info_available_r10_present = true;
}
if (contains_nr_complete == true) { if (contains_nr_complete == true) {
logger.debug("Preparing RRC Connection Reconfig Complete with NR Complete"); logger.debug("Preparing RRC Connection Reconfig Complete with NR Complete");
@ -1055,6 +1086,10 @@ void rrc::start_go_idle()
void rrc::ho_failed() void rrc::ho_failed()
{ {
ho_handler.trigger(ho_proc::t304_expiry{}); ho_handler.trigger(ho_proc::t304_expiry{});
// Store the information in VarRLF-Report
var_rlf_report.set_failure(meas_cells, rrc_rlf_report::hof);
start_con_restablishment(reest_cause_e::ho_fail); start_con_restablishment(reest_cause_e::ho_fail);
} }
@ -1757,6 +1792,10 @@ void rrc::parse_dl_dcch(uint32_t lcid, unique_byte_buffer_t pdu)
case dl_dcch_msg_type_c::c1_c_::types::rrc_conn_release: case dl_dcch_msg_type_c::c1_c_::types::rrc_conn_release:
rrc_connection_release(c1->rrc_conn_release().crit_exts.c1().rrc_conn_release_r8().release_cause.to_string()); rrc_connection_release(c1->rrc_conn_release().crit_exts.c1().rrc_conn_release_r8().release_cause.to_string());
break; break;
case dl_dcch_msg_type_c::c1_c_::types::ue_info_request_r9:
transaction_id = c1->ue_info_request_r9().rrc_transaction_id;
handle_ue_info_request(c1->ue_info_request_r9());
break;
default: default:
logger.error("The provided DL-CCCH message type is not recognized or supported"); logger.error("The provided DL-CCCH message type is not recognized or supported");
break; break;
@ -2136,6 +2175,42 @@ void rrc::handle_ue_capability_enquiry(const ue_cap_enquiry_s& enquiry)
send_ul_dcch_msg(srb_to_lcid(lte_srb::srb1), ul_dcch_msg); send_ul_dcch_msg(srb_to_lcid(lte_srb::srb1), ul_dcch_msg);
} }
/*******************************************************************************
*
*
*
* UEInformationRequest message
*
*
*
*******************************************************************************/
void rrc::handle_ue_info_request(const ue_info_request_r9_s& request)
{
logger.debug("Preparing UEInformationResponse message");
ul_dcch_msg_s ul_dcch_msg;
ue_info_resp_r9_ies_s* resp =
&ul_dcch_msg.msg.set_c1().set_ue_info_resp_r9().crit_exts.set_c1().set_ue_info_resp_r9();
ul_dcch_msg.msg.c1().ue_info_resp_r9().rrc_transaction_id = transaction_id;
// if rach-ReportReq is set to true, set the contents of the rach-Report in the UEInformationResponse message as
// follows
if (request.crit_exts.c1().ue_info_request_r9().rach_report_req_r9) {
// todo...
}
// Include rlf-Report if rlf-ReportReq is set to true
if (request.crit_exts.c1().ue_info_request_r9().rlf_report_req_r9 && var_rlf_report.has_info()) {
resp->rlf_report_r9_present = true;
resp->rlf_report_r9 = var_rlf_report.get_report();
// fixme: should be cleared upon successful delivery
var_rlf_report.clear();
}
send_ul_dcch_msg(srb_to_lcid(lte_srb::srb1), ul_dcch_msg);
}
/******************************************************************************* /*******************************************************************************
* *
* *

@ -33,6 +33,15 @@ srsran::plmn_id_t meas_cell_eutra::get_plmn(uint32_t idx) const
} }
} }
asn1::rrc::plmn_id_s meas_cell_eutra::get_plmn_asn1(uint32_t idx) const
{
if (idx < sib1.cell_access_related_info.plmn_id_list.size() && has_valid_sib1) {
return sib1.cell_access_related_info.plmn_id_list[idx].plmn_id;
} else {
return {};
}
}
void meas_cell_eutra::set_sib1(const asn1::rrc::sib_type1_s& sib1_) void meas_cell_eutra::set_sib1(const asn1::rrc::sib_type1_s& sib1_)
{ {
sib1 = sib1_; sib1 = sib1_;

@ -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/stack/rrc/rrc_common.h"
namespace srsue {
uint8_t rrc_value_to_range(quant_s quant, const float value)
{
uint8_t range = 0;
if (quant == quant_rsrp) {
if (value < -140) {
range = 0;
} else if (value < -44) {
range = 1u + (uint8_t)(value + 140);
} else {
range = 97;
}
} else {
if (value < -19.5) {
range = 0;
} else if (value < -3) {
range = 1u + (uint8_t)(2 * (value + 19.5));
} else {
range = 34;
}
}
return range;
}
float rrc_range_to_value(quant_s quant, const uint8_t range)
{
float val = 0;
if (quant == quant_rsrp) {
val = -140 + (float)range;
} else {
val = -19.5f + (float)range / 2;
}
return val;
}
} // namespace srsue

@ -130,50 +130,6 @@ void rrc::rrc_meas::run_tti()
meas_cfg.report_triggers(); meas_cfg.report_triggers();
} }
uint8_t rrc::rrc_meas::value_to_range(const report_cfg_eutra_s::trigger_quant_opts::options quant, const float value)
{
uint8_t range = 0;
switch (quant) {
case report_cfg_eutra_s::trigger_quant_opts::rsrp:
if (value < -140) {
range = 0;
} else if (value < -44) {
range = 1u + (uint8_t)(value + 140);
} else {
range = 97;
}
break;
case report_cfg_eutra_s::trigger_quant_opts::rsrq:
if (value < -19.5) {
range = 0;
} else if (value < -3) {
range = 1u + (uint8_t)(2 * (value + 19.5));
} else {
range = 34;
}
break;
default:
break;
}
return range;
}
float rrc::rrc_meas::range_to_value(const report_cfg_eutra_s::trigger_quant_opts::options quant, const uint8_t range)
{
float val = 0;
switch (quant) {
case report_cfg_eutra_s::trigger_quant_opts::rsrp:
val = -140 + (float)range;
break;
case report_cfg_eutra_s::trigger_quant_opts::rsrq:
val = -19.5f + (float)range / 2;
break;
default:
break;
}
return val;
}
// For thresholds, the actual value is (field value 156) dBm, except for field value 127, in which case the actual // For thresholds, the actual value is (field value 156) dBm, except for field value 127, in which case the actual
// value is infinity. // value is infinity.
float rrc::rrc_meas::range_to_value_nr(const asn1::rrc::thres_nr_r15_c::types_opts::options type, const uint8_t range) float rrc::rrc_meas::range_to_value_nr(const asn1::rrc::thres_nr_r15_c::types_opts::options type, const uint8_t range)
@ -303,8 +259,8 @@ void rrc::rrc_meas::var_meas_report_list::generate_report_eutra(meas_results_s*
break; break;
} }
rc.pci = (uint16_t)cell.pci; rc.pci = (uint16_t)cell.pci;
rc.meas_result.rsrp_result = value_to_range(report_cfg_eutra_s::trigger_quant_opts::rsrp, rsrp_value); rc.meas_result.rsrp_result = rrc_value_to_range(quant_rsrp, rsrp_value);
rc.meas_result.rsrq_result = value_to_range(report_cfg_eutra_s::trigger_quant_opts::rsrq, rsrq_value); rc.meas_result.rsrq_result = rrc_value_to_range(quant_rsrq, rsrq_value);
logger.info("MEAS: Adding to report neighbour=%d, pci=%d, earfcn=%d, rsrp=%+.1f, rsrq=%+.1f", logger.info("MEAS: Adding to report neighbour=%d, pci=%d, earfcn=%d, rsrp=%+.1f, rsrq=%+.1f",
neigh_list.size(), neigh_list.size(),
@ -448,10 +404,8 @@ void rrc::rrc_meas::var_meas_report_list::generate_report(const uint32_t measId)
meas_results_s* report = &ul_dcch_msg.msg.c1().meas_report().crit_exts.c1().meas_report_r8().meas_results; meas_results_s* report = &ul_dcch_msg.msg.c1().meas_report().crit_exts.c1().meas_report_r8().meas_results;
report->meas_id = (uint8_t)measId; report->meas_id = (uint8_t)measId;
report->meas_result_pcell.rsrp_result = report->meas_result_pcell.rsrp_result = rrc_value_to_range(quant_rsrp, serv_cell->get_rsrp());
value_to_range(report_cfg_eutra_s::trigger_quant_opts::rsrp, serv_cell->get_rsrp()); report->meas_result_pcell.rsrq_result = rrc_value_to_range(quant_rsrq, serv_cell->get_rsrq());
report->meas_result_pcell.rsrq_result =
value_to_range(report_cfg_eutra_s::trigger_quant_opts::rsrq, serv_cell->get_rsrq());
logger.info("MEAS: Generate report MeasId=%d, Pcell rsrp=%f rsrq=%f", logger.info("MEAS: Generate report MeasId=%d, Pcell rsrp=%f rsrq=%f",
report->meas_id, report->meas_id,
@ -805,6 +759,14 @@ void rrc::rrc_meas::var_meas_cfg::eval_triggers_eutra(uint32_t meas_i
float Ofs, float Ofs,
float Ocs) float Ocs)
{ {
auto asn1_quant_convert = [](report_cfg_eutra_s::trigger_quant_e_ q) {
if (q == report_cfg_eutra_s::trigger_quant_opts::rsrp) {
return quant_rsrp;
} else {
return quant_rsrq;
}
};
double hyst = 0.5 * report_cfg.trigger_type.event().hysteresis; double hyst = 0.5 * report_cfg.trigger_type.event().hysteresis;
float Ms = is_rsrp(report_cfg.trigger_quant.value) ? serv_cell->get_rsrp() : serv_cell->get_rsrq(); float Ms = is_rsrp(report_cfg.trigger_quant.value) ? serv_cell->get_rsrp() : serv_cell->get_rsrq();
@ -823,17 +785,21 @@ void rrc::rrc_meas::var_meas_cfg::eval_triggers_eutra(uint32_t meas_i
bool exit_condition = false; bool exit_condition = false;
if (event_id.type() == eutra_event_s::event_id_c_::types::event_a1) { if (event_id.type() == eutra_event_s::event_id_c_::types::event_a1) {
if (event_id.event_a1().a1_thres.type().value == thres_eutra_c::types::thres_rsrp) { if (event_id.event_a1().a1_thres.type().value == thres_eutra_c::types::thres_rsrp) {
thresh = range_to_value(report_cfg.trigger_quant, event_id.event_a1().a1_thres.thres_rsrp()); thresh = rrc_range_to_value(asn1_quant_convert(report_cfg.trigger_quant),
event_id.event_a1().a1_thres.thres_rsrp());
} else { } else {
thresh = range_to_value(report_cfg.trigger_quant, event_id.event_a1().a1_thres.thres_rsrq()); thresh = rrc_range_to_value(asn1_quant_convert(report_cfg.trigger_quant),
event_id.event_a1().a1_thres.thres_rsrq());
} }
enter_condition = Ms - hyst > thresh; enter_condition = Ms - hyst > thresh;
exit_condition = Ms + hyst < thresh; exit_condition = Ms + hyst < thresh;
} else { } else {
if (event_id.event_a2().a2_thres.type() == thres_eutra_c::types::thres_rsrp) { if (event_id.event_a2().a2_thres.type() == thres_eutra_c::types::thres_rsrp) {
thresh = range_to_value(report_cfg.trigger_quant, event_id.event_a2().a2_thres.thres_rsrp()); thresh = rrc_range_to_value(asn1_quant_convert(report_cfg.trigger_quant),
event_id.event_a2().a2_thres.thres_rsrp());
} else { } else {
thresh = range_to_value(report_cfg.trigger_quant, event_id.event_a2().a2_thres.thres_rsrq()); thresh = rrc_range_to_value(asn1_quant_convert(report_cfg.trigger_quant),
event_id.event_a2().a2_thres.thres_rsrq());
} }
enter_condition = Ms + hyst < thresh; enter_condition = Ms + hyst < thresh;
exit_condition = Ms - hyst > thresh; exit_condition = Ms - hyst > thresh;
@ -884,7 +850,7 @@ void rrc::rrc_meas::var_meas_cfg::eval_triggers_eutra(uint32_t meas_i
} else { } else {
range = event_id.event_a4().a4_thres.thres_rsrq(); range = event_id.event_a4().a4_thres.thres_rsrq();
} }
thresh = range_to_value(report_cfg.trigger_quant.value, range); thresh = rrc_range_to_value(asn1_quant_convert(report_cfg.trigger_quant.value), range);
enter_condition = Mn + Ofn + Ocn - hyst > thresh; enter_condition = Mn + Ofn + Ocn - hyst > thresh;
exit_condition = Mn + Ofn + Ocn + hyst < thresh; exit_condition = Mn + Ofn + Ocn + hyst < thresh;
break; break;
@ -899,8 +865,8 @@ void rrc::rrc_meas::var_meas_cfg::eval_triggers_eutra(uint32_t meas_i
} else { } else {
range2 = event_id.event_a5().a5_thres2.thres_rsrq(); range2 = event_id.event_a5().a5_thres2.thres_rsrq();
} }
th1 = range_to_value(report_cfg.trigger_quant.value, range); th1 = rrc_range_to_value(asn1_quant_convert(report_cfg.trigger_quant.value), range);
th2 = range_to_value(report_cfg.trigger_quant.value, range2); th2 = rrc_range_to_value(asn1_quant_convert(report_cfg.trigger_quant.value), range2);
enter_condition = (Ms + hyst < th1) && (Mn + Ofn + Ocn - hyst > th2); enter_condition = (Ms + hyst < th1) && (Mn + Ofn + Ocn - hyst > th2);
exit_condition = (Ms - hyst > th1) && (Mn + Ofn + Ocn + hyst < th2); exit_condition = (Ms - hyst > th1) && (Mn + Ofn + Ocn + hyst < th2);
break; break;
@ -1470,19 +1436,18 @@ void rrc::rrc_meas::var_meas_cfg::log_debug_trigger_value_eutra(const eutra_even
switch (e.type()) { switch (e.type()) {
case eutra_event_s::event_id_c_::types_opts::event_a1: case eutra_event_s::event_id_c_::types_opts::event_a1:
logger.debug("MEAS: A1-threshold=%.1f dBm", logger.debug("MEAS: A1-threshold=%.1f dBm",
range_to_value(report_cfg_eutra_s::trigger_quant_opts::rsrp, e.event_a1().a1_thres.thres_rsrp())); rrc_range_to_value(quant_rsrp, e.event_a1().a1_thres.thres_rsrp()));
break; break;
case eutra_event_s::event_id_c_::types_opts::event_a2: case eutra_event_s::event_id_c_::types_opts::event_a2:
logger.debug("MEAS: A2-threshold=%.1f dBm", logger.debug("MEAS: A2-threshold=%.1f dBm",
range_to_value(report_cfg_eutra_s::trigger_quant_opts::rsrp, e.event_a2().a2_thres.thres_rsrp())); rrc_range_to_value(quant_rsrp, e.event_a2().a2_thres.thres_rsrp()));
break; break;
case eutra_event_s::event_id_c_::types_opts::event_a3: case eutra_event_s::event_id_c_::types_opts::event_a3:
logger.debug("MEAS: A3-offset=%.1f dB", logger.debug("MEAS: A3-offset=%.1f dB", rrc_range_to_value(quant_rsrp, e.event_a3().a3_offset));
range_to_value(report_cfg_eutra_s::trigger_quant_opts::rsrp, e.event_a3().a3_offset));
break; break;
case eutra_event_s::event_id_c_::types_opts::event_a4: case eutra_event_s::event_id_c_::types_opts::event_a4:
logger.debug("MEAS: A4-threshold=%.1f dBm", logger.debug("MEAS: A4-threshold=%.1f dBm",
range_to_value(report_cfg_eutra_s::trigger_quant_opts::rsrp, e.event_a4().a4_thres.thres_rsrp())); rrc_range_to_value(quant_rsrp, e.event_a4().a4_thres.thres_rsrp()));
break; break;
default: default:
logger.debug("MEAS: Unsupported"); logger.debug("MEAS: Unsupported");
@ -1597,7 +1562,7 @@ bool rrc::rrc_meas::var_meas_cfg::parse_meas_config(const meas_cfg_s* cfg, bool
// set the parameter s-Measure within VarMeasConfig to the lowest value of the RSRP ranges indicated by the // set the parameter s-Measure within VarMeasConfig to the lowest value of the RSRP ranges indicated by the
// received value of s-Measure // received value of s-Measure
if (cfg->s_measure) { if (cfg->s_measure) {
s_measure_value = range_to_value(report_cfg_eutra_s::trigger_quant_opts::options::rsrp, cfg->s_measure); s_measure_value = rrc_range_to_value(quant_rsrp, cfg->s_measure);
} }
} }

@ -1656,6 +1656,9 @@ srsran::proc_outcome_t rrc::ho_proc::init(const asn1::rrc::rrc_conn_recfg_s& rrc
rrc_ptr->t304.set(mob_ctrl_info->t304.to_number(), [this](uint32_t tid) { rrc_ptr->timer_expired(tid); }); rrc_ptr->t304.set(mob_ctrl_info->t304.to_number(), [this](uint32_t tid) { rrc_ptr->timer_expired(tid); });
rrc_ptr->t304.run(); rrc_ptr->t304.run();
// Indicate RLF-Report that a new HO has been received
rrc_ptr->var_rlf_report.received_ho_command(rrc_ptr->meas_cells.serving_cell().get_cell_id_bit());
// starting at start synchronising to the DL of the target PCell // starting at start synchronising to the DL of the target PCell
rrc_ptr->set_serving_cell(target_cell, false); rrc_ptr->set_serving_cell(target_cell, false);
Info("Starting cell selection of target cell PCI=%d EARFCN=%d", target_cell.pci, target_cell.earfcn); Info("Starting cell selection of target cell PCI=%d EARFCN=%d", target_cell.pci, target_cell.earfcn);

@ -0,0 +1,136 @@
/**
*
* \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/stack/rrc/rrc_rlf_report.h"
#include "srsue/hdr/stack/rrc/rrc_common.h"
namespace srsue {
void rrc_rlf_report::init(srsran::task_sched_handle task_sched)
{
timer_conn_failure = task_sched.get_unique_timer();
}
// Returns true if VarRLF-Report structure has info available
bool rrc_rlf_report::has_info()
{
return has_event;
}
// Called upon T304 expiry (type == hof) or Detection of radio link failure (type == rlf)
void rrc_rlf_report::set_failure(meas_cell_list<meas_cell_eutra>& meas_cells, failure_type_t type)
{
has_event = true;
// clear the information included in VarRLF-Report, if any
rlf_report = {};
// set the plmn-Identity to the RPLMN
// set the measResultLastServCell to include the RSRP and RSRQ, if available, of the PCell based on
// measurements collected up to the moment the UE detected radio link failure
rlf_report.meas_result_last_serv_cell_r9.rsrp_result_r9 =
rrc_value_to_range(quant_rsrp, meas_cells.serving_cell().get_rsrp());
rlf_report.meas_result_last_serv_cell_r9.rsrq_result_r9 =
rrc_value_to_range(quant_rsrq, meas_cells.serving_cell().get_rsrq());
rlf_report.meas_result_last_serv_cell_r9.rsrq_result_r9_present = true;
// set the measResultNeighCells to include the best measured cells, other than the PCell, ordered such that
// the best cell is listed first, and based on measurements collected up to the moment the UE detected radio
// link failure
if (meas_cells.nof_neighbours() > 0) {
rlf_report.meas_result_neigh_cells_r9_present = true;
rlf_report.meas_result_neigh_cells_r9.meas_result_list_eutra_r9_present = true;
rlf_report.meas_result_neigh_cells_r9.meas_result_list_eutra_r9.clear();
meas_cells.sort_neighbour_cells();
// It is not clear how the sorting and grouping of cells per frequency must be done.
// We use a separate MeasResultList2EUTRA-r9 struct for each pci/frequency pair
for (const auto& f : meas_cells) {
meas_result2_eutra_r9_s meas2 = {};
meas2.carrier_freq_r9 = f->get_earfcn();
meas_result_eutra_s meas = {};
meas.pci = f->get_pci();
meas.meas_result.rsrp_result_present = true;
meas.meas_result.rsrq_result_present = true;
meas.meas_result.rsrp_result = rrc_value_to_range(quant_rsrp, f->get_rsrp());
meas.meas_result.rsrq_result = rrc_value_to_range(quant_rsrq, f->get_rsrq());
meas2.meas_result_list_r9.push_back(meas);
rlf_report.meas_result_neigh_cells_r9.meas_result_list_eutra_r9.push_back(meas2);
}
}
// set the failedPCellId to the global cell identity, if available, and otherwise to the physical cell identity and
// carrier frequency of the PCell where radio link failure is detected;
rlf_report.failed_pcell_id_r10.set_present(true);
if (meas_cells.serving_cell().has_sib1()) {
rlf_report.failed_pcell_id_r10->set_cell_global_id_r10().cell_id = meas_cells.serving_cell().get_cell_id_bit();
rlf_report.failed_pcell_id_r10->cell_global_id_r10().plmn_id = meas_cells.serving_cell().get_plmn_asn1(0);
} else {
rlf_report.failed_pcell_id_r10->set_pci_arfcn_r10();
rlf_report.failed_pcell_id_r10->pci_arfcn_r10().pci_r10 = meas_cells.serving_cell().get_pci();
rlf_report.failed_pcell_id_r10->pci_arfcn_r10().carrier_freq_r10 = meas_cells.serving_cell().get_earfcn();
}
// if an RRCConnectionReconfiguration message including the mobilityControlInfo was received before the
// connection failure
if (timer_conn_failure.is_running()) {
timer_conn_failure.stop();
// include previousPCellId and set it to the global cell identity of the PCell where the last
// RRCConnectionReconfiguration including the mobilityControlInfo message was received;
rlf_report.prev_pcell_id_r10.set_present(true);
rlf_report.prev_pcell_id_r10->cell_id = ho_gci;
rlf_report.prev_pcell_id_r10->plmn_id = meas_cells.serving_cell().get_plmn_asn1(0);
// set the timeConnFailure to the elapsed time since reception of the last
// RRCConnectionReconfiguration message including the mobilityControlInfo;
rlf_report.time_conn_fail_r10_present = true;
rlf_report.time_conn_fail_r10 = timer_conn_failure.time_elapsed() / 100; // 1 unit = 100 ms
}
// set the connectionFailureType
rlf_report.conn_fail_type_r10_present = true;
rlf_report.conn_fail_type_r10 =
type == rlf ? rlf_report_r9_s::conn_fail_type_r10_opts::rlf : rlf_report_r9_s::conn_fail_type_r10_opts::hof;
rlf_report.ext = true;
}
void rrc_rlf_report::set_reest_gci(const asn1::fixed_bitstring<28>& gci, const asn1::rrc::plmn_id_s& plmn_id)
{
rlf_report.reest_cell_id_r10.set_present(true);
rlf_report.reest_cell_id_r10->cell_id = gci;
rlf_report.reest_cell_id_r10->plmn_id = plmn_id;
}
void rrc_rlf_report::received_ho_command(const asn1::fixed_bitstring<28>& current_gci)
{
if (timer_conn_failure.is_valid()) {
timer_conn_failure.stop();
timer_conn_failure.run();
ho_gci = current_gci;
}
}
rlf_report_r9_s rrc_rlf_report::get_report()
{
return rlf_report;
}
// Clears VarRLF-Report contents
void rrc_rlf_report::clear()
{
has_event = false;
rlf_report = {};
}
} // namespace srsue

@ -22,6 +22,10 @@ add_executable(rrc_cell_test rrc_cell_test.cc)
target_link_libraries(rrc_cell_test srsue_rrc srsue_upper srsran_pdcp srsran_phy rrc_asn1 rrc_nr_asn1) target_link_libraries(rrc_cell_test srsue_rrc srsue_upper srsran_pdcp srsran_phy rrc_asn1 rrc_nr_asn1)
add_test(rrc_cell_test rrc_cell_test) add_test(rrc_cell_test rrc_cell_test)
add_executable(rrc_rlf_report_test rrc_rlf_report_test.cc)
target_link_libraries(rrc_rlf_report_test srsue_rrc srsue_upper srsran_pdcp srsran_phy rrc_asn1 rrc_nr_asn1)
add_test(rrc_rlf_report_test rrc_rlf_report_test)
add_executable(ue_rrc_nr_test ue_rrc_nr_test.cc) add_executable(ue_rrc_nr_test ue_rrc_nr_test.cc)
target_link_libraries(ue_rrc_nr_test srsue_rrc_nr srsue_upper srsran_common srsran_pdcp srsran_phy rrc_asn1 rrc_nr_asn1) target_link_libraries(ue_rrc_nr_test srsue_rrc_nr srsue_upper srsran_common srsran_pdcp srsran_phy rrc_asn1 rrc_nr_asn1)

@ -0,0 +1,196 @@
/**
*
* \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 "srsran/common/test_common.h"
#include "srsue/hdr/stack/rrc/rrc_cell.h"
#include "srsue/hdr/stack/rrc/rrc_rlf_report.h"
using namespace srsue;
int test_single()
{
srsran::task_scheduler task_sched;
rrc_rlf_report rlf_report;
meas_cell_list<meas_cell_eutra> list{&task_sched};
phy_meas_t pmeas;
pmeas.rsrp = -20;
pmeas.pci = 1;
pmeas.earfcn = 3400;
pmeas.rsrq = -10;
list.add_meas_cell(pmeas);
list.set_serving_cell(phy_cell_t{1, 3400}, false);
rlf_report.set_failure(list, rrc_rlf_report::rlf);
asn1::json_writer jw;
asn1::rrc::rlf_report_r9_s out = rlf_report.get_report();
out.to_json(jw);
printf("test_single: %s\n", jw.to_string().c_str());
TESTASSERT(!out.meas_result_neigh_cells_r9_present);
TESTASSERT(out.meas_result_neigh_cells_r9.meas_result_list_eutra_r9.size() == 0);
TESTASSERT(out.failed_pcell_id_r10.is_present());
TESTASSERT(out.failed_pcell_id_r10->pci_arfcn_r10().pci_r10 == 1);
TESTASSERT(out.failed_pcell_id_r10->pci_arfcn_r10().carrier_freq_r10 = 3400);
TESTASSERT(out.conn_fail_type_r10_present);
TESTASSERT(out.conn_fail_type_r10.value == asn1::rrc::rlf_report_r9_s::conn_fail_type_r10_e_::rlf);
return SRSRAN_SUCCESS;
}
int test_neighbours()
{
srsran::task_scheduler task_sched;
rrc_rlf_report rlf_report;
meas_cell_list<meas_cell_eutra> list{&task_sched};
phy_meas_t pmeas;
pmeas.rsrp = -20;
pmeas.pci = 1;
pmeas.earfcn = 3400;
pmeas.rsrq = -10;
list.add_meas_cell(pmeas);
pmeas.pci = 4;
list.add_meas_cell(pmeas);
pmeas.pci = 6;
list.add_meas_cell(pmeas);
list.set_serving_cell(phy_cell_t{4, 3400}, false);
TESTASSERT(!rlf_report.has_info());
rlf_report.set_failure(list, rrc_rlf_report::hof);
asn1::json_writer jw;
asn1::rrc::rlf_report_r9_s out = rlf_report.get_report();
out.to_json(jw);
printf("test_neighbours: %s\n", jw.to_string().c_str());
TESTASSERT(out.meas_result_neigh_cells_r9_present);
TESTASSERT(out.meas_result_neigh_cells_r9.meas_result_list_eutra_r9_present);
TESTASSERT(out.meas_result_neigh_cells_r9.meas_result_list_eutra_r9.size() == 2);
TESTASSERT(out.meas_result_neigh_cells_r9.meas_result_list_eutra_r9[0].carrier_freq_r9 = 3400);
TESTASSERT(out.meas_result_neigh_cells_r9.meas_result_list_eutra_r9[0].meas_result_list_r9[0].pci == 1);
TESTASSERT(out.meas_result_neigh_cells_r9.meas_result_list_eutra_r9[1].carrier_freq_r9 = 3400);
TESTASSERT(out.meas_result_neigh_cells_r9.meas_result_list_eutra_r9[1].meas_result_list_r9[0].pci == 6);
TESTASSERT(out.failed_pcell_id_r10.is_present());
TESTASSERT(out.failed_pcell_id_r10->pci_arfcn_r10().pci_r10 == 4);
TESTASSERT(out.failed_pcell_id_r10->pci_arfcn_r10().carrier_freq_r10 = 3400);
TESTASSERT(out.conn_fail_type_r10_present);
TESTASSERT(out.conn_fail_type_r10.value == asn1::rrc::rlf_report_r9_s::conn_fail_type_r10_e_::hof);
TESTASSERT(rlf_report.has_info());
return SRSRAN_SUCCESS;
}
int test_reest()
{
srsran::task_scheduler task_sched;
rrc_rlf_report rlf_report;
meas_cell_list<meas_cell_eutra> list{&task_sched};
phy_meas_t pmeas;
pmeas.rsrp = -20;
pmeas.pci = 1;
pmeas.earfcn = 3400;
pmeas.rsrq = -10;
list.add_meas_cell(pmeas);
pmeas.pci = 4;
list.add_meas_cell(pmeas);
pmeas.pci = 6;
list.add_meas_cell(pmeas);
list.set_serving_cell(phy_cell_t{4, 3400}, false);
TESTASSERT(!rlf_report.has_info());
rlf_report.set_failure(list, rrc_rlf_report::hof);
rlf_report.set_reest_gci(list.serving_cell().get_cell_id_bit(), list.serving_cell().get_plmn_asn1(0));
asn1::json_writer jw;
asn1::rrc::rlf_report_r9_s out = rlf_report.get_report();
out.to_json(jw);
printf("test_reest: %s\n", jw.to_string().c_str());
TESTASSERT(out.meas_result_neigh_cells_r9_present);
TESTASSERT(out.meas_result_neigh_cells_r9.meas_result_list_eutra_r9_present);
TESTASSERT(out.failed_pcell_id_r10.is_present());
TESTASSERT(out.conn_fail_type_r10_present);
TESTASSERT(out.conn_fail_type_r10.value == asn1::rrc::rlf_report_r9_s::conn_fail_type_r10_e_::hof);
TESTASSERT(out.reest_cell_id_r10.is_present());
TESTASSERT(rlf_report.has_info());
return SRSRAN_SUCCESS;
}
int test_ho()
{
srsran::task_scheduler task_sched;
rrc_rlf_report rlf_report;
meas_cell_list<meas_cell_eutra> list{&task_sched};
rlf_report.init(&task_sched);
phy_meas_t pmeas;
pmeas.rsrp = -20;
pmeas.pci = 1;
pmeas.earfcn = 3400;
pmeas.rsrq = -10;
list.add_meas_cell(pmeas);
pmeas.pci = 4;
list.add_meas_cell(pmeas);
pmeas.pci = 6;
list.add_meas_cell(pmeas);
list.set_serving_cell(phy_cell_t{4, 3400}, false);
TESTASSERT(!rlf_report.has_info());
rlf_report.received_ho_command(list.serving_cell().get_cell_id_bit());
for (int i = 0; i < 1000; i++) {
task_sched.tic();
task_sched.run_pending_tasks();
}
rlf_report.set_failure(list, rrc_rlf_report::hof);
rlf_report.set_reest_gci(list.serving_cell().get_cell_id_bit(), list.serving_cell().get_plmn_asn1(0));
asn1::json_writer jw;
asn1::rrc::rlf_report_r9_s out = rlf_report.get_report();
out.to_json(jw);
printf("test_ho: %s\n", jw.to_string().c_str());
TESTASSERT(out.meas_result_neigh_cells_r9_present);
TESTASSERT(out.meas_result_neigh_cells_r9.meas_result_list_eutra_r9_present);
TESTASSERT(out.failed_pcell_id_r10.is_present());
TESTASSERT(out.conn_fail_type_r10_present);
TESTASSERT(out.conn_fail_type_r10.value == asn1::rrc::rlf_report_r9_s::conn_fail_type_r10_e_::hof);
TESTASSERT(out.reest_cell_id_r10.is_present());
TESTASSERT(rlf_report.has_info());
return SRSRAN_SUCCESS;
}
int main()
{
TESTASSERT(test_single() == SRSRAN_SUCCESS);
TESTASSERT(test_neighbours() == SRSRAN_SUCCESS);
TESTASSERT(test_reest() == SRSRAN_SUCCESS);
TESTASSERT(test_ho() == SRSRAN_SUCCESS);
printf("Success\n");
return SRSRAN_SUCCESS;
}
Loading…
Cancel
Save