Prepare Measurement Configuration according to neighbour measurement configuration
Neighbor configuration can be given by gNB.conf get_MeasConfig function is extended as it will prepare A2 / A3 Report Configs. Single Meas Obj is used for all. rrc_gNB_process_MeasurementReport function is extended to process A2 / A3 measurement events. helper functions are written to fetch neighbour cell informations from sequence containers. (get_neighbour_cell_information, get_neighbour_config)
This commit is contained in:
committed by
Robert Schmidt
parent
cec6b8925a
commit
c51b2a64fb
@@ -736,7 +736,7 @@ int do_RRCReconfiguration(const gNB_RRC_UE_t *UE,
|
||||
|
||||
dl_dcch_msg.message.choice.c1->choice.rrcReconfiguration->criticalExtensions.choice.rrcReconfiguration = ie;
|
||||
|
||||
if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) {
|
||||
if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
|
||||
xer_fprint(stdout, &asn_DEF_NR_DL_DCCH_Message, (void *)&dl_dcch_msg);
|
||||
}
|
||||
|
||||
@@ -1093,15 +1093,180 @@ int do_RRCReestablishmentComplete(uint8_t *buffer, size_t buffer_size, int64_t r
|
||||
return((enc_rval.encoded+7)/8);
|
||||
}
|
||||
|
||||
NR_MeasConfig_t *get_defaultMeasConfig(const NR_MeasTiming_t *mt, int band, int scs)
|
||||
static NR_ReportConfigToAddMod_t *prepare_periodic_event_report(const nr_per_event_t *per_event)
|
||||
{
|
||||
DevAssert(mt != NULL && mt->frequencyAndTiming != NULL);
|
||||
const struct NR_MeasTiming__frequencyAndTiming *ft = mt->frequencyAndTiming;
|
||||
const NR_SSB_MTC_t *ssb_mtc = &ft->ssb_MeasurementTimingConfiguration;
|
||||
NR_ReportConfigToAddMod_t *rc = calloc(1, sizeof(*rc));
|
||||
rc->reportConfigId = 1;
|
||||
rc->reportConfig.present = NR_ReportConfigToAddMod__reportConfig_PR_reportConfigNR;
|
||||
|
||||
NR_PeriodicalReportConfig_t *prc = calloc(1, sizeof(*prc));
|
||||
prc->rsType = NR_NR_RS_Type_ssb;
|
||||
prc->reportInterval = NR_ReportInterval_ms1024;
|
||||
prc->reportAmount = NR_PeriodicalReportConfig__reportAmount_infinity;
|
||||
prc->reportQuantityCell.rsrp = true;
|
||||
prc->reportQuantityCell.rsrq = true;
|
||||
prc->reportQuantityCell.sinr = true;
|
||||
prc->reportQuantityRS_Indexes = calloc(1, sizeof(*prc->reportQuantityRS_Indexes));
|
||||
prc->reportQuantityRS_Indexes->rsrp = true;
|
||||
prc->reportQuantityRS_Indexes->rsrq = true;
|
||||
prc->reportQuantityRS_Indexes->sinr = true;
|
||||
asn1cCallocOne(prc->maxNrofRS_IndexesToReport, per_event->maxReportCells);
|
||||
prc->maxReportCells = per_event->maxReportCells;
|
||||
prc->includeBeamMeasurements = per_event->includeBeamMeasurements;
|
||||
|
||||
NR_ReportConfigNR_t *rcnr = calloc(1, sizeof(*rcnr));
|
||||
rcnr->reportType.present = NR_ReportConfigNR__reportType_PR_periodical;
|
||||
rcnr->reportType.choice.periodical = prc;
|
||||
|
||||
rc->reportConfig.choice.reportConfigNR = rcnr;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static NR_ReportConfigToAddMod_t *prepare_a2_event_report(const nr_a2_event_t *a2_event)
|
||||
{
|
||||
NR_ReportConfigToAddMod_t *rc_A2 = calloc(1, sizeof(*rc_A2));
|
||||
rc_A2->reportConfigId = 2;
|
||||
rc_A2->reportConfig.present = NR_ReportConfigToAddMod__reportConfig_PR_reportConfigNR;
|
||||
NR_EventTriggerConfig_t *etrc_A2 = calloc(1, sizeof(*etrc_A2));
|
||||
etrc_A2->eventId.present = NR_EventTriggerConfig__eventId_PR_eventA2;
|
||||
etrc_A2->eventId.choice.eventA2 = calloc(1, sizeof(*etrc_A2->eventId.choice.eventA2));
|
||||
etrc_A2->eventId.choice.eventA2->a2_Threshold.present = NR_MeasTriggerQuantity_PR_rsrp;
|
||||
etrc_A2->eventId.choice.eventA2->a2_Threshold.choice.rsrp = a2_event->threshold_RSRP;
|
||||
etrc_A2->eventId.choice.eventA2->reportOnLeave = false;
|
||||
etrc_A2->eventId.choice.eventA2->hysteresis = 0;
|
||||
etrc_A2->eventId.choice.eventA2->timeToTrigger = a2_event->timeToTrigger;
|
||||
etrc_A2->rsType = NR_NR_RS_Type_ssb;
|
||||
etrc_A2->reportInterval = NR_ReportInterval_ms480;
|
||||
etrc_A2->reportAmount = NR_EventTriggerConfig__reportAmount_r4;
|
||||
etrc_A2->reportQuantityCell.rsrp = true;
|
||||
etrc_A2->reportQuantityCell.rsrq = true;
|
||||
etrc_A2->reportQuantityCell.sinr = true;
|
||||
asn1cCallocOne(etrc_A2->maxNrofRS_IndexesToReport, 4);
|
||||
etrc_A2->maxReportCells = 1;
|
||||
etrc_A2->includeBeamMeasurements = false;
|
||||
NR_ReportConfigNR_t *rcnr_A2 = calloc(1, sizeof(*rcnr_A2));
|
||||
rcnr_A2->reportType.present = NR_ReportConfigNR__reportType_PR_eventTriggered;
|
||||
rcnr_A2->reportType.choice.eventTriggered = etrc_A2;
|
||||
rc_A2->reportConfig.choice.reportConfigNR = rcnr_A2;
|
||||
|
||||
return rc_A2;
|
||||
}
|
||||
|
||||
static NR_ReportConfigToAddMod_t *prepare_a3_event_report(const nr_a3_event_t *a3_event)
|
||||
{
|
||||
NR_ReportConfigToAddMod_t *rc_A3 = calloc(1, sizeof(*rc_A3));
|
||||
rc_A3->reportConfigId =
|
||||
a3_event->cell_id == -1
|
||||
? 3
|
||||
: a3_event->cell_id + 4; // 3 is default A3 Report Config ID. So cellId(0) specific Report Config ID starts from 4
|
||||
rc_A3->reportConfig.present = NR_ReportConfigToAddMod__reportConfig_PR_reportConfigNR;
|
||||
NR_EventTriggerConfig_t *etrc_A3 = calloc(1, sizeof(*etrc_A3));
|
||||
etrc_A3->eventId.present = NR_EventTriggerConfig__eventId_PR_eventA3;
|
||||
etrc_A3->eventId.choice.eventA3 = calloc(1, sizeof(*etrc_A3->eventId.choice.eventA3));
|
||||
etrc_A3->eventId.choice.eventA3->a3_Offset.present = NR_MeasTriggerQuantityOffset_PR_rsrp;
|
||||
etrc_A3->eventId.choice.eventA3->a3_Offset.choice.rsrp = a3_event->a3_offset;
|
||||
etrc_A3->eventId.choice.eventA3->reportOnLeave = true;
|
||||
etrc_A3->eventId.choice.eventA3->hysteresis = a3_event->hysteresis;
|
||||
etrc_A3->eventId.choice.eventA3->timeToTrigger = a3_event->timeToTrigger;
|
||||
etrc_A3->rsType = NR_NR_RS_Type_ssb;
|
||||
etrc_A3->reportInterval = NR_ReportInterval_ms1024;
|
||||
etrc_A3->reportAmount = NR_EventTriggerConfig__reportAmount_r4;
|
||||
etrc_A3->reportQuantityCell.rsrp = true;
|
||||
etrc_A3->reportQuantityCell.rsrq = true;
|
||||
etrc_A3->reportQuantityCell.sinr = true;
|
||||
asn1cCallocOne(etrc_A3->maxNrofRS_IndexesToReport, 4);
|
||||
etrc_A3->maxReportCells = 4;
|
||||
etrc_A3->includeBeamMeasurements = false;
|
||||
NR_ReportConfigNR_t *rcnr_A3 = calloc(1, sizeof(*rcnr_A3));
|
||||
rcnr_A3->reportType.present = NR_ReportConfigNR__reportType_PR_eventTriggered;
|
||||
rcnr_A3->reportType.choice.eventTriggered = etrc_A3;
|
||||
rc_A3->reportConfig.choice.reportConfigNR = rcnr_A3;
|
||||
return rc_A3;
|
||||
}
|
||||
|
||||
const nr_a3_event_t *get_a3_configuration(int nr_cellid)
|
||||
{
|
||||
gNB_RRC_INST *rrc = RC.nrrrc[0];
|
||||
nr_measurement_configuration_t *measurementConfiguration = &rrc->measurementConfiguration;
|
||||
if (!measurementConfiguration->a3_event_list)
|
||||
return NULL;
|
||||
|
||||
for (uint8_t i = 0; i < measurementConfiguration->a3_event_list->size; i++) {
|
||||
nr_a3_event_t *a3_event = (nr_a3_event_t *)seq_arr_at(measurementConfiguration->a3_event_list, i);
|
||||
if (a3_event->cell_id == nr_cellid)
|
||||
return a3_event;
|
||||
}
|
||||
|
||||
if (measurementConfiguration->is_default_a3_configuration_exists)
|
||||
return get_a3_configuration(-1);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt,
|
||||
int band,
|
||||
int scs,
|
||||
const nr_measurement_configuration_t *const measurementConfiguration,
|
||||
const seq_arr_t *const neighbourConfiguration)
|
||||
{
|
||||
if (!measurementConfiguration)
|
||||
return NULL;
|
||||
|
||||
if (!measurementConfiguration->a2_event && !measurementConfiguration->per_event && !measurementConfiguration->a3_event_list) {
|
||||
LOG_D(NR_RRC, "NR Measurements are not configured in the conf file\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!measurementConfiguration->a2_event && !measurementConfiguration->per_event && measurementConfiguration->a3_event_list
|
||||
&& !neighbourConfiguration) {
|
||||
LOG_I(NR_RRC, "A2 and Periodical Events are off. A3 Can not be prepared without neighbours!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NR_MeasConfig_t *mc = calloc(1, sizeof(*mc));
|
||||
mc->measObjectToAddModList = calloc(1, sizeof(*mc->measObjectToAddModList));
|
||||
mc->reportConfigToAddModList = calloc(1, sizeof(*mc->reportConfigToAddModList));
|
||||
mc->measIdToAddModList = calloc(1, sizeof(*mc->measIdToAddModList));
|
||||
|
||||
if (measurementConfiguration->per_event) {
|
||||
NR_ReportConfigToAddMod_t *rc_PER = prepare_periodic_event_report(measurementConfiguration->per_event);
|
||||
asn1cSeqAdd(&mc->reportConfigToAddModList->list, rc_PER);
|
||||
}
|
||||
|
||||
if (measurementConfiguration->a2_event) {
|
||||
LOG_D(NR_RRC, "HO LOG: Preparing A2 Event Measurement Configuration!\n");
|
||||
NR_ReportConfigToAddMod_t *rc_A2 = prepare_a2_event_report(measurementConfiguration->a2_event);
|
||||
asn1cSeqAdd(&mc->reportConfigToAddModList->list, rc_A2);
|
||||
}
|
||||
|
||||
if (neighbourConfiguration && measurementConfiguration->a3_event_list && measurementConfiguration->a3_event_list->size > 0) {
|
||||
/* Loop through neighbours and find related A3 configuration
|
||||
If no related A3 but there is default add the default one.
|
||||
If default one added once as a report, no need to add it again && duplication.
|
||||
*/
|
||||
LOG_D(NR_RRC, "HO LOG: Preparing A3 Event Measurement Configuration!\n");
|
||||
bool is_default_a3_added = false;
|
||||
for (uint8_t neighbourIdx = 0; neighbourIdx < neighbourConfiguration->size; neighbourIdx++) {
|
||||
const nr_neighbour_gnb_configuration_t *neighbourCell =
|
||||
(const nr_neighbour_gnb_configuration_t *)seq_arr_at(neighbourConfiguration, neighbourIdx);
|
||||
if (!neighbourCell->isIntraFrequencyNeighbour)
|
||||
continue;
|
||||
|
||||
const nr_a3_event_t *a3Event = get_a3_configuration(neighbourCell->nrcell_id);
|
||||
if (!a3Event || is_default_a3_added)
|
||||
continue;
|
||||
|
||||
if (a3Event->cell_id == -1)
|
||||
is_default_a3_added = true;
|
||||
|
||||
NR_ReportConfigToAddMod_t *rc_A3 = prepare_a3_event_report(a3Event);
|
||||
asn1cSeqAdd(&mc->reportConfigToAddModList->list, rc_A3);
|
||||
}
|
||||
}
|
||||
|
||||
DevAssert(mt != NULL && mt->frequencyAndTiming != NULL);
|
||||
const struct NR_MeasTiming__frequencyAndTiming *ft = mt->frequencyAndTiming;
|
||||
const NR_SSB_MTC_t *ssb_mtc = &ft->ssb_MeasurementTimingConfiguration;
|
||||
|
||||
// Measurement Objects: Specifies what is to be measured. For NR and inter-RAT E-UTRA measurements, this may include
|
||||
// cell-specific offsets, blacklisted cells to be ignored and whitelisted cells to consider for measurements.
|
||||
@@ -1122,62 +1287,48 @@ NR_MeasConfig_t *get_defaultMeasConfig(const NR_MeasTiming_t *mt, int band, int
|
||||
monr1->quantityConfigIndex = 1;
|
||||
monr1->ext1 = calloc(1, sizeof(*monr1->ext1));
|
||||
asn1cCallocOne(monr1->ext1->freqBandIndicatorNR, band);
|
||||
|
||||
if (neighbourConfiguration && measurementConfiguration->a3_event_list) {
|
||||
for (uint8_t nCell = 0; nCell < neighbourConfiguration->size; nCell++) {
|
||||
const nr_neighbour_gnb_configuration_t *neighbourCell =
|
||||
(const nr_neighbour_gnb_configuration_t *)seq_arr_at(neighbourConfiguration, nCell);
|
||||
if (!neighbourCell->isIntraFrequencyNeighbour)
|
||||
continue;
|
||||
|
||||
if (monr1->cellsToAddModList == NULL) {
|
||||
monr1->cellsToAddModList = calloc(1, sizeof(*monr1->cellsToAddModList));
|
||||
}
|
||||
|
||||
NR_CellsToAddMod_t *cell = calloc(1, sizeof(*cell));
|
||||
cell->physCellId = neighbourCell->physicalCellId;
|
||||
ASN_SEQUENCE_ADD(&monr1->cellsToAddModList->list, cell);
|
||||
}
|
||||
}
|
||||
|
||||
mo1->measObject.choice.measObjectNR = monr1;
|
||||
asn1cSeqAdd(&mc->measObjectToAddModList->list, mo1);
|
||||
|
||||
// Reporting Configuration: Specifies how reporting should be done. This could be periodic or event-triggered.
|
||||
NR_ReportConfigToAddMod_t *rc = calloc(1, sizeof(*rc));
|
||||
rc->reportConfigId = 1;
|
||||
rc->reportConfig.present = NR_ReportConfigToAddMod__reportConfig_PR_reportConfigNR;
|
||||
|
||||
NR_PeriodicalReportConfig_t *prc = calloc(1, sizeof(*prc));
|
||||
prc->rsType = NR_NR_RS_Type_ssb;
|
||||
prc->reportInterval = NR_ReportInterval_ms1024;
|
||||
prc->reportAmount = NR_PeriodicalReportConfig__reportAmount_infinity;
|
||||
prc->reportQuantityCell.rsrp = true;
|
||||
prc->reportQuantityCell.rsrq = true;
|
||||
prc->reportQuantityCell.sinr = true;
|
||||
prc->reportQuantityRS_Indexes = calloc(1, sizeof(*prc->reportQuantityRS_Indexes));
|
||||
prc->reportQuantityRS_Indexes->rsrp = true;
|
||||
prc->reportQuantityRS_Indexes->rsrq = true;
|
||||
prc->reportQuantityRS_Indexes->sinr = true;
|
||||
asn1cCallocOne(prc->maxNrofRS_IndexesToReport, 4);
|
||||
prc->maxReportCells = 4;
|
||||
prc->includeBeamMeasurements = true;
|
||||
// Preparation of measId
|
||||
for (uint8_t reportIdx = 0; reportIdx < mc->reportConfigToAddModList->list.count; reportIdx++) {
|
||||
const NR_ReportConfigId_t reportId = mc->reportConfigToAddModList->list.array[reportIdx]->reportConfigId;
|
||||
NR_MeasIdToAddMod_t *measid = calloc(1, sizeof(NR_MeasIdToAddMod_t));
|
||||
measid->measId = reportIdx + 1;
|
||||
measid->reportConfigId = reportId;
|
||||
measid->measObjectId = 1;
|
||||
asn1cSeqAdd(&mc->measIdToAddModList->list, measid);
|
||||
}
|
||||
|
||||
NR_ReportConfigNR_t *rcnr = calloc(1, sizeof(*rcnr));
|
||||
rcnr->reportType.present = NR_ReportConfigNR__reportType_PR_periodical;
|
||||
rcnr->reportType.choice.periodical = prc;
|
||||
|
||||
|
||||
rc->reportConfig.choice.reportConfigNR = rcnr;
|
||||
asn1cSeqAdd(&mc->reportConfigToAddModList->list, rc);
|
||||
|
||||
// Measurement ID: Identifies how to report measurements of a specific object. This is a many-to-many mapping: a
|
||||
// measurement object could have multiple reporting configurations, a reporting configuration could apply to multiple
|
||||
// objects. A unique ID is used for each object-to-report-config association. When UE sends a MeasurementReport
|
||||
// message, a single ID and related measurements are included in the message.
|
||||
mc->measIdToAddModList = calloc(1, sizeof(*mc->measIdToAddModList));
|
||||
NR_MeasIdToAddMod_t *measid = calloc(1, sizeof(*measid));
|
||||
measid->measId = 1;
|
||||
measid->measObjectId = 1;
|
||||
measid->reportConfigId = 1;
|
||||
asn1cSeqAdd(&mc->measIdToAddModList->list, measid);
|
||||
|
||||
// Quantity Configuration: Specifies parameters for layer 3 filtering of measurements. Only after filtering, reporting
|
||||
// criteria are evaluated. The formula used is F_n = (1-a)F_(n-1) + a*M_n, where M is the latest measurement, F is the
|
||||
// filtered measurement, and ais based on configured filter coefficient.
|
||||
mc->quantityConfig = calloc(1, sizeof(*mc->quantityConfig));
|
||||
mc->quantityConfig->quantityConfigNR_List = calloc(1, sizeof(*mc->quantityConfig->quantityConfigNR_List));
|
||||
NR_QuantityConfigNR_t *qcnr3 = calloc(1, sizeof(*qcnr3));
|
||||
asn1cCallocOne(qcnr3->quantityConfigCell.ssb_FilterConfig.filterCoefficientRSRP, NR_FilterCoefficient_fc6);
|
||||
asn1cCallocOne(qcnr3->quantityConfigCell.csi_RS_FilterConfig.filterCoefficientRSRP, NR_FilterCoefficient_fc6);
|
||||
asn1cSeqAdd(&mc->quantityConfig->quantityConfigNR_List->list, qcnr3);
|
||||
NR_QuantityConfigNR_t *qcnr = calloc(1, sizeof(*qcnr));
|
||||
asn1cCallocOne(qcnr->quantityConfigCell.ssb_FilterConfig.filterCoefficientRSRP, NR_FilterCoefficient_fc6);
|
||||
asn1cCallocOne(qcnr->quantityConfigCell.csi_RS_FilterConfig.filterCoefficientRSRP, NR_FilterCoefficient_fc6);
|
||||
asn1cSeqAdd(&mc->quantityConfig->quantityConfigNR_List->list, qcnr);
|
||||
|
||||
return mc;
|
||||
}
|
||||
|
||||
void free_defaultMeasConfig(NR_MeasConfig_t *mc)
|
||||
void free_MeasConfig(NR_MeasConfig_t *mc)
|
||||
{
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MeasConfig, mc);
|
||||
}
|
||||
|
||||
@@ -143,8 +143,13 @@ int do_RRCReestablishment(rrc_gNB_ue_context_t *const ue_context_pP,
|
||||
|
||||
int do_RRCReestablishmentComplete(uint8_t *buffer, size_t buffer_size, int64_t rrc_TransactionIdentifier);
|
||||
|
||||
NR_MeasConfig_t *get_defaultMeasConfig(const NR_MeasTiming_t *mt, int band, int scs);
|
||||
void free_defaultMeasConfig(NR_MeasConfig_t *mc);
|
||||
const nr_a3_event_t *get_a3_configuration(int nr_cellid);
|
||||
NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt,
|
||||
int band,
|
||||
int scs,
|
||||
const nr_measurement_configuration_t *const measurementConfiguration,
|
||||
const seq_arr_t *const neighbourConfiguration);
|
||||
void free_MeasConfig(NR_MeasConfig_t *mc);
|
||||
int do_NR_Paging(uint8_t Mod_id, uint8_t *buffer, uint32_t tmsi);
|
||||
|
||||
#endif /* __RRC_NR_MESSAGES_ASN1_MSG__H__ */
|
||||
|
||||
+187
-10
@@ -141,6 +141,42 @@ static void freeDRBlist(NR_DRB_ToAddModList_t *list)
|
||||
return;
|
||||
}
|
||||
|
||||
const neighbour_cell_configuration_t *get_neighbour_config(int serving_cell_nr_cellid)
|
||||
{
|
||||
const gNB_RRC_INST *rrc = RC.nrrrc[0];
|
||||
seq_arr_t *neighbour_cell_configuration = rrc->neighbour_cell_configuration;
|
||||
if (!neighbour_cell_configuration)
|
||||
return NULL;
|
||||
|
||||
for (int cellIdx = 0; cellIdx < neighbour_cell_configuration->size; cellIdx++) {
|
||||
neighbour_cell_configuration_t *neighbour_config =
|
||||
(neighbour_cell_configuration_t *)seq_arr_at(neighbour_cell_configuration, cellIdx);
|
||||
if (neighbour_config->nr_cell_id == serving_cell_nr_cellid)
|
||||
return neighbour_config;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const nr_neighbour_gnb_configuration_t *get_neighbour_cell_information(int serving_cell_nr_cellid, int neighbour_cell_phy_id)
|
||||
{
|
||||
const gNB_RRC_INST *rrc = RC.nrrrc[0];
|
||||
seq_arr_t *neighbour_cell_configuration = rrc->neighbour_cell_configuration;
|
||||
for (int cellIdx = 0; cellIdx < neighbour_cell_configuration->size; cellIdx++) {
|
||||
neighbour_cell_configuration_t *neighbour_config =
|
||||
(neighbour_cell_configuration_t *)seq_arr_at(neighbour_cell_configuration, cellIdx);
|
||||
if (!neighbour_config)
|
||||
continue;
|
||||
|
||||
for (int neighbourIdx = 0; neighbourIdx < neighbour_config->neighbour_cells->size; neighbourIdx++) {
|
||||
nr_neighbour_gnb_configuration_t *neighbour =
|
||||
(nr_neighbour_gnb_configuration_t *)seq_arr_at(neighbour_config->neighbour_cells, neighbourIdx);
|
||||
if (neighbour != NULL && neighbour->physicalCellId == neighbour_cell_phy_id)
|
||||
return neighbour;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typedef struct deliver_dl_rrc_message_data_s {
|
||||
const gNB_RRC_INST *rrc;
|
||||
f1ap_dl_rrc_message_t *dl_rrc;
|
||||
@@ -504,14 +540,25 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const c
|
||||
DevAssert(du != NULL);
|
||||
f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info;
|
||||
NR_MeasConfig_t *measconfig = NULL;
|
||||
|
||||
if (du->mtc != NULL) {
|
||||
int scs = get_ssb_scs(cell_info);
|
||||
int band = get_dl_band(cell_info);
|
||||
const NR_MeasTimingList_t *mtlist = du->mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming;
|
||||
const NR_MeasTiming_t *mt = mtlist->list.array[0];
|
||||
measconfig = get_defaultMeasConfig(mt, band, scs);
|
||||
const neighbour_cell_configuration_t *neighbour_config = get_neighbour_config(cell_info->nr_cellid);
|
||||
seq_arr_t *neighbour_cells = NULL;
|
||||
if (neighbour_config)
|
||||
neighbour_cells = neighbour_config->neighbour_cells;
|
||||
|
||||
measconfig = get_MeasConfig(mt, band, scs, &rrc->measurementConfiguration, neighbour_cells);
|
||||
}
|
||||
|
||||
if (ue_p->measConfig)
|
||||
free_MeasConfig(ue_p->measConfig);
|
||||
|
||||
ue_p->measConfig = measconfig;
|
||||
|
||||
uint8_t buffer[RRC_BUF_SIZE] = {0};
|
||||
NR_SRB_ToAddModList_t *SRBs = createSRBlist(ue_p, false);
|
||||
NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, false);
|
||||
@@ -527,8 +574,7 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const c
|
||||
measconfig,
|
||||
dedicatedNAS_MessageList,
|
||||
cellGroupConfig);
|
||||
LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size,"[MSG] RRC Reconfiguration\n");
|
||||
free_defaultMeasConfig(measconfig);
|
||||
LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)buffer, size, "[MSG] RRC Reconfiguration\n");
|
||||
freeSRBlist(SRBs);
|
||||
freeDRBlist(DRBs);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToReleaseList, ue_p->DRB_ReleaseList);
|
||||
@@ -1148,14 +1194,9 @@ fallback_rrc_setup:
|
||||
return;
|
||||
}
|
||||
|
||||
static void rrc_gNB_process_MeasurementReport(rrc_gNB_ue_context_t *ue_context, NR_MeasurementReport_t *measurementReport)
|
||||
static void process_Periodical_Measurement_Report(rrc_gNB_ue_context_t *ue_context, NR_MeasurementReport_t *measurementReport)
|
||||
{
|
||||
if (LOG_DEBUGFLAG(DEBUG_ASN1))
|
||||
xer_fprint(stdout, &asn_DEF_NR_MeasurementReport, (void *)measurementReport);
|
||||
|
||||
DevAssert(measurementReport->criticalExtensions.present == NR_MeasurementReport__criticalExtensions_PR_measurementReport
|
||||
&& measurementReport->criticalExtensions.choice.measurementReport != NULL);
|
||||
|
||||
// LOG_I(NR_RRC, "Periodical Event Report! Do Nothing for now...\n");
|
||||
gNB_RRC_UE_t *ue_ctxt = &ue_context->ue_context;
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MeasResults, ue_ctxt->measResults);
|
||||
ue_ctxt->measResults = NULL;
|
||||
@@ -1168,6 +1209,141 @@ static void rrc_gNB_process_MeasurementReport(rrc_gNB_ue_context_t *ue_context,
|
||||
measurementReport->criticalExtensions.choice.measurementReport = NULL;
|
||||
}
|
||||
|
||||
static void process_Event_Based_Measurement_Report(NR_ReportConfigNR_t *report, NR_MeasurementReport_t *measurementReport)
|
||||
{
|
||||
NR_EventTriggerConfig_t *event_triggered = report->reportType.choice.eventTriggered;
|
||||
|
||||
int servingCellRSRP = 0;
|
||||
int neighbourCellRSRP = 0;
|
||||
int servingCellId = -1;
|
||||
|
||||
switch (event_triggered->eventId.present) {
|
||||
case NR_EventTriggerConfig__eventId_PR_eventA2:
|
||||
LOG_I(NR_RRC, "\nHO LOG: Event A2 (Serving becomes worse than threshold)\n");
|
||||
break;
|
||||
|
||||
case NR_EventTriggerConfig__eventId_PR_eventA3: {
|
||||
LOG_I(NR_RRC, "\nHO LOG: Event A3 Report - Neighbour Becomes Better than Serving!\n");
|
||||
const NR_MeasResults_t *measResults = &measurementReport->criticalExtensions.choice.measurementReport->measResults;
|
||||
|
||||
for (int serving_cell_idx = 0; serving_cell_idx < measResults->measResultServingMOList.list.count; serving_cell_idx++) {
|
||||
const NR_MeasResultServMO_t *meas_result_serv_MO = measResults->measResultServingMOList.list.array[serving_cell_idx];
|
||||
servingCellId = *(meas_result_serv_MO->measResultServingCell.physCellId);
|
||||
if (meas_result_serv_MO->measResultServingCell.measResult.cellResults.resultsSSB_Cell) {
|
||||
servingCellRSRP = *(meas_result_serv_MO->measResultServingCell.measResult.cellResults.resultsSSB_Cell->rsrp) - 157;
|
||||
} else {
|
||||
servingCellRSRP = *(meas_result_serv_MO->measResultServingCell.measResult.cellResults.resultsCSI_RS_Cell->rsrp) - 157;
|
||||
}
|
||||
LOG_D(NR_RRC, "Serving Cell RSRP: %d\n", servingCellRSRP);
|
||||
}
|
||||
|
||||
if (measResults->measResultNeighCells == NULL)
|
||||
break;
|
||||
|
||||
if (measResults->measResultNeighCells->present != NR_MeasResults__measResultNeighCells_PR_measResultListNR)
|
||||
break;
|
||||
|
||||
const NR_MeasResultListNR_t *measResultListNR = measResults->measResultNeighCells->choice.measResultListNR;
|
||||
for (int neigh_meas_idx = 0; neigh_meas_idx < measResultListNR->list.count; neigh_meas_idx++) {
|
||||
const NR_MeasResultNR_t *meas_result_neigh_cell = (measResultListNR->list.array[neigh_meas_idx]);
|
||||
const int neighbourCellId = *(meas_result_neigh_cell->physCellId);
|
||||
|
||||
// TS 138 133 Table 10.1.6.1-1: SS-RSRP and CSI-RSRP measurement report mapping
|
||||
const struct NR_MeasResultNR__measResult__cellResults *cellResults = &(meas_result_neigh_cell->measResult.cellResults);
|
||||
|
||||
if (cellResults->resultsSSB_Cell) {
|
||||
neighbourCellRSRP = *(cellResults->resultsSSB_Cell->rsrp) - 157;
|
||||
} else {
|
||||
neighbourCellRSRP = *(cellResults->resultsCSI_RS_Cell->rsrp) - 157;
|
||||
}
|
||||
|
||||
LOG_I(NR_RRC,
|
||||
"HO LOG: Measurement Report has came for the neighbour: %d with RSRP: %d\n",
|
||||
neighbourCellId,
|
||||
neighbourCellRSRP);
|
||||
|
||||
const f1ap_served_cell_info_t *neighbour_cell_du_context = get_cell_information_by_phycellId(neighbourCellId);
|
||||
const f1ap_served_cell_info_t *serving_cell_du_context = get_cell_information_by_phycellId(servingCellId);
|
||||
const nr_neighbour_gnb_configuration_t *neighbour =
|
||||
get_neighbour_cell_information(serving_cell_du_context->nr_cellid, neighbourCellId);
|
||||
// CU does not have f1 connection with neighbour cell context. So check does serving cell has this phyCellId as a
|
||||
// neighbour.
|
||||
if (!neighbour_cell_du_context && neighbour) {
|
||||
// No F1 connection but static neighbour configuration is available
|
||||
const nr_a3_event_t *a3_event_configuration = get_a3_configuration(neighbour->nrcell_id);
|
||||
// Additional check - This part can be modified according to additional cell specific Handover Margin
|
||||
if (a3_event_configuration
|
||||
&& ((a3_event_configuration->a3_offset + a3_event_configuration->hysteresis)
|
||||
< (neighbourCellRSRP - servingCellRSRP))) {
|
||||
LOG_D(NR_RRC, "HO LOG: Trigger N2 HO for the neighbour gnb: %u cell: %lu\n", neighbour->gNB_ID, neighbour->nrcell_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} break;
|
||||
default:
|
||||
LOG_D(NR_RRC, "NR_EventTriggerConfig__eventId_PR_NOTHING or Other event report\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void rrc_gNB_process_MeasurementReport(rrc_gNB_ue_context_t *ue_context, NR_MeasurementReport_t *measurementReport)
|
||||
{
|
||||
LOG_D(NR_RRC, "Process Measurement Report\n");
|
||||
if (LOG_DEBUGFLAG(DEBUG_ASN1))
|
||||
xer_fprint(stdout, &asn_DEF_NR_MeasurementReport, (void *)measurementReport);
|
||||
|
||||
DevAssert(measurementReport->criticalExtensions.present == NR_MeasurementReport__criticalExtensions_PR_measurementReport
|
||||
&& measurementReport->criticalExtensions.choice.measurementReport != NULL);
|
||||
|
||||
gNB_RRC_UE_t *ue_ctxt = &ue_context->ue_context;
|
||||
NR_MeasConfig_t *meas_config = ue_ctxt->measConfig;
|
||||
if (meas_config == NULL) {
|
||||
LOG_I(NR_RRC, "Unexpected Measurement Report from UE with id: %d\n", ue_ctxt->rrc_ue_id);
|
||||
return;
|
||||
}
|
||||
|
||||
NR_MeasurementReport_IEs_t *measurementReport_IEs = measurementReport->criticalExtensions.choice.measurementReport;
|
||||
const NR_MeasId_t measId = measurementReport_IEs->measResults.measId;
|
||||
|
||||
NR_MeasIdToAddMod_t *meas_id_s = NULL;
|
||||
for (int meas_idx = 0; meas_idx < meas_config->measIdToAddModList->list.count; meas_idx++) {
|
||||
if (measId == meas_config->measIdToAddModList->list.array[meas_idx]->measId) {
|
||||
meas_id_s = meas_config->measIdToAddModList->list.array[meas_idx];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (meas_id_s == NULL) {
|
||||
LOG_E(NR_RRC, "Incoming Meas ID with id: %d Can not Found!\n", (int)measId);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_D(NR_RRC, "HO LOG: Meas Id is found: %d\n", (int)meas_id_s->measId);
|
||||
|
||||
struct NR_ReportConfigToAddMod__reportConfig *report_config = NULL;
|
||||
for (int rep_id = 0; rep_id < meas_config->reportConfigToAddModList->list.count; rep_id++) {
|
||||
if (meas_id_s->reportConfigId == meas_config->reportConfigToAddModList->list.array[rep_id]->reportConfigId) {
|
||||
report_config = &meas_config->reportConfigToAddModList->list.array[rep_id]->reportConfig;
|
||||
}
|
||||
}
|
||||
|
||||
if (report_config == NULL) {
|
||||
LOG_E(NR_RRC, "There is no related report configuration for this measId!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (report_config->choice.reportConfigNR->reportType.present == NR_ReportConfigNR__reportType_PR_periodical)
|
||||
return process_Periodical_Measurement_Report(ue_context, measurementReport);
|
||||
|
||||
if (report_config->choice.reportConfigNR->reportType.present != NR_ReportConfigNR__reportType_PR_eventTriggered) {
|
||||
LOG_D(NR_RRC, "Incoming Report Type: %d is not supported! \n", report_config->choice.reportConfigNR->reportType.present);
|
||||
return;
|
||||
}
|
||||
|
||||
process_Event_Based_Measurement_Report(report_config->choice.reportConfigNR, measurementReport);
|
||||
}
|
||||
|
||||
static int handle_rrcReestablishmentComplete(const protocol_ctxt_t *const ctxt_pP,
|
||||
rrc_gNB_ue_context_t *ue_context_p,
|
||||
const NR_RRCReestablishmentComplete_t *reestablishment_complete)
|
||||
@@ -1783,6 +1959,7 @@ static void rrc_delete_ue_data(gNB_RRC_UE_t *UE)
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_UE_NR_Capability, UE->UE_Capability_nr);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->masterCellGroup);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MeasResults, UE->measResults);
|
||||
free_MeasConfig(UE->measConfig);
|
||||
}
|
||||
|
||||
void rrc_remove_ue(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context_p)
|
||||
|
||||
Reference in New Issue
Block a user