Commit 97dee1ac authored by Noemi Giustini's avatar Noemi Giustini

Add MR.NRScSSSINR metric

Implement MR.NRScSSSINR (3GPP TS 28.552 §5.1.1.32): distribution of the NR
serving-cell SS-SINR reported by UEs. Level L maps to (L-46)/2 dB (0.5 dB
steps, range -23..+40.5 dB) per TS 38.133 §10.1.16.

This is the RRC serving-cell SS-SINR (TS 38.331 Measurement Report), so it
is collected at RRC and kept as a per-cell RRC statistic.

- ran_func_kpm.c: introduce kpm_node_meas_cu[] with MR.NRScSSSINR; add it to
  kpm_node_meas_gnb[]; wire kpm_node_meas_cu into the ran_def_kpm table for
  the CU and CU-CP rows.
- ran_func_kpm_subs.c: add fill_MR_NRScSSSINR(); distBinX (SINR level) is
  0-based on the wire (valid range 0..127) and used directly as the array
  index, returning RC.nrrrc[0]->ss_sinr_cell_dist[bin]; requests without
  distBinX yield NO_VALUE; add dispatch entry to lst_measure[].
- nr_rrc_defs.h: add ss_sinr_cell_dist[128] to gNB_RRC_INST.
- rrc_gNB.c: add nr_rrc_count_ss_sinr_dist(); it reads the serving-cell SINR
  of a periodic Measurement Report and increments the histogram. It is
  invoked from rrc_gNB_process_MeasurementReport() on the report itself,
  before process_Periodical_Measurement_Report() consumes it, so the latter
  keeps its original signature. It is always compiled: counting is harmless
  when the E2 agent is disabled.

