diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index 6ab3f58dab..67f0913dc4 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -88,6 +88,8 @@ static inline const char *rnti_types(nr_rnti_type_t rr) #define NR_NUMBER_OF_SYMBOLS_PER_SLOT_EXTENDED_CP 12 #define NR_MAX_NB_LAYERS 4 // 8 +#define BOUNDED_EVAL(a, b, c) (min(c, max(a, b))) + // Since the IQ samples are represented by SQ15 R+I (see https://en.wikipedia.org/wiki/Q_(number_format)) we need to compensate when // calcualting signal energy. Instead of shifting each sample right by 15, we can normalize the result in dB scale once its // calcualted. Signal energy is calculated using RMS^2, where each sample is squared before taking the average of the sum, therefore @@ -175,6 +177,17 @@ typedef struct { uint32_t step; } NR_timer_t; +typedef struct val_init { + int val; + bool init; +} val_init_t; + +typedef struct meas_s { + uint16_t Nid_cell; + val_init_t ss_rsrp_dBm; + val_init_t csi_rsrp_dBm; +} meas_t; + /** * @brief To start a timer * @param timer Timer to be started diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_constants.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_constants.h index 37b661afb9..57292ecee5 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_constants.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_constants.h @@ -20,7 +20,7 @@ #define FAPI_NR_RX_PDU_TYPE_DLSCH 0x03 #define FAPI_NR_DCI_IND 0x04 #define FAPI_NR_RX_PDU_TYPE_RAR 0x05 -#define FAPI_NR_CSIRS_IND 0x06 +#define FAPI_NR_MEAS_IND 0x06 #define FAPI_NR_SIBS_MASK_SIB1 0x1 diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index 64c8dab07e..a9e83758f6 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -49,16 +49,23 @@ typedef enum { NFAPI_NR_FORMAT_0_1_AND_1_1, } nfapi_nr_dci_formats_e; +typedef enum { + NFAPI_NR_CSI_MEAS, + NFAPI_NR_SS_MEAS +} nfapi_nr_meas_type_e; typedef struct { - uint32_t rsrp; - int rsrp_dBm; + uint32_t gNB_index; + uint16_t Nid_cell; + nfapi_nr_meas_type_e meas_type; + bool is_neighboring_cell; + uint8_t rsrp_dBm; uint8_t rank_indicator; uint16_t i1; uint8_t i2; uint8_t cqi; rlm_t radiolink_monitoring; -} fapi_nr_csirs_measurements_t; +} fapi_nr_l1_measurements_t; typedef struct { /// frequency_domain_resource; @@ -145,7 +152,7 @@ typedef struct { fapi_nr_pdsch_pdu_t pdsch_pdu; fapi_nr_ssb_pdu_t ssb_pdu; fapi_nr_sib_pdu_t sib_pdu; - fapi_nr_csirs_measurements_t csirs_measurements; + fapi_nr_l1_measurements_t l1_measurements; }; } fapi_nr_rx_indication_body_t; diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c index 3c9850bd52..825e025308 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c @@ -37,6 +37,7 @@ #include "PHY/phy_extern_nr_ue.h" #include "common/utils/LOG/log.h" #include "PHY/sse_intrin.h" +#include "SCHED_NR_UE/defs.h" #define K1 ((long long int) 512) #define K2 ((long long int) (1024-K1)) @@ -254,6 +255,24 @@ void nr_ue_ssb_rsrp_measurements(PHY_VARS_NR_UE *ue, ue->measurements.ssb_rsrp_dBm[ssb_index], rsrp_db_per_re, ue->measurements.ssb_sinr_dB[ssb_index]); + + // Send SS measurements to MAC + if (!ue->if_inst || !ue->if_inst->dl_indication) + return; + + fapi_nr_l1_measurements_t l1_measurements = { + .gNB_index = proc->gNB_id, + .meas_type = NFAPI_NR_SS_MEAS, + .Nid_cell = ue->frame_parms.Nid_cell, + .is_neighboring_cell = false, + }; + int ssb_rsrp_dBm = ue->measurements.ssb_rsrp_dBm[ssb_index]; + l1_measurements.rsrp_dBm = BOUNDED_EVAL(16, ssb_rsrp_dBm + 157, 113); // TS 38.133 - Table 10.1.6.1-1 + nr_downlink_indication_t dl_indication = {0}; + fapi_nr_rx_indication_t rx_ind = {0}; + nr_fill_dl_indication(&dl_indication, NULL, &rx_ind, proc, ue, NULL); + nr_fill_rx_indication(&rx_ind, FAPI_NR_MEAS_IND, ue, NULL, NULL, 1, proc, &l1_measurements, NULL); + ue->if_inst->dl_indication(&dl_indication); } // This function computes the received noise power diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 295718e22c..4ab72a13f0 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -979,18 +979,24 @@ void nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, } // Send CSI measurements to MAC - fapi_nr_csirs_measurements_t csirs_measurements; - csirs_measurements.rsrp = rsrp; - csirs_measurements.rsrp_dBm = rsrp_dBm; - csirs_measurements.rank_indicator = rank_indicator; - csirs_measurements.i1 = *i1; - csirs_measurements.i2 = *i2; - csirs_measurements.cqi = cqi; - csirs_measurements.radiolink_monitoring = RLM_no_monitoring; // TODO do be activated in case of RLM based on CSI-RS + if (!ue->if_inst || !ue->if_inst->dl_indication) + return; + + fapi_nr_l1_measurements_t l1_measurements = { + .gNB_index = proc->gNB_id, + .meas_type = NFAPI_NR_CSI_MEAS, + .Nid_cell = frame_parms->Nid_cell, + .is_neighboring_cell = false, + .rsrp_dBm = BOUNDED_EVAL(16, rsrp_dBm + 157, 113), // TS 38.133 - Table 10.1.6.1-1 + .rank_indicator = rank_indicator, + .i1 = *i1, + .i2 = *i2, + .cqi = cqi, + .radiolink_monitoring = RLM_no_monitoring, // TODO do be activated in case of RLM based on CSI-RS + }; nr_downlink_indication_t dl_indication; fapi_nr_rx_indication_t rx_ind = {0}; nr_fill_dl_indication(&dl_indication, NULL, &rx_ind, proc, ue, NULL); - nr_fill_rx_indication(&rx_ind, FAPI_NR_CSIRS_IND, ue, NULL, NULL, 1, proc, (void *)&csirs_measurements, NULL); - if (ue->if_inst && ue->if_inst->dl_indication) - ue->if_inst->dl_indication(&dl_indication); + nr_fill_rx_indication(&rx_ind, FAPI_NR_MEAS_IND, ue, NULL, NULL, 1, proc, (void *)&l1_measurements, NULL); + ue->if_inst->dl_indication(&dl_indication); } diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index f683a2098d..25447e4bb4 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -186,8 +186,8 @@ void nr_fill_rx_indication(fapi_nr_rx_indication_t *rx_ind, rx->ssb_pdu.decoded_pdu = false; } } break; - case FAPI_NR_CSIRS_IND: - memcpy(&rx->csirs_measurements, typeSpecific, sizeof(fapi_nr_csirs_measurements_t)); + case FAPI_NR_MEAS_IND: + memcpy(&rx->l1_measurements, typeSpecific, sizeof(fapi_nr_l1_measurements_t)); break; default: break; diff --git a/openair1/SIMULATION/NR_PHY/nr_unitary_common.c b/openair1/SIMULATION/NR_PHY/nr_unitary_common.c index 7aca911b7f..585c5388e4 100644 --- a/openair1/SIMULATION/NR_PHY/nr_unitary_common.c +++ b/openair1/SIMULATION/NR_PHY/nr_unitary_common.c @@ -178,3 +178,12 @@ void *rrc_nrue(void *notUsed) { return NULL; } + +void nr_mac_rrc_meas_ind_ue(module_id_t module_id, + uint32_t gNB_index, + uint16_t Nid_cell, + bool csi_meas, + bool is_neighboring_cell, + uint8_t rsrp_dBm) +{ +} diff --git a/openair2/COMMON/mac_messages_def.h b/openair2/COMMON/mac_messages_def.h index f342444c65..11e8ab6f5e 100644 --- a/openair2/COMMON/mac_messages_def.h +++ b/openair2/COMMON/mac_messages_def.h @@ -62,3 +62,7 @@ MESSAGE_DEF(NR_RRC_MAC_SBCCH_DATA_IND, MESSAGE_PRIORITY_MED_PLUS, NRRrcMacSBc // Message to GNB_APP to update SIB19 satellite position information MESSAGE_DEF(GNB_SAT_POSITION_UPDATE, MESSAGE_PRIORITY_MED, gnb_sat_position_update_t, gnb_sat_position_update) + +// nrUE +MESSAGE_DEF(NR_RRC_MAC_MEAS_DATA_IND, MESSAGE_PRIORITY_MED_PLUS, NRRrcMacMeasDataInd, nr_rrc_mac_meas_data_ind) + diff --git a/openair2/COMMON/mac_messages_types.h b/openair2/COMMON/mac_messages_types.h index f5712b115a..677e1e90b1 100644 --- a/openair2/COMMON/mac_messages_types.h +++ b/openair2/COMMON/mac_messages_types.h @@ -44,6 +44,8 @@ #define NR_RRC_MAC_BCCH_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.nr_rrc_mac_bcch_data_ind #define NR_RRC_MAC_SBCCH_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.nr_rrc_mac_sbcch_data_ind +#define NR_RRC_MAC_MEAS_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.nr_rrc_mac_meas_data_ind + #define RRC_MAC_BCCH_MBMS_DATA_REQ(mSGpTR) (mSGpTR)->ittiMsg.rrc_mac_bcch_mbms_data_req #define RRC_MAC_BCCH_MBMS_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.rrc_mac_bcch_mbms_data_ind @@ -142,6 +144,14 @@ typedef struct NRRrcMacSBcchDataInd_s { uint8_t rsrp; } NRRrcMacSBcchDataInd; +typedef struct NRRrcMacMeasDataInd_s { + uint8_t gnb_index; + uint8_t rsrp_dBm; + uint16_t Nid_cell; + bool is_csi_meas; + bool is_neighboring_cell; +} NRRrcMacMeasDataInd; + typedef struct RrcMacBcchMbmsDataReq_s { uint32_t frame; uint32_t sdu_size; diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index d734870f52..680b5138df 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -594,8 +594,8 @@ typedef struct NR_UE_MAC_INST_s { nr_csi_report_t csi_report_template[MAX_CSI_REPORTCONFIG]; - /// measurements from CSI-RS - fapi_nr_csirs_measurements_t csirs_measurements; + /// measurements from SS or CSI-RS + fapi_nr_l1_measurements_t l1_measurements; //// FAPI-like interface message fapi_nr_ul_config_request_t *ul_config_request; diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index 6d4f025a30..035e59c09c 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -117,10 +117,8 @@ csi_payload_t nr_ue_aperiodic_csi_reporting(NR_UE_MAC_INST_t *mac, dci_field_t c nr_dci_format_t nr_ue_process_dci_indication_pdu(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, fapi_nr_dci_indication_pdu_t *dci); -int8_t nr_ue_process_csirs_measurements(NR_UE_MAC_INST_t *mac, - frame_t frame, - int slot, - fapi_nr_csirs_measurements_t *csirs_measurements); +void nr_ue_process_l1_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, fapi_nr_l1_measurements_t *l1_measurements); + void nr_ue_aperiodic_srs_scheduling(NR_UE_MAC_INST_t *mac, long resource_trigger, int frame, int slot); bool trigger_periodic_scheduling_request(NR_UE_MAC_INST_t *mac, diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c index 3348c6b278..78bfb1021c 100644 --- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c +++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c @@ -302,7 +302,7 @@ void release_mac_configuration(NR_UE_MAC_INST_t *mac, NR_UE_MAC_reset_cause_t ca release_ul_BWP(mac, i); memset(&mac->ssb_measurements, 0, sizeof(mac->ssb_measurements)); - memset(&mac->csirs_measurements, 0, sizeof(mac->csirs_measurements)); + memset(&mac->l1_measurements, 0, sizeof(mac->l1_measurements)); memset(&mac->ul_time_alignment, 0, sizeof(mac->ul_time_alignment)); for (int i = mac->TAG_list.count; i > 0 ; i--) asn_sequence_del(&mac->TAG_list, i - 1, 1); diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index a4362a346e..ab13c9dd07 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -1504,13 +1504,17 @@ nr_dci_format_t nr_ue_process_dci_indication_pdu(NR_UE_MAC_INST_t *mac, frame_t return format; } -int8_t nr_ue_process_csirs_measurements(NR_UE_MAC_INST_t *mac, - frame_t frame, - int slot, - fapi_nr_csirs_measurements_t *csirs_measurements) { - LOG_D(NR_MAC,"(%d.%d) Received CSI-RS measurements\n", frame, slot); - memcpy(&mac->csirs_measurements, csirs_measurements, sizeof(*csirs_measurements)); - return 0; +void nr_ue_process_l1_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, fapi_nr_l1_measurements_t *l1_measurements) +{ + LOG_D(NR_MAC, "(%d.%d) Received CSI-RS measurements\n", frame, slot); + memcpy(&mac->l1_measurements, l1_measurements, sizeof(*l1_measurements)); + bool csi_meas = l1_measurements->meas_type == NFAPI_NR_CSI_MEAS; + nr_mac_rrc_meas_ind_ue(mac->ue_id, + l1_measurements->gNB_index, + l1_measurements->Nid_cell, + csi_meas, + l1_measurements->is_neighboring_cell, + l1_measurements->rsrp_dBm); } static void set_harq_status(NR_UE_MAC_INST_t *mac, @@ -2993,9 +2997,9 @@ static csi_payload_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac, AssertFatal(csi_report, "Couldn't find CSI report with ID %ld\n", csi_reportconfig->reportConfigId); int cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen; int ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen; - int pmi_x1_bitlen = csi_report->csi_meas_bitlen.pmi_x1_bitlen[mac->csirs_measurements.rank_indicator]; - int pmi_x2_bitlen = csi_report->csi_meas_bitlen.pmi_x2_bitlen[mac->csirs_measurements.rank_indicator]; - int cqi_bitlen = csi_report->csi_meas_bitlen.cqi_bitlen[mac->csirs_measurements.rank_indicator]; + int pmi_x1_bitlen = csi_report->csi_meas_bitlen.pmi_x1_bitlen[mac->l1_measurements.rank_indicator]; + int pmi_x2_bitlen = csi_report->csi_meas_bitlen.pmi_x2_bitlen[mac->l1_measurements.rank_indicator]; + int cqi_bitlen = csi_report->csi_meas_bitlen.cqi_bitlen[mac->l1_measurements.rank_indicator]; if (get_softmodem_params()->emulate_l1) { static const uint8_t mcs_to_cqi[] = {0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, @@ -3003,9 +3007,9 @@ static csi_payload_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac, CHECK_INDEX(nr_bler_data, NR_NUM_MCS - 1); int mcs = get_mcs_from_sinr(nr_bler_data, (mac->nr_ue_emul_l1.cqi - 640) * 0.1); CHECK_INDEX(mcs_to_cqi, mcs); - mac->csirs_measurements.rank_indicator = mac->nr_ue_emul_l1.ri; - mac->csirs_measurements.i1 = mac->nr_ue_emul_l1.pmi; - mac->csirs_measurements.cqi = mcs_to_cqi[mcs]; + mac->l1_measurements.rank_indicator = mac->nr_ue_emul_l1.ri; + mac->l1_measurements.i1 = mac->nr_ue_emul_l1.pmi; + mac->l1_measurements.cqi = mcs_to_cqi[mcs]; } int padding_bitlen = 0; @@ -3014,19 +3018,19 @@ static csi_payload_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac, p1_bits = cri_bitlen + ri_bitlen + cqi_bitlen; p2_bits = pmi_x1_bitlen + pmi_x2_bitlen; temp_payload_1 = (0/*mac->csi_measurements.cri*/ << (cqi_bitlen + ri_bitlen)) | - (mac->csirs_measurements.rank_indicator << cqi_bitlen) | - (mac->csirs_measurements.cqi); - temp_payload_2 = (mac->csirs_measurements.i1 << pmi_x2_bitlen) | - mac->csirs_measurements.i2; + (mac->l1_measurements.rank_indicator << cqi_bitlen) | + (mac->l1_measurements.cqi); + temp_payload_2 = (mac->l1_measurements.i1 << pmi_x2_bitlen) | + mac->l1_measurements.i2; } else { p1_bits = nr_get_csi_bitlen(csi_report); padding_bitlen = p1_bits - (cri_bitlen + ri_bitlen + pmi_x1_bitlen + pmi_x2_bitlen + cqi_bitlen); temp_payload_1 = (0/*mac->csi_measurements.cri*/ << (cqi_bitlen + pmi_x2_bitlen + pmi_x1_bitlen + padding_bitlen + ri_bitlen)) | - (mac->csirs_measurements.rank_indicator << (cqi_bitlen + pmi_x2_bitlen + pmi_x1_bitlen + padding_bitlen)) | - (mac->csirs_measurements.i1 << (cqi_bitlen + pmi_x2_bitlen)) | - (mac->csirs_measurements.i2 << (cqi_bitlen)) | - (mac->csirs_measurements.cqi); + (mac->l1_measurements.rank_indicator << (cqi_bitlen + pmi_x2_bitlen + pmi_x1_bitlen + padding_bitlen)) | + (mac->l1_measurements.i1 << (cqi_bitlen + pmi_x2_bitlen)) | + (mac->l1_measurements.i2 << (cqi_bitlen)) | + (mac->l1_measurements.cqi); } temp_payload_1 = reverse_bits(temp_payload_1, p1_bits); @@ -3085,17 +3089,7 @@ static csi_payload_t get_csirs_RSRP_payload(NR_UE_MAC_INST_t *mac, } // TODO: Improvements will be needed to cri_ssbri_bitlen>0 - // TS 38.133 - Table 10.1.6.1-1 - int rsrp_dBm = mac->csirs_measurements.rsrp_dBm; - if (rsrp_dBm < -140) { - temp_payload = 16; - } else if (rsrp_dBm > -44) { - temp_payload = 113; - } else { - temp_payload = mac->csirs_measurements.rsrp_dBm + 157; - } - - temp_payload = reverse_bits(temp_payload, n_bits); + temp_payload = reverse_bits(mac->l1_measurements.rsrp_dBm, n_bits); // rsrp_dBm as in TS 38.133 - Table 10.1.6.1-1 LOG_D(NR_MAC, "cri_ssbri_bitlen = %d\n", cri_ssbri_bitlen); LOG_D(NR_MAC, "rsrp_bitlen = %d\n", rsrp_bitlen); diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c index 21818c68c3..3f765bf6c9 100644 --- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c @@ -1174,13 +1174,11 @@ static void handle_rlm(rlm_t rlm_result, int frame, NR_UE_MAC_INST_t *mac) nr_mac_rrc_sync_ind(mac->ue_id, frame, is_sync); } -static int8_t handle_csirs_measurements(NR_UE_MAC_INST_t *mac, - frame_t frame, - int slot, - fapi_nr_csirs_measurements_t *csirs_measurements) +static int8_t handle_l1_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, fapi_nr_l1_measurements_t *l1_measurements) { - handle_rlm(csirs_measurements->radiolink_monitoring, frame, mac); - return nr_ue_process_csirs_measurements(mac, frame, slot, csirs_measurements); + handle_rlm(l1_measurements->radiolink_monitoring, frame, mac); + nr_ue_process_l1_measurements(mac, frame, slot, l1_measurements); + return 0; } void update_harq_status(NR_UE_MAC_INST_t *mac, uint8_t harq_pid, uint8_t ack_nack) @@ -1316,11 +1314,11 @@ static uint32_t nr_ue_dl_processing(NR_UE_MAC_INST_t *mac, nr_downlink_indicatio } ret_mask |= (handle_dlsch(mac, dl_info, i)) << FAPI_NR_RX_PDU_TYPE_RAR; break; - case FAPI_NR_CSIRS_IND: - ret_mask |= (handle_csirs_measurements(mac, - dl_info->frame, - dl_info->slot, - &rx_indication_body.csirs_measurements)) << FAPI_NR_CSIRS_IND; + case FAPI_NR_MEAS_IND: + ret_mask |= (handle_l1_measurements(mac, + dl_info->frame, + dl_info->slot, + &rx_indication_body.l1_measurements)) << FAPI_NR_MEAS_IND; break; default: break; diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 3ff6aecea9..21ccb1e40f 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -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, diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index dde62d142f..4f13ca2fad 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -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); diff --git a/openair2/RRC/NR_UE/L2_interface_ue.c b/openair2/RRC/NR_UE/L2_interface_ue.c index b751f31670..d6bee2ab10 100644 --- a/openair2/RRC/NR_UE/L2_interface_ue.c +++ b/openair2/RRC/NR_UE/L2_interface_ue.c @@ -37,6 +37,17 @@ typedef uint32_t channel_t; +void nr_mac_rrc_meas_ind_ue(module_id_t module_id, uint32_t gNB_index, uint16_t Nid_cell, bool csi_meas, bool is_neighboring_cell, uint8_t rsrp_dBm) +{ + MessageDef *message_p = itti_alloc_new_message(TASK_MAC_UE, 0, NR_RRC_MAC_MEAS_DATA_IND); + NR_RRC_MAC_MEAS_DATA_IND(message_p).gnb_index = gNB_index; + NR_RRC_MAC_MEAS_DATA_IND(message_p).Nid_cell = Nid_cell; + NR_RRC_MAC_MEAS_DATA_IND(message_p).is_csi_meas = csi_meas; + NR_RRC_MAC_MEAS_DATA_IND(message_p).is_neighboring_cell = is_neighboring_cell; + NR_RRC_MAC_MEAS_DATA_IND(message_p).rsrp_dBm = rsrp_dBm; + itti_send_msg_to_task(TASK_RRC_NRUE, GNB_MODULE_ID_TO_INSTANCE(module_id), message_p); +} + void nr_mac_rrc_sync_ind(const module_id_t module_id, const frame_t frame, const bool in_sync) { MessageDef *message_p = itti_alloc_new_message(TASK_MAC_UE, 0, NR_RRC_MAC_SYNC_IND); diff --git a/openair2/RRC/NR_UE/L2_interface_ue.h b/openair2/RRC/NR_UE/L2_interface_ue.h index daaed50e65..857c110d9e 100644 --- a/openair2/RRC/NR_UE/L2_interface_ue.h +++ b/openair2/RRC/NR_UE/L2_interface_ue.h @@ -37,6 +37,12 @@ void nr_mac_rrc_data_ind_ue(const module_id_t module_id, const channel_t channel, const uint8_t* pduP, const sdu_size_t pdu_len); +void nr_mac_rrc_meas_ind_ue(module_id_t module_id, + uint32_t gNB_index, + uint16_t Nid_cell, + bool csi_meas, + bool is_neighboring_cell, + uint8_t rsrp_dBm); void nr_mac_rrc_inactivity_timer_ind(const module_id_t mod_id); void nr_mac_rrc_msg3_ind(const module_id_t mod_id, const int rnti, bool prepare_payload); void nr_ue_rrc_timer_trigger(int instance, int frame, int gnb_id); diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 52d9ecb50a..7ace2c7a91 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -807,6 +807,9 @@ NR_UE_RRC_INST_t* nr_rrc_init_ue(char* uecap_file, int instance_id, int num_ant_ for (int i = 0; i < NB_CNX_UE; i++) { rrcPerNB_t *ptr = &rrc->perNB[i]; ptr->SInfo = (NR_UE_RRC_SI_INFO){0}; + ptr->l3_measurements = (l3_measurements_t){0}; + ptr->l3_measurements.ssb_filter_coeff_rsrp = 1.0f; + ptr->l3_measurements.csi_RS_filter_coeff_rsrp = 1.0f; init_SI_timers(&ptr->SInfo); } @@ -1663,6 +1666,14 @@ static void handle_meas_reporting_remove(rrcPerNB_t *rrc, int id, NR_UE_Timers_C // TODO stop the periodical reporting timer or timer T321, whichever is running, // and reset the associated information (e.g. timeToTrigger) for this measId nr_timer_stop(&timers->T321); + + l3_measurements_t *l3_measurements = &rrc->l3_measurements; + nr_timer_stop(&l3_measurements->TA2); + nr_timer_stop(&l3_measurements->periodic_report_timer); + + l3_measurements->reports_sent = 0; + l3_measurements->max_reports = 0; + l3_measurements->report_interval_ms = 0; } static void handle_measobj_remove(rrcPerNB_t *rrc, struct NR_MeasObjectToRemoveList *remove_list, NR_UE_Timers_Constants_t *timers) @@ -1814,6 +1825,14 @@ static void handle_quantityconfig(rrcPerNB_t *rrc, NR_QuantityConfig_t *quantity if (!rrc->QuantityConfig[i]) rrc->QuantityConfig[i] = calloc(1, sizeof(*rrc->QuantityConfig[i])); rrc->QuantityConfig[i]->quantityConfigCell = quantityNR->quantityConfigCell; + // TODO: It remains to compute ssb_filter_coeff_rsrp and csi_RS_filter_coeff_rsrp for multiple quantityConfig + // TS 38.331 - 5.5.3.2 Layer 3 filtering + NR_QuantityConfigRS_t *qcc = &quantityNR->quantityConfigCell; + l3_measurements_t *l3_measurements = &rrc->l3_measurements; + if (qcc->ssb_FilterConfig.filterCoefficientRSRP) + l3_measurements->ssb_filter_coeff_rsrp = 1. / pow(2, (*qcc->ssb_FilterConfig.filterCoefficientRSRP) / 4); + if (qcc->csi_RS_FilterConfig.filterCoefficientRSRP) + l3_measurements->csi_RS_filter_coeff_rsrp = 1. / pow(2, (*qcc->csi_RS_FilterConfig.filterCoefficientRSRP) / 4); if (quantityNR->quantityConfigRS_Index) UPDATE_IE(rrc->QuantityConfig[i]->quantityConfigRS_Index, quantityNR->quantityConfigRS_Index, struct NR_QuantityConfigRS); } @@ -2238,6 +2257,146 @@ static int nr_rrc_ue_decode_dcch(NR_UE_RRC_INST_t *rrc, return 0; } +static void apply_ema(val_init_t *vi_rsrp_dBm, float filter_coeff_rsrp, int rsrp_dBm) +{ + int *quant = &vi_rsrp_dBm->val; + bool *meas_init = &vi_rsrp_dBm->init; + float coef = *meas_init ? filter_coeff_rsrp : 1.0f; // if not init, first measurement gets full weight + *quant = (1.0f - coef) * (*quant) + coef * rsrp_dBm; + *meas_init = true; +} + +void nr_ue_meas_filtering(rrcPerNB_t *rrc, bool is_neighboring_cell, uint16_t Nid_cell, bool csi_meas, int rsrp_dBm) +{ + if (is_neighboring_cell) + return; + + l3_measurements_t *l3_measurements = &rrc->l3_measurements; + meas_t *meas_cell = &l3_measurements->serving_cell; + if (meas_cell->Nid_cell != Nid_cell) { + meas_cell->ss_rsrp_dBm.init = false; + meas_cell->csi_rsrp_dBm.init = false; + } + meas_cell->Nid_cell = Nid_cell; + + if (csi_meas) + apply_ema(&meas_cell->csi_rsrp_dBm, l3_measurements->csi_RS_filter_coeff_rsrp, rsrp_dBm); + else + apply_ema(&meas_cell->ss_rsrp_dBm, l3_measurements->ssb_filter_coeff_rsrp, rsrp_dBm); +} + +static long get_measurement_report_interval_ms(NR_ReportInterval_t interval) +{ + switch (interval) { + case NR_ReportInterval_ms120: + return 120; + case NR_ReportInterval_ms240: + return 240; + case NR_ReportInterval_ms480: + return 480; + case NR_ReportInterval_ms640: + return 640; + case NR_ReportInterval_ms1024: + return 1024; + case NR_ReportInterval_ms2048: + return 2048; + case NR_ReportInterval_ms5120: + return 5120; + case NR_ReportInterval_ms10240: + return 10240; + case NR_ReportInterval_min1: + return 60000; + case NR_ReportInterval_min6: + return 360000; + case NR_ReportInterval_min12: + return 720000; + case NR_ReportInterval_min30: + return 1800000; + default: + return 1024; + } +} + +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) && (l3_measurements->reports_sent == 0)) { + 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; + l3_measurements->reports_sent = 0; + l3_measurements->max_reports = (event_trigger_config->reportAmount == NR_EventTriggerConfig__reportAmount_infinity) + ? INT_MAX + : (1 << event_trigger_config->reportAmount); + l3_measurements->report_interval_ms = get_measurement_report_interval_ms(event_trigger_config->reportInterval); + + 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); + nr_timer_stop(&l3_measurements->periodic_report_timer); + l3_measurements->reports_sent = 0; + } + } +} + 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; @@ -2354,6 +2513,21 @@ void *rrc_nrue(void *notUsed) nr_rrc_ue_decode_NR_SBCCH_SL_BCH_Message(rrc, sbcch->gnb_index,sbcch->frame, sbcch->slot, sbcch->sdu, sbcch->sdu_size, sbcch->rx_slss_id); + case NR_RRC_MAC_MEAS_DATA_IND: + + LOG_D(NR_RRC, "[%s][Nid_cell %i] Received %s measurements: RSRP = %i (dBm)\n", + NR_RRC_MAC_MEAS_DATA_IND(msg_p).is_neighboring_cell? "Neighboring cell" : "Active cell", + NR_RRC_MAC_MEAS_DATA_IND(msg_p).Nid_cell, + NR_RRC_MAC_MEAS_DATA_IND(msg_p).is_csi_meas ? "CSI meas" : "SSB meas", + NR_RRC_MAC_MEAS_DATA_IND(msg_p).rsrp_dBm - 157); + + rrcPerNB_t *rrcNB = rrc->perNB + NR_RRC_MAC_MEAS_DATA_IND(msg_p).gnb_index; + nr_ue_meas_filtering(rrcNB, + NR_RRC_MAC_MEAS_DATA_IND(msg_p).is_neighboring_cell, + 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: { @@ -2992,3 +3166,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); +} diff --git a/openair2/RRC/NR_UE/rrc_defs.h b/openair2/RRC/NR_UE/rrc_defs.h index bc645f7cc1..d1435526b3 100644 --- a/openair2/RRC/NR_UE/rrc_defs.h +++ b/openair2/RRC/NR_UE/rrc_defs.h @@ -192,6 +192,20 @@ typedef enum { typedef enum { RB_NOT_PRESENT, RB_ESTABLISHED, RB_SUSPENDED } NR_RB_status_t; +typedef struct l3_measurements_s { + float ssb_filter_coeff_rsrp; + float csi_RS_filter_coeff_rsrp; + meas_t serving_cell; + long trigger_to_measid; + long trigger_quantity; + long rs_type; + int reports_sent; + int max_reports; + long report_interval_ms; + NR_timer_t TA2; + NR_timer_t periodic_report_timer; +} l3_measurements_t; + typedef struct rrcPerNB { NR_MeasObjectToAddMod_t *MeasObj[MAX_MEAS_OBJ]; NR_ReportConfigToAddMod_t *ReportConfig[MAX_MEAS_CONFIG]; @@ -201,6 +215,7 @@ typedef struct rrcPerNB { NR_MeasGapConfig_t *measGapConfig; NR_UE_RRC_SI_INFO SInfo; NR_RSRP_Range_t s_measure; + l3_measurements_t l3_measurements; } rrcPerNB_t; typedef struct NR_UE_RRC_INST_s { diff --git a/openair2/RRC/NR_UE/rrc_proto.h b/openair2/RRC/NR_UE/rrc_proto.h index ba853f546d..d332ca5175 100644 --- a/openair2/RRC/NR_UE/rrc_proto.h +++ b/openair2/RRC/NR_UE/rrc_proto.h @@ -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); diff --git a/openair2/RRC/NR_UE/rrc_timers_and_constants.c b/openair2/RRC/NR_UE/rrc_timers_and_constants.c index 57f6be2eb6..694656736a 100644 --- a/openair2/RRC/NR_UE/rrc_timers_and_constants.c +++ b/openair2/RRC/NR_UE/rrc_timers_and_constants.c @@ -122,6 +122,36 @@ 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); + l3_measurements->reports_sent = 1; + + if (l3_measurements->reports_sent < l3_measurements->max_reports) { + nr_timer_setup(&l3_measurements->periodic_report_timer, l3_measurements->report_interval_ms, 10); + nr_timer_start(&l3_measurements->periodic_report_timer); + } + } + + bool periodic_expired = nr_timer_tick(&l3_measurements->periodic_report_timer); + if (periodic_expired && l3_measurements->reports_sent < l3_measurements->max_reports) { + rrc_ue_generate_measurementReport(nb, rrc->ue_id); + l3_measurements->reports_sent++; + + if (l3_measurements->reports_sent < l3_measurements->max_reports) { + nr_timer_setup(&l3_measurements->periodic_report_timer, l3_measurements->report_interval_ms, 10); + nr_timer_start(&l3_measurements->periodic_report_timer); + } + } + } +} + void nr_rrc_handle_timers(NR_UE_RRC_INST_t *rrc) { NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants; @@ -185,6 +215,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 +662,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); + } +}