UE sends the measurement report for event A2
This commit is contained in:
@@ -785,6 +785,63 @@ int do_RRCSetupComplete(uint8_t *buffer,
|
||||
return((enc_rval.encoded+7)/8);
|
||||
}
|
||||
|
||||
// TODO: This function is only implemented for event A2
|
||||
int do_nrMeasurementReport_SA(NR_MeasurementReport_t *measurementReport,
|
||||
long trigger_to_measid,
|
||||
long trigger_quantity,
|
||||
long rs_type,
|
||||
uint16_t Nid_cell,
|
||||
int rsrp_dBm,
|
||||
uint8_t *buffer,
|
||||
size_t buffer_size)
|
||||
{
|
||||
asn_enc_rval_t enc_rval;
|
||||
NR_UL_DCCH_Message_t ul_dcch_msg;
|
||||
memset((void *)&ul_dcch_msg, 0, sizeof(NR_UL_DCCH_Message_t));
|
||||
|
||||
ul_dcch_msg.message.present = NR_UL_DCCH_MessageType_PR_c1;
|
||||
ul_dcch_msg.message.choice.c1 = CALLOC(1, sizeof(struct NR_UL_DCCH_MessageType__c1));
|
||||
ul_dcch_msg.message.choice.c1->present = NR_UL_DCCH_MessageType__c1_PR_measurementReport;
|
||||
|
||||
memset(measurementReport, 0, sizeof(struct NR_MeasurementReport));
|
||||
ul_dcch_msg.message.choice.c1->choice.measurementReport = measurementReport;
|
||||
measurementReport->criticalExtensions.present = NR_MeasurementReport__criticalExtensions_PR_measurementReport;
|
||||
|
||||
NR_MeasurementReport_IEs_t *measurementReport_ie = CALLOC(1, sizeof(struct NR_MeasurementReport_IEs));
|
||||
measurementReport->criticalExtensions.choice.measurementReport = measurementReport_ie;
|
||||
measurementReport_ie->measResults.measId = trigger_to_measid;
|
||||
|
||||
NR_MeasResultServMO_t *measResultServMo = CALLOC(1, sizeof(struct NR_MeasResultServMO));
|
||||
|
||||
NR_MeasResultNR_t *measResultServingCell = &measResultServMo->measResultServingCell;
|
||||
measResultServingCell->physCellId = CALLOC(1, sizeof(NR_PhysCellId_t));
|
||||
*measResultServingCell->physCellId = Nid_cell;
|
||||
|
||||
struct NR_MeasQuantityResults *active_mq_res = CALLOC(1, sizeof(struct NR_MeasQuantityResults));
|
||||
|
||||
if (trigger_quantity == NR_MeasTriggerQuantityOffset_PR_rsrp) {
|
||||
active_mq_res->rsrp = CALLOC(1, sizeof(NR_RSRP_Range_t));
|
||||
|
||||
*active_mq_res->rsrp = rsrp_dBm + 157;
|
||||
if (rs_type == NR_NR_RS_Type_ssb)
|
||||
measResultServingCell->measResult.cellResults.resultsSSB_Cell = active_mq_res;
|
||||
else
|
||||
measResultServingCell->measResult.cellResults.resultsCSI_RS_Cell = active_mq_res;
|
||||
}
|
||||
|
||||
ASN_SEQUENCE_ADD(&measurementReport_ie->measResults.measResultServingMOList.list, measResultServMo);
|
||||
enc_rval = uper_encode_to_buffer(&asn_DEF_NR_UL_DCCH_Message, NULL, (void *)&ul_dcch_msg, buffer, buffer_size);
|
||||
AssertFatal(enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name, enc_rval.encoded);
|
||||
|
||||
if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
|
||||
xer_fprint(stdout, &asn_DEF_NR_UL_DCCH_Message, (void *)&ul_dcch_msg);
|
||||
}
|
||||
|
||||
LOG_I(NR_RRC, "MeasurementReport Encoded %zd bits (%zd bytes)\n", enc_rval.encoded, (enc_rval.encoded + 7) / 8);
|
||||
|
||||
return ((enc_rval.encoded + 7) / 8);
|
||||
}
|
||||
|
||||
int do_NR_DLInformationTransfer(uint8_t *buffer,
|
||||
size_t buffer_len,
|
||||
uint8_t transaction_id,
|
||||
|
||||
@@ -50,11 +50,13 @@
|
||||
#include "NR_ReestablishmentCause.h"
|
||||
#include "NR_SRB-ToAddModList.h"
|
||||
#include "NR_SecurityConfig.h"
|
||||
#include "NR_MeasurementReport.h"
|
||||
#include "NR_MeasurementTimingConfiguration.h"
|
||||
#include "ds/seq_arr.h"
|
||||
#include "ds/byte_array.h"
|
||||
#include "rrc_messages_types.h"
|
||||
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_configuration.h"
|
||||
#include "common/utils/nr/nr_common.h"
|
||||
struct asn_TYPE_descriptor_s;
|
||||
|
||||
typedef struct {
|
||||
@@ -127,6 +129,15 @@ int do_NR_MeasurementTimingConfiguration(const NR_MeasurementTimingConfiguration
|
||||
|
||||
int do_RRCSetupRequest(uint8_t *buffer, size_t buffer_size, uint8_t *rv, uint64_t fiveG_S_TMSI_part1);
|
||||
|
||||
int do_nrMeasurementReport_SA(NR_MeasurementReport_t *measurementReport,
|
||||
long trigger_to_measid,
|
||||
long trigger_quantity,
|
||||
long rs_type,
|
||||
uint16_t Nid_cell,
|
||||
int rsrp_dBm,
|
||||
uint8_t *buffer,
|
||||
size_t buffer_size);
|
||||
|
||||
int do_NR_RRCReconfigurationComplete_for_nsa(uint8_t *buffer, size_t buffer_size, NR_RRC_TransactionIdentifier_t Transaction_id);
|
||||
|
||||
int do_NR_RRCReconfigurationComplete(uint8_t *buffer, size_t buffer_size, const uint8_t Transaction_id);
|
||||
|
||||
@@ -2277,6 +2277,79 @@ void nr_ue_meas_filtering(rrcPerNB_t *rrc, bool is_neighboring_cell, uint16_t Ni
|
||||
apply_ema(&meas_cell->ss_rsrp_dBm, l3_measurements->ssb_filter_coeff_rsrp, rsrp_dBm);
|
||||
}
|
||||
|
||||
static void nr_ue_check_meas_report(NR_UE_RRC_INST_t *rrc, const uint8_t gnb_index)
|
||||
{
|
||||
rrcPerNB_t *rrcNB = rrc->perNB + gnb_index;
|
||||
l3_measurements_t *l3_measurements = &rrcNB->l3_measurements;
|
||||
|
||||
for (int i = 0; i < MAX_MEAS_CONFIG; i++) {
|
||||
NR_ReportConfigToAddMod_t *report_config = rrcNB->ReportConfig[i];
|
||||
if (report_config == NULL)
|
||||
continue;
|
||||
|
||||
if (report_config->reportConfig.present != NR_ReportConfigToAddMod__reportConfig_PR_reportConfigNR)
|
||||
continue;
|
||||
|
||||
NR_ReportConfigNR_t *report_config_nr = report_config->reportConfig.choice.reportConfigNR;
|
||||
if (report_config_nr->reportType.present != NR_ReportConfigNR__reportType_PR_eventTriggered)
|
||||
continue;
|
||||
|
||||
NR_EventTriggerConfig_t *event_trigger_config = report_config_nr->reportType.choice.eventTriggered;
|
||||
if (event_trigger_config->eventId.present != NR_EventTriggerConfig__eventId_PR_eventA2)
|
||||
continue;
|
||||
|
||||
struct NR_EventTriggerConfig__eventId__eventA2 *event_A2 = event_trigger_config->eventId.choice.eventA2;
|
||||
if (event_A2->a2_Threshold.present != NR_MeasTriggerQuantity_PR_rsrp)
|
||||
continue;
|
||||
|
||||
meas_t *serving_cell = &l3_measurements->serving_cell;
|
||||
int serving_cell_rsrp = INT_MAX;
|
||||
if (serving_cell->ss_rsrp_dBm.init == true) {
|
||||
serving_cell_rsrp = serving_cell->ss_rsrp_dBm.val;
|
||||
} else if (serving_cell->csi_rsrp_dBm.init == true) {
|
||||
serving_cell_rsrp = serving_cell->csi_rsrp_dBm.val;
|
||||
} else {
|
||||
LOG_E(NR_RRC, "There are no RSRP measurements taken for the active cell\n");
|
||||
}
|
||||
|
||||
// TS 38.133 - Table 10.1.6.1-1: SS-RSRP and CSI-RSRP measurement report mapping
|
||||
int rsrp_threshold = event_A2->a2_Threshold.choice.rsrp - 157;
|
||||
int rsrp_hysteresis = event_A2->hysteresis >> 1;
|
||||
|
||||
// TS 38.331 - 5.5.4.3 Event A2 (Serving becomes worse than threshold)
|
||||
if (serving_cell_rsrp + rsrp_hysteresis < rsrp_threshold) {
|
||||
if (!nr_timer_is_active(&l3_measurements->TA2)) {
|
||||
nr_timer_setup(&l3_measurements->TA2, get_A2_event_time_to_trigger(event_A2->timeToTrigger), 10);
|
||||
nr_timer_start(&l3_measurements->TA2);
|
||||
int report_config_id = report_config->reportConfigId;
|
||||
int meas_id = -1;
|
||||
for (int j = 0; j < MAX_MEAS_ID; j++) {
|
||||
NR_MeasIdToAddMod_t *meas_id_toAddMod = rrcNB->MeasId[j];
|
||||
if (meas_id_toAddMod == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (meas_id_toAddMod->reportConfigId == report_config_id) {
|
||||
meas_id = meas_id_toAddMod->measId;
|
||||
}
|
||||
}
|
||||
AssertFatal(meas_id > 0, "meas_id did not found for report_config_id %i\n", report_config_id);
|
||||
|
||||
l3_measurements->trigger_to_measid = meas_id;
|
||||
l3_measurements->trigger_quantity = event_A2->a2_Threshold.present;
|
||||
l3_measurements->rs_type = event_trigger_config->rsType;
|
||||
|
||||
LOG_W(NR_RRC,
|
||||
"(active_cell_rsrp) %i + (rsrp_hysteresis) %i < (rsrp_threshold) %i\n",
|
||||
serving_cell_rsrp,
|
||||
rsrp_hysteresis,
|
||||
rsrp_threshold);
|
||||
}
|
||||
} else if (nr_timer_is_active(&l3_measurements->TA2) && (serving_cell_rsrp - rsrp_hysteresis > rsrp_threshold)) {
|
||||
nr_timer_stop(&l3_measurements->TA2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nr_rrc_handle_ra_indication(NR_UE_RRC_INST_t *rrc, bool ra_succeeded)
|
||||
{
|
||||
NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants;
|
||||
@@ -2407,6 +2480,7 @@ void *rrc_nrue(void *notUsed)
|
||||
NR_RRC_MAC_MEAS_DATA_IND(msg_p).Nid_cell,
|
||||
NR_RRC_MAC_MEAS_DATA_IND(msg_p).is_csi_meas,
|
||||
NR_RRC_MAC_MEAS_DATA_IND(msg_p).rsrp_dBm - 157);
|
||||
nr_ue_check_meas_report(rrc, NR_RRC_MAC_MEAS_DATA_IND(msg_p).gnb_index);
|
||||
break;
|
||||
|
||||
case NR_RRC_MAC_CCCH_DATA_IND: {
|
||||
@@ -3045,3 +3119,22 @@ void nr_rrc_set_mac_queue(instance_t instance, notifiedFIFO_t *mac_input_nf)
|
||||
NR_UE_RRC_INST_t *rrc = get_NR_UE_rrc_inst(instance);
|
||||
rrc->mac_input_nf = mac_input_nf;
|
||||
}
|
||||
|
||||
void rrc_ue_generate_measurementReport(rrcPerNB_t *rrc, instance_t ue_id)
|
||||
{
|
||||
uint8_t buffer[NR_RRC_BUF_SIZE];
|
||||
NR_MeasurementReport_t measurementReport = {0};
|
||||
l3_measurements_t *l3m = &rrc->l3_measurements;
|
||||
int rsrp_dBm = l3m->rs_type == NR_NR_RS_Type_ssb ? l3m->serving_cell.ss_rsrp_dBm.val : l3m->serving_cell.csi_rsrp_dBm.val;
|
||||
uint8_t size = do_nrMeasurementReport_SA(&measurementReport,
|
||||
l3m->trigger_to_measid,
|
||||
l3m->trigger_quantity,
|
||||
l3m->rs_type,
|
||||
l3m->serving_cell.Nid_cell,
|
||||
rsrp_dBm,
|
||||
buffer,
|
||||
sizeof(buffer));
|
||||
|
||||
int srb_id = 1; // possibly TODO in SRB3 in some cases
|
||||
nr_pdcp_data_req_srb(ue_id, srb_id, 0, size, buffer, deliver_pdu_srb_rlc, NULL);
|
||||
}
|
||||
|
||||
@@ -199,6 +199,7 @@ typedef struct l3_measurements_s {
|
||||
long trigger_to_measid;
|
||||
long trigger_quantity;
|
||||
long rs_type;
|
||||
NR_timer_t TA2;
|
||||
} l3_measurements_t;
|
||||
|
||||
typedef struct rrcPerNB {
|
||||
|
||||
@@ -55,6 +55,8 @@ void nr_rrc_going_to_IDLE(NR_UE_RRC_INST_t *rrc,
|
||||
|
||||
void handle_RRCRelease(NR_UE_RRC_INST_t *rrc);
|
||||
|
||||
void rrc_ue_generate_measurementReport(rrcPerNB_t *rrc, instance_t ue_id);
|
||||
|
||||
void set_rlf_sib1_timers_and_constants(NR_UE_Timers_Constants_t *tac, NR_UE_TimersAndConstants_t *ue_TimersAndConstants);
|
||||
|
||||
/**\brief RRC UE task.
|
||||
@@ -83,6 +85,7 @@ void nr_ue_rrc_timer_trigger(int module_id, int frame, int gnb_id);
|
||||
void handle_t300_expiry(NR_UE_RRC_INST_t *rrc);
|
||||
void handle_t430_expiry(NR_UE_RRC_INST_t *rrc);
|
||||
|
||||
int get_A2_event_time_to_trigger(long time_to_trigger);
|
||||
void reset_rlf_timers_and_constants(NR_UE_Timers_Constants_t *tac);
|
||||
void set_default_timers_and_constants(NR_UE_Timers_Constants_t *tac);
|
||||
void nr_rrc_set_sib1_timers_and_constants(NR_UE_Timers_Constants_t *tac, NR_SIB1_t *sib1);
|
||||
|
||||
@@ -122,6 +122,19 @@ void nr_rrc_SI_timers(NR_UE_RRC_SI_INFO *SInfo)
|
||||
}
|
||||
}
|
||||
|
||||
void handle_meas_timers(NR_UE_RRC_INST_t *rrc)
|
||||
{
|
||||
for (int i = 0; i < NB_CNX_UE; i++) {
|
||||
rrcPerNB_t *nb = &rrc->perNB[i];
|
||||
l3_measurements_t *l3_measurements = &nb->l3_measurements;
|
||||
|
||||
bool ta2_expired = nr_timer_tick(&l3_measurements->TA2);
|
||||
if (ta2_expired && l3_measurements->trigger_quantity > 0) {
|
||||
rrc_ue_generate_measurementReport(nb, rrc->ue_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nr_rrc_handle_timers(NR_UE_RRC_INST_t *rrc)
|
||||
{
|
||||
NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants;
|
||||
@@ -185,6 +198,8 @@ void nr_rrc_handle_timers(NR_UE_RRC_INST_t *rrc)
|
||||
// Spec 38.331 Section 5.2.2.6
|
||||
handle_t430_expiry(rrc);
|
||||
}
|
||||
|
||||
handle_meas_timers(rrc);
|
||||
}
|
||||
|
||||
int nr_rrc_get_T304(long t304)
|
||||
@@ -630,3 +645,43 @@ void reset_rlf_timers_and_constants(NR_UE_Timers_Constants_t *tac)
|
||||
tac->N310_cnt = 0;
|
||||
tac->N311_cnt = 0;
|
||||
}
|
||||
|
||||
int get_A2_event_time_to_trigger(long time_to_trigger)
|
||||
{
|
||||
switch (time_to_trigger) {
|
||||
case NR_TimeToTrigger_ms0:
|
||||
return 0;
|
||||
case NR_TimeToTrigger_ms40:
|
||||
return 40;
|
||||
case NR_TimeToTrigger_ms64:
|
||||
return 64;
|
||||
case NR_TimeToTrigger_ms80:
|
||||
return 80;
|
||||
case NR_TimeToTrigger_ms100:
|
||||
return 100;
|
||||
case NR_TimeToTrigger_ms128:
|
||||
return 128;
|
||||
case NR_TimeToTrigger_ms160:
|
||||
return 160;
|
||||
case NR_TimeToTrigger_ms256:
|
||||
return 256;
|
||||
case NR_TimeToTrigger_ms320:
|
||||
return 320;
|
||||
case NR_TimeToTrigger_ms480:
|
||||
return 480;
|
||||
case NR_TimeToTrigger_ms512:
|
||||
return 512;
|
||||
case NR_TimeToTrigger_ms640:
|
||||
return 640;
|
||||
case NR_TimeToTrigger_ms1024:
|
||||
return 1024;
|
||||
case NR_TimeToTrigger_ms1280:
|
||||
return 1280;
|
||||
case NR_TimeToTrigger_ms2560:
|
||||
return 2560;
|
||||
case NR_TimeToTrigger_ms5120:
|
||||
return 5120;
|
||||
default:
|
||||
AssertFatal(false, "Invalid TimeToTrigger %ld\n", time_to_trigger);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user