Advertised by CU, CU-CP, and monolithic gNB node types.
Signed-off-by: default avatarNoemi Giustini <giustini.n@northeastern.edu>
parent 1ba5150f
......@@ -445,10 +445,16 @@ static const char* kpm_node_meas_du[] = {
NULL,
};
static const char* kpm_node_meas_cu[] = {
"MR.NRScSSSINR",
NULL,
};
static const char* kpm_node_meas_gnb[] = {
"CARR.PDSCHMCSDist",
"CARR.PUSCHMCSDist",
"L1M.SS-RSRP",
"MR.NRScSSSINR",
NULL,
};
......@@ -486,11 +492,11 @@ static const meas_list ran_def_kpm[END_NGRAN_NODE_TYPE][END_RIC_SERVICE_REPORT]
{kpm_node_meas_gnb, NULL, NULL, kpm_meas_gnb, NULL},
{NULL, NULL, NULL, NULL, NULL},
{NULL, NULL, NULL, NULL, NULL},
{NULL, NULL, NULL, kpm_meas_cuup, NULL}, // at the moment, for CU, we use the same function as for CU-UP
{kpm_node_meas_cu, NULL, NULL, kpm_meas_cuup, NULL},
{NULL, NULL, NULL, NULL, NULL},
{kpm_node_meas_du, NULL, NULL, kpm_meas_du, NULL},
{NULL, NULL, NULL, NULL, NULL},
{NULL, NULL, NULL, NULL, NULL}, // at the moment, no measurement is implemented in CU-CP
{kpm_node_meas_cu, NULL, NULL, NULL, NULL},
{NULL, NULL, NULL, kpm_meas_cuup, NULL}
};
......
......@@ -6,6 +6,8 @@
#include <search.h>
#include "openair2/RRC/NR/rrc_gNB_UE_context.h"
e2_node_level_stats_t cp_node_level_stats(const e2_node_level_stats_t *src)
{
e2_node_level_stats_t dst = {
......@@ -130,6 +132,34 @@ static meas_record_lst_t fill_L1M_SS_RSRP(const label_info_lst_t label,
return meas_record;
}
/* MR.NRScSSSINR — 3GPP TS 28.552 - section 5.1.1.32 */
static meas_record_lst_t fill_MR_NRScSSSINR(const label_info_lst_t label,
__attribute__((unused)) uint32_t gran_period_ms,
__attribute__((unused)) cudu_ue_info_pair_t ue_info,
__attribute__((unused)) const size_t ue_idx,
__attribute__((unused)) e2_node_level_stats_t* node_stats)
{
meas_record_lst_t meas_record = {0};
if (label.distBinX == NULL) {
printf("[E2 AGENT][E2SM-KPM] MR.NRScSSSINR requested without distBinX label; "
"TS 28.552 5.1.1.32 is a distribution with no aggregate value, reporting NO_VALUE\n");
meas_record.value = NO_VALUE_MEAS_VALUE;
return meas_record;
}
if (*label.distBinX > NR_KPM_SS_SINR_NB_LEVELS - 1) {
printf("[E2 AGENT][E2SM-KPM] MR.NRScSSSINR: distBinX %u out of range [0..127], reporting NO_VALUE\n", *label.distBinX);
meas_record.value = NO_VALUE_MEAS_VALUE;
return meas_record;
}
const uint32_t bin = *label.distBinX;
meas_record.value = INTEGER_MEAS_VALUE;
meas_record.int_val = RC.nrrrc[0]->ss_sinr_cell_dist[bin];
return meas_record;
}
#if defined (NGRAN_GNB_DU)
static uldlcounter_t last_rlc_pdu_total_bytes[MAX_MOBILES_PER_GNB] = {0};
static uldlcounter_t last_total_prbs[MAX_MOBILES_PER_GNB] = {0};
......@@ -328,6 +358,7 @@ static kv_measure_t lst_measure[] = {
{.key = "DRB.PdcpSduVolumeDL", .value = fill_DRB_PdcpSduVolumeDL },
{.key = "DRB.PdcpSduVolumeUL", .value = fill_DRB_PdcpSduVolumeUL },
{.key = "L1M.SS-RSRP", .value = fill_L1M_SS_RSRP },
{.key = "MR.NRScSSSINR", .value = fill_MR_NRScSSSINR },
#if defined (NGRAN_GNB_DU)
{.key = "DRB.RlcSduDelayDl", .value = fill_DRB_RlcSduDelayDl },
{.key = "DRB.UEThpDl", .value = fill_DRB_UEThpDl },
......
......@@ -104,6 +104,7 @@ From 3GPP TS 28.552, we support the following list:
* `CARR.PDSCHMCSDist`
* `CARR.PUSCHMCSDist`
* `L1M.SS-RSRP`
* `MR.NRScSSSINR`
From `O-RAN.WG3.E2SM-KPM-version` specification, we implemented:
* REPORT Service Style 4 ("Common condition-based, UE-level" - section 7.4.5) - fetch above measurements per each UE based on the common S-NSSAI `(1, 0xffffff)` condition
......
......@@ -599,6 +599,9 @@ typedef struct sib2_config_s {
bool deriveSSB_IndexFromCell;
} sib2_config_t;
/* MR.NRScSSSINR histogram dimension (3GPP TS 28.552 §5.1.1.32). */
#define NR_KPM_SS_SINR_NB_LEVELS 128 /* SS-SINR report level: 0..127, TS 38.133 Table 10.1.16.1-1 */
//---NR---(completely change)---------------------
typedef struct gNB_RRC_INST_s {
......@@ -645,6 +648,10 @@ typedef struct gNB_RRC_INST_s {
// PDCP configuration parameters loaded during startup
nr_pdcp_configuration_t pdcp_config;
nr_rlc_configuration_t rlc_config;
/// cell-wide NR serving-cell SS-SINR distribution, see 28.552 5.1.1.32
/// 0-127 SS-SINR report level (TS 38.133)
uint32_t ss_sinr_cell_dist[NR_KPM_SS_SINR_NB_LEVELS];
} gNB_RRC_INST;
/** Forward declaration for UE log macros */
......
......@@ -1633,6 +1633,27 @@ fallback_rrc_setup:
return;
}
static void nr_rrc_count_ss_sinr_dist(gNB_RRC_INST *rrc, const NR_MeasResults_t *mr)
{
if (rrc == NULL || mr == NULL)
return;
if (mr->measResultServingMOList.list.count == 0 || mr->measResultServingMOList.list.array == NULL)
return;
for (int i = 0; i < mr->measResultServingMOList.list.count; i++) {
const NR_MeasResultServMO_t *serv_mo = mr->measResultServingMOList.list.array[i];
if (serv_mo == NULL)
continue;
const struct NR_MeasResultNR__measResult__cellResults *cr =
&serv_mo->measResultServingCell.measResult.cellResults;
if (cr->resultsSSB_Cell == NULL || cr->resultsSSB_Cell->sinr == NULL)
continue;
const long encoded = *cr->resultsSSB_Cell->sinr;
if (encoded >= 0 && encoded < NR_KPM_SS_SINR_NB_LEVELS)
rrc->ss_sinr_cell_dist[encoded]++;
}
}
static void process_Periodical_Measurement_Report(gNB_RRC_UE_t *ue_ctxt, NR_MeasurementReport_t *measurementReport)
{
ASN_STRUCT_FREE(asn_DEF_NR_MeasResults, ue_ctxt->measResults);
......@@ -1815,8 +1836,11 @@ static void rrc_gNB_process_MeasurementReport(gNB_RRC_INST *rrc, gNB_RRC_UE_t *U
return;
}
if (report_config->choice.reportConfigNR->reportType.present == NR_ReportConfigNR__reportType_PR_periodical)
return process_Periodical_Measurement_Report(UE, measurementReport);
if (report_config->choice.reportConfigNR->reportType.present == NR_ReportConfigNR__reportType_PR_periodical) {
nr_rrc_count_ss_sinr_dist(rrc, &measurementReport->criticalExtensions.choice.measurementReport->measResults);
process_Periodical_Measurement_Report(UE, measurementReport);
return;
}
if (report_config->choice.reportConfigNR->reportType.present == NR_ReportConfigNR__reportType_PR_eventTriggered)
return process_Event_Based_Measurement_Report(rrc, UE, report_config->choice.reportConfigNR, measurementReport);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment