From 25f3d632f4766c0c1a3ee6cfc52ebf6593f74dc9 Mon Sep 17 00:00:00 2001 From: Rakesh BB Date: Mon, 27 Oct 2025 16:05:31 +0530 Subject: [PATCH 01/80] =?UTF-8?q?[NGAP]=20Fix=20incorrect=20AMF=20Set=20ID?= =?UTF-8?q?=20type=20(uint8=20=E2=86=92=20uint16)=20causing=20AMF=20lookup?= =?UTF-8?q?=20failure?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Corrected AMF Set ID data type in ngap_gNB_nnsf_select_amf_by_amf_setid() from uint8_t to uint16_t. - AMF Set ID is a 10-bit field as per 3GPP TS 38.413 ยง9.3.3.12. - The incorrect data type caused truncation for AMF Set IDs >255, leading to lookup failures during RRC reestablishment. - Verified successful reestablishment with large AMF Set IDs after the fix. Reason for fix: AMF lookup using AMF Set ID was failing because the 10-bit AMF Set ID was truncated to 8 bits. Closes #1012 --- openair3/NGAP/ngap_gNB_nnsf.c | 2 +- openair3/NGAP/ngap_gNB_nnsf.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openair3/NGAP/ngap_gNB_nnsf.c b/openair3/NGAP/ngap_gNB_nnsf.c index 5fbc3e4d11..e16e790d38 100644 --- a/openair3/NGAP/ngap_gNB_nnsf.c +++ b/openair3/NGAP/ngap_gNB_nnsf.c @@ -156,7 +156,7 @@ ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_plmn_id(ngap_gNB_instance_t *in ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t *instance_p, const ngap_rrc_establishment_cause_t cause, const plmn_id_t selected_plmn_identity, - uint8_t amf_setid) + uint16_t amf_setid) { struct ngap_gNB_amf_data_s *amf_data_p = NULL; diff --git a/openair3/NGAP/ngap_gNB_nnsf.h b/openair3/NGAP/ngap_gNB_nnsf.h index 8a87ecfce2..0b7c7059e3 100644 --- a/openair3/NGAP/ngap_gNB_nnsf.h +++ b/openair3/NGAP/ngap_gNB_nnsf.h @@ -43,7 +43,7 @@ ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_plmn_id(ngap_gNB_instance_t *in ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t *instance_p, const ngap_rrc_establishment_cause_t cause, const plmn_id_t selected_plmn_identity, - uint8_t amf_setid); + uint16_t amf_setid); ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_guami(ngap_gNB_instance_t *instance_p, const ngap_rrc_establishment_cause_t cause, From 56b987c1dd388b58f493bdfaf4295c26baf391dd Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 29 Oct 2025 14:27:36 +0100 Subject: [PATCH 02/80] bugfix for computation of alt size of DCI00 --- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index 1a5431bdd2..9572b4f602 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -2813,11 +2813,13 @@ uint16_t nr_dci_size(const NR_UE_DL_BWP_t *DL_BWP, dci_pdu->harq_pid.nbits = 4; dci_pdu->frequency_domain_assignment.nbits = (uint8_t)ceil(log2((N_RB * (N_RB + 1)) >>1)); // Freq domain assignment -- hopping scenario to be updated size += dci_pdu->frequency_domain_assignment.nbits; - if(alt_size >= size) - size += alt_size - size; // Padding to match 1_0 size - else if (ss_type == NR_SearchSpace__searchSpaceType_PR_common) { - dci_pdu->frequency_domain_assignment.nbits -= (size - alt_size); - size = alt_size; + if (alt_size) { + if(alt_size >= size) + size += alt_size - size; // Padding to match 1_0 size + else if (ss_type == NR_SearchSpace__searchSpaceType_PR_common) { + dci_pdu->frequency_domain_assignment.nbits -= (size - alt_size); + size = alt_size; + } } // UL/SUL indicator assumed to be 0 break; @@ -3127,7 +3129,7 @@ uint16_t nr_dci_size(const NR_UE_DL_BWP_t *DL_BWP, default: AssertFatal(1==0, "Invalid NR DCI format %d\n", format); } - LOG_D(NR_MAC, "DCI size: %d\n", size); + LOG_D(NR_MAC, "DCI format %d size: %d alt_size %d\n", format, size, alt_size); return size; } From 69f391f2b84aafaf66f4eb5ddebf5947a20b36df Mon Sep 17 00:00:00 2001 From: Raghavendra Dinavahi Date: Thu, 15 May 2025 17:08:59 +0200 Subject: [PATCH 03/80] Fix for the ULDLduplex issue for NTN bands Duplex is assumed to be static but for NTN bands, it is not static. TxRX Duplex is defined in section 5.4.4 of 38.101-5 (for NTN) specs v1809 n256 190 MHz, 165 to 215 MHz n255 -101.5 MHz, -72.5 to -130.5 MHz n254 862 - 885 MHz --- common/utils/nr/nr_common.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index 8e6a16c97d..c3d0c881b3 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -459,10 +459,36 @@ bool compare_relative_ul_channel_bw(int nr_band, int scs, int channel_bandwidth, return rel_bw > limit; } +static bool check_delta_duplex(int index, uint64_t dlfreq_khz, uint64_t ulfreq_khz) +{ + int uldl_min_offset = nr_bandtable[index].dl_min - nr_bandtable[index].ul_min; + int txrx_offset = dlfreq_khz - ulfreq_khz; + LOG_I(NR_PHY, "dlfreq:%ld ulfreq:%ld deltaduplex:%d khz, uldl_min_offset:%d khz\n", + dlfreq_khz, ulfreq_khz, txrx_offset, uldl_min_offset); + if (txrx_offset == uldl_min_offset) + return true; + + int band = nr_bandtable[index].band; + + // TBD.. Delta duplex is also a range for these bands n26, n91-n94, n109. + // TBD .. Add the checks later + + // Refer to section 5.4.4 in spec 38.101-5 + if (band == 256 && txrx_offset >= 165000 && txrx_offset <= 215000) + return true; + if (band == 255 && txrx_offset >= -130500 && txrx_offset <= -72500) + return true; + if (band == 254 && txrx_offset >= 862000 && txrx_offset <= 885000) + return true; + + return false; +} + uint16_t get_band(uint64_t downlink_frequency, int32_t delta_duplex) { const int64_t dl_freq_khz = downlink_frequency / 1000; const int32_t delta_duplex_khz = delta_duplex / 1000; + const int64_t ul_freq_khz = dl_freq_khz + delta_duplex_khz; uint64_t center_freq_diff_khz = UINT64_MAX; // 2^64 uint16_t current_band = 0; @@ -472,9 +498,10 @@ uint16_t get_band(uint64_t downlink_frequency, int32_t delta_duplex) if (dl_freq_khz < nr_bandtable[ind].dl_min || dl_freq_khz > nr_bandtable[ind].dl_max) continue; - int32_t current_offset_khz = nr_bandtable[ind].ul_min - nr_bandtable[ind].dl_min; + if (ul_freq_khz < nr_bandtable[ind].ul_min || ul_freq_khz > nr_bandtable[ind].ul_max) + continue; - if (current_offset_khz != delta_duplex_khz) + if (!check_delta_duplex(ind, dl_freq_khz, ul_freq_khz)) continue; int64_t center_frequency_khz = (nr_bandtable[ind].dl_max + nr_bandtable[ind].dl_min) / 2; From 40fae6136c2a3dca84dd1705b03f798c26541c12 Mon Sep 17 00:00:00 2001 From: Raghavendra Dinavahi Date: Thu, 30 Oct 2025 16:37:39 +0100 Subject: [PATCH 04/80] Added the check for non-NTN bands --- common/utils/nr/nr_common.c | 33 ++++++++++++++++++++------------- common/utils/nr/nr_common.h | 2 +- openair1/PHY/INIT/nr_init.c | 2 +- openair1/PHY/INIT/nr_parms.c | 20 +++++--------------- 4 files changed, 27 insertions(+), 30 deletions(-) diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index c3d0c881b3..53fc42837b 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -459,7 +459,7 @@ bool compare_relative_ul_channel_bw(int nr_band, int scs, int channel_bandwidth, return rel_bw > limit; } -static bool check_delta_duplex(int index, uint64_t dlfreq_khz, uint64_t ulfreq_khz) +static bool check_delta_duplex(int index, uint64_t dlfreq_khz, uint64_t ulfreq_khz, int64_t dlbw, int64_t ulbw) { int uldl_min_offset = nr_bandtable[index].dl_min - nr_bandtable[index].ul_min; int txrx_offset = dlfreq_khz - ulfreq_khz; @@ -470,9 +470,6 @@ static bool check_delta_duplex(int index, uint64_t dlfreq_khz, uint64_t ulfreq_k int band = nr_bandtable[index].band; - // TBD.. Delta duplex is also a range for these bands n26, n91-n94, n109. - // TBD .. Add the checks later - // Refer to section 5.4.4 in spec 38.101-5 if (band == 256 && txrx_offset >= 165000 && txrx_offset <= 215000) return true; @@ -481,16 +478,31 @@ static bool check_delta_duplex(int index, uint64_t dlfreq_khz, uint64_t ulfreq_k if (band == 254 && txrx_offset >= 862000 && txrx_offset <= 885000) return true; + // Refer to section 5.4.4 in spec 38.101-1 for these bands 24, 91-94, 109 + if (band == 24 && (txrx_offset == -101500 || txrx_offset == -120500)) + return true; + //Delta duplex is also a range for these bands n91-n94, n109. + if ((band >= 91 && band <= 94) || band == 109) { + dlbw = ((dlbw / 1000) + 1) * 1000; + ulbw = ((ulbw / 1000) + 1) * 1000; + int lower_limit = nr_bandtable[index].dl_min - nr_bandtable[index].ul_max + ((dlbw + ulbw) >> 1); + int upper_limit = nr_bandtable[index].dl_max - nr_bandtable[index].ul_min - ((dlbw + ulbw) >> 1); + LOG_I(NR_PHY, "Band %d dlbw:%ld Khz, ulbw: %ld Khz RXTX lower limit:%d khz, upper limit:%d khz\n", + band, dlbw, ulbw, lower_limit, upper_limit); + + if (txrx_offset >= lower_limit && txrx_offset <= upper_limit) + return true; + } + return false; } -uint16_t get_band(uint64_t downlink_frequency, int32_t delta_duplex) +uint16_t get_band(uint64_t downlink_frequency, int32_t delta_duplex, int64_t dlbw, int64_t ulbw) { const int64_t dl_freq_khz = downlink_frequency / 1000; const int32_t delta_duplex_khz = delta_duplex / 1000; const int64_t ul_freq_khz = dl_freq_khz + delta_duplex_khz; - uint64_t center_freq_diff_khz = UINT64_MAX; // 2^64 uint16_t current_band = 0; for (int ind = 0; ind < sizeofArray(nr_bandtable); ind++) { @@ -501,15 +513,10 @@ uint16_t get_band(uint64_t downlink_frequency, int32_t delta_duplex) if (ul_freq_khz < nr_bandtable[ind].ul_min || ul_freq_khz > nr_bandtable[ind].ul_max) continue; - if (!check_delta_duplex(ind, dl_freq_khz, ul_freq_khz)) + if (!check_delta_duplex(ind, dl_freq_khz, ul_freq_khz, dlbw, ulbw)) continue; - int64_t center_frequency_khz = (nr_bandtable[ind].dl_max + nr_bandtable[ind].dl_min) / 2; - - if (labs(dl_freq_khz - center_frequency_khz) < center_freq_diff_khz){ - current_band = nr_bandtable[ind].band; - center_freq_diff_khz = labs(dl_freq_khz - center_frequency_khz); - } + current_band = nr_bandtable[ind].band; } printf("DL frequency %"PRIu64": band %d, UL frequency %"PRIu64"\n", diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index e0d68a45ad..2e796bac23 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -285,7 +285,7 @@ int get_coreset_num_cces(uint8_t *FreqDomainResource, int duration); int get_nr_table_idx(int nr_bandP, uint8_t scs_index); int32_t get_delta_duplex(int nr_bandP, uint8_t scs_index); frame_type_t get_frame_type(uint16_t nr_bandP, uint8_t scs_index); -uint16_t get_band(uint64_t downlink_frequency, int32_t delta_duplex); +uint16_t get_band(uint64_t downlink_frequency, int32_t delta_duplex, int64_t dlbw, int64_t ulbw); int NRRIV2BW(int locationAndBandwidth,int N_RB); int NRRIV2PRBOFFSET(int locationAndBandwidth,int N_RB); int PRBalloc_to_locationandbandwidth0(int NPRB,int RBstart,int BWPsize); diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 778903be91..edf9a5c6ee 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -375,7 +375,7 @@ void nr_phy_config_request(NR_PHY_Config_t *phy_config) fp->ul_CarrierFreq = ((ul_bw_khz>>1) + gNB_config->carrier_config.uplink_frequency.value)*1000 ; int32_t dlul_offset = fp->ul_CarrierFreq - fp->dl_CarrierFreq; - fp->nr_band = get_band(fp->dl_CarrierFreq, dlul_offset); + fp->nr_band = get_band(fp->dl_CarrierFreq, dlul_offset, dl_bw_khz, ul_bw_khz); LOG_I(PHY, "DL frequency %lu Hz, UL frequency %lu Hz: band %d, uldl offset %d Hz\n", fp->dl_CarrierFreq, fp->ul_CarrierFreq, fp->nr_band, dlul_offset); diff --git a/openair1/PHY/INIT/nr_parms.c b/openair1/PHY/INIT/nr_parms.c index 2ace21eab5..cc31dc173a 100644 --- a/openair1/PHY/INIT/nr_parms.c +++ b/openair1/PHY/INIT/nr_parms.c @@ -379,15 +379,13 @@ int nr_init_frame_parms_ue(NR_DL_FRAME_PARMS *fp, fp->N_RB_SL = config->carrier_config.sl_grid_size[fp->numerology_index]; fp->frame_type = get_frame_type(fp->nr_band, fp->numerology_index); - int32_t uplink_frequency_offset = get_delta_duplex(fp->nr_band, fp->numerology_index); + int64_t uplink_frequency_offset = fp->ul_CarrierFreq - fp->dl_CarrierFreq; uplink_frequency_offset *= 1000; - LOG_I(PHY, "Initializing frame parms: DL frequency %lu Hz, UL frequency %lu Hz: band %d, uldl offset %d Hz\n", fp->dl_CarrierFreq, fp->ul_CarrierFreq, fp->nr_band, uplink_frequency_offset); + LOG_I(PHY, "Initializing frame parms: DL frequency %lu Hz, UL frequency %lu Hz: band %d, uldl offset %ld Hz\n", fp->dl_CarrierFreq, fp->ul_CarrierFreq, fp->nr_band, uplink_frequency_offset); AssertFatal(fp->frame_type==config->cell_config.frame_duplex_type, "Invalid duplex type (frame_type %d,cell_config.frame_duplex_type %d) in config request file for band %d\n", fp->frame_type,config->cell_config.frame_duplex_type,fp->nr_band); - AssertFatal(fp->ul_CarrierFreq == (fp->dl_CarrierFreq + uplink_frequency_offset), "Disagreement in uplink frequency for band %d: ul_CarrierFreq = %lu Hz vs expected %lu Hz\n", fp->nr_band, fp->ul_CarrierFreq, fp->dl_CarrierFreq + uplink_frequency_offset); - LOG_I(PHY,"Initializing frame parms for mu %d, N_RB %d, Ncp %d\n",fp->numerology_index, fp->N_RB_DL, Ncp); @@ -508,7 +506,7 @@ int nr_init_frame_parms_ue_sl(NR_DL_FRAME_PARMS *fp, fp->ofdm_offset_divisor = ofdm_offset_divisor; fp->threequarter_fs = threequarter_fs; - fp->nr_band = get_band(config->sl_carrier_config.sl_frequency, 0); + fp->nr_band = get_band(config->sl_carrier_config.sl_frequency, 0, 0, 0); fp->att_rx = 0; fp->att_tx = 0; @@ -522,8 +520,6 @@ int nr_init_frame_parms_ue_sl(NR_DL_FRAME_PARMS *fp, fp->Ncp = config->sl_bwp_config.sl_cyclic_prefix; fp->frame_type = get_frame_type(fp->nr_band, fp->numerology_index); - int32_t uplink_frequency_offset = get_delta_duplex(fp->nr_band, fp->numerology_index); - uplink_frequency_offset *= 1000; uint64_t bw_khz = (12 * config->sl_carrier_config.sl_grid_size) * (15 << config->sl_bwp_config.sl_scs); // REfer to section 3GPP spec 38.101 5.4E.2.1 @@ -539,20 +535,14 @@ int nr_init_frame_parms_ue_sl(NR_DL_FRAME_PARMS *fp, LOG_D(PHY, "CarrierFreq %lu Hz\n", fp->sl_CarrierFreq); LOG_I(PHY, - "Initializing frame parms: DL frequency %lu Hz, UL frequency %lu Hz SL frequency %lu Hz: band %d, uldl offset %d Hz\n", + "Initializing frame parms: DL frequency %lu Hz, UL frequency %lu Hz SL frequency %lu Hz: band %d\n", fp->dl_CarrierFreq, fp->ul_CarrierFreq, fp->sl_CarrierFreq, - fp->nr_band, - uplink_frequency_offset); + fp->nr_band); AssertFatal(fp->frame_type == TDD, "Sidelink bands only support TDD"); - AssertFatal(fp->ul_CarrierFreq == (fp->dl_CarrierFreq + uplink_frequency_offset), - "Disagreement in uplink frequency for band %d: ul_CarrierFreq = %lu Hz vs expected %lu Hz\n", - fp->nr_band, - fp->ul_CarrierFreq, - fp->dl_CarrierFreq + uplink_frequency_offset); LOG_I(PHY, "Initializing frame parms for mu %d, N_RB %d, Ncp %d\n", fp->numerology_index, fp->N_RB_DL, fp->Ncp); From db09f50ae455302605f4166416abdb6df7983957 Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Wed, 15 Oct 2025 16:50:49 +0200 Subject: [PATCH 05/80] phy_procedures_gNB_uespec_RX is too long function with too long lines of code, this commit only shorten lines and improve a bit the readability --- .../PHY/nr_phy_common/inc/nr_phy_common.h | 2 +- .../PHY/nr_phy_common/src/nr_phy_common_srs.c | 2 +- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 883 +++++++++--------- 3 files changed, 449 insertions(+), 438 deletions(-) diff --git a/openair1/PHY/nr_phy_common/inc/nr_phy_common.h b/openair1/PHY/nr_phy_common/inc/nr_phy_common.h index 8303c510c7..a2011e1fa6 100644 --- a/openair1/PHY/nr_phy_common/inc/nr_phy_common.h +++ b/openair1/PHY/nr_phy_common/inc/nr_phy_common.h @@ -365,7 +365,7 @@ void nr_channel_level(const int symbol, int32_t avg[nb_rx * Nl], const uint32_t len); void nr_scale_channel(int size, int ch_estimates_ext[][size], int symb, uint32_t len, int nrOfLayers, int nb_rx, int shift_ch_ext); -bool generate_srs_nr(NR_DL_FRAME_PARMS *frame_parms, +bool generate_srs_nr(const NR_DL_FRAME_PARMS *frame_parms, c16_t **txdataF, uint16_t symbol_offset, int bwp_start, diff --git a/openair1/PHY/nr_phy_common/src/nr_phy_common_srs.c b/openair1/PHY/nr_phy_common/src/nr_phy_common_srs.c index ba5d792428..ad21978e06 100644 --- a/openair1/PHY/nr_phy_common/src/nr_phy_common_srs.c +++ b/openair1/PHY/nr_phy_common/src/nr_phy_common_srs.c @@ -139,7 +139,7 @@ static int compute_n_b(frame_t frame_number, * See TS 38.211 - Section 6.4.1.4 Sounding reference signal * ***************************************************************************/ -bool generate_srs_nr(NR_DL_FRAME_PARMS *frame_parms, +bool generate_srs_nr(const NR_DL_FRAME_PARMS *frame_parms, c16_t **txdataF, uint16_t symbol_offset, int bwp_start, diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 51e8c771e5..44d0a24d1c 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -627,18 +627,18 @@ void nr_fill_indication(PHY_VARS_gNB *gNB, } // Function to fill UL RB mask to be used for N0 measurements -static void fill_ul_rb_mask(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, uint32_t rb_mask_ul[14][9]) +static void fill_ul_rb_mask(PHY_VARS_gNB *gNB, + int frame_rx, + int slot_rx, + uint32_t rb_mask_ul[14][9], + nfapi_nr_max_num_of_symbol_per_slot_t *slot_conf) { - int rb = 0; - int rb2 = 0; - int prbpos = 0; - for (int symbol = 0; symbol < 14; symbol++) { for (int m = 0; m < 9; m++) { rb_mask_ul[symbol][m] = 0; for (int i = 0; i < 32; i++) { - prbpos = (m * 32) + i; - if (prbpos>gNB->frame_parms.N_RB_UL) + int prbpos = (m * 32) + i; + if (prbpos > gNB->frame_parms.N_RB_UL) break; rb_mask_ul[symbol][m] |= (gNB->ulprbbl[prbpos] > 0 ? 1U : 0) << i; } @@ -646,23 +646,27 @@ static void fill_ul_rb_mask(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, uint32 } for (int i = 0; i < gNB->max_nb_pucch; i++){ - NR_gNB_PUCCH_t *pucch = &gNB->pucch[i]; - if (pucch) { - if ((pucch->active == 1) && - (pucch->frame == frame_rx) && - (pucch->slot == slot_rx) ) { - nfapi_nr_pucch_pdu_t *pucch_pdu = &pucch->pucch_pdu; - LOG_D(PHY,"%d.%d pucch %d : start_symbol %d, nb_symbols %d, prb_size %d\n",frame_rx,slot_rx,i,pucch_pdu->start_symbol_index,pucch_pdu->nr_of_symbols,pucch_pdu->prb_size); - for (int symbol=pucch_pdu->start_symbol_index ; symbol<(pucch_pdu->start_symbol_index+pucch_pdu->nr_of_symbols);symbol++) { - if(gNB->frame_parms.frame_type == FDD || - (gNB->frame_parms.frame_type == TDD && gNB->gNB_config.tdd_table.max_tdd_periodicity_list[slot_rx].max_num_of_symbol_per_slot_list[symbol].slot_config.value==1)) { - for (rb=0; rbprb_size; rb++) { - rb2 = rb + pucch_pdu->bwp_start + - ((symbol < pucch_pdu->start_symbol_index+(pucch_pdu->nr_of_symbols>>1)) || (pucch_pdu->freq_hop_flag == 0) ? - pucch_pdu->prb_start : pucch_pdu->second_hop_prb); - rb_mask_ul[symbol][rb2>>5] |= (((uint32_t)1)<<(rb2&31)); - } - } + const NR_gNB_PUCCH_t *pucch = gNB->pucch + i; + if (!(pucch && pucch->active && pucch->frame == frame_rx && pucch->slot == slot_rx)) + continue; + const nfapi_nr_pucch_pdu_t *pucch_pdu = &pucch->pucch_pdu; + const int start = pucch_pdu->start_symbol_index; + LOG_D(PHY, + "%d.%d pucch %d : start_symbol %d, nb_symbols %d, prb_size %d\n", + frame_rx, + slot_rx, + i, + start, + pucch_pdu->nr_of_symbols, + pucch_pdu->prb_size); + for (int symbol = start; symbol < (start + pucch_pdu->nr_of_symbols); symbol++) { + if (gNB->frame_parms.frame_type == FDD || (gNB->frame_parms.frame_type == TDD && slot_conf[symbol].slot_config.value == 1)) { + for (int rb = 0; rb < pucch_pdu->prb_size; rb++) { + int rb2 = + rb + pucch_pdu->bwp_start + + ((symbol < start + (pucch_pdu->nr_of_symbols >> 1)) || (pucch_pdu->freq_hop_flag == 0) ? pucch_pdu->prb_start + : pucch_pdu->second_hop_prb); + rb_mask_ul[symbol][rb2 >> 5] |= 1U << (rb2 & 31); } } } @@ -672,21 +676,16 @@ static void fill_ul_rb_mask(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, uint32 NR_gNB_ULSCH_t *ulsch = &gNB->ulsch[ULSCH_id]; NR_UL_gNB_HARQ_t *ulsch_harq = ulsch->harq_process; AssertFatal(ulsch_harq != NULL, "harq_pid %d is not allocated\n", ulsch->harq_pid); - if ((ulsch->active == true) && (ulsch->frame == frame_rx) && (ulsch->slot == slot_rx) && (ulsch->handled == 0)) { - uint8_t symbol_start = ulsch_harq->ulsch_pdu.start_symbol_index; - uint8_t symbol_end = symbol_start + ulsch_harq->ulsch_pdu.nr_of_symbols; - for (int symbol = symbol_start; symbol < symbol_end; symbol++) { - if (gNB->frame_parms.frame_type == FDD - || (gNB->frame_parms.frame_type == TDD - && gNB->gNB_config.tdd_table.max_tdd_periodicity_list[slot_rx] - .max_num_of_symbol_per_slot_list[symbol] - .slot_config.value - == 1)) { - LOG_D(PHY, "symbol %d Filling rb_mask_ul rb_size %d\n", symbol, ulsch_harq->ulsch_pdu.rb_size); - for (rb = 0; rb < ulsch_harq->ulsch_pdu.rb_size; rb++) { - rb2 = rb + ulsch_harq->ulsch_pdu.rb_start + ulsch_harq->ulsch_pdu.bwp_start; - rb_mask_ul[symbol][rb2 >> 5] |= 1U << (rb2 & 31); - } + if (!(ulsch->active && ulsch->frame == frame_rx && ulsch->slot == slot_rx && !ulsch->handled)) + continue; + uint8_t symbol_start = ulsch_harq->ulsch_pdu.start_symbol_index; + uint8_t symbol_end = symbol_start + ulsch_harq->ulsch_pdu.nr_of_symbols; + for (int symbol = symbol_start; symbol < symbol_end; symbol++) { + if (gNB->frame_parms.frame_type == FDD || (gNB->frame_parms.frame_type == TDD && slot_conf[symbol].slot_config.value == 1)) { + LOG_D(PHY, "symbol %d Filling rb_mask_ul rb_size %d\n", symbol, ulsch_harq->ulsch_pdu.rb_size); + for (int rb = 0; rb < ulsch_harq->ulsch_pdu.rb_size; rb++) { + int rb2 = rb + ulsch_harq->ulsch_pdu.rb_start + ulsch_harq->ulsch_pdu.bwp_start; + rb_mask_ul[symbol][rb2 >> 5] |= 1U << (rb2 & 31); } } } @@ -694,14 +693,12 @@ static void fill_ul_rb_mask(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, uint32 for (int i = 0; i < gNB->max_nb_srs; i++) { NR_gNB_SRS_t *srs = &gNB->srs[i]; - if (srs) { - if ((srs->active == 1) && (srs->frame == frame_rx) && (srs->slot == slot_rx)) { - nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu; - for(int symbol = 0; symbol < (1 << srs_pdu->num_symbols); symbol++) { - for(rb = srs_pdu->bwp_start; rb < (srs_pdu->bwp_start+srs_pdu->bwp_size); rb++) { - rb_mask_ul[srs_pdu->time_start_position + symbol][rb >> 5] |= 1U << (rb & 31); - } - } + if (!(srs && srs->active && srs->frame == frame_rx && srs->slot == slot_rx)) + continue; + nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu; + for (int symbol = 0; symbol < (1 << srs_pdu->num_symbols); symbol++) { + for (int rb = srs_pdu->bwp_start; rb < (srs_pdu->bwp_start + srs_pdu->bwp_size); rb++) { + rb_mask_ul[srs_pdu->time_start_position + symbol][rb >> 5] |= 1U << (rb & 31); } } } @@ -728,18 +725,25 @@ int fill_srs_reported_symbol(nfapi_nr_srs_reported_symbol_t *reported_symbol, return 0; } -int fill_srs_channel_matrix(uint8_t *channel_matrix, - const nfapi_nr_srs_pdu_t *srs_pdu, - const nr_srs_info_t *nr_srs_info, - const uint8_t normalized_iq_representation, - const uint16_t num_gnb_antenna_elements, - const uint16_t num_ue_srs_ports, - const uint16_t prg_size, - const uint16_t num_prgs, - const NR_DL_FRAME_PARMS *frame_parms, - const c16_t srs_estimated_channel_freq[][1 << srs_pdu->num_ant_ports] - [frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols)]) +static int fill_srs_channel_matrix( + nfapi_nr_srs_normalized_channel_iq_matrix_t *nr_srs_channel_iq_matrix, + const nfapi_nr_srs_pdu_t *srs_pdu, + const nr_srs_info_t *nr_srs_info, + const uint8_t normalized_iq_representation, + const uint16_t num_gnb_antenna_elements, + const uint16_t num_ue_srs_ports, + const uint16_t prg_size, + const uint16_t num_prgs, + const NR_DL_FRAME_PARMS *frame_parms, + const c16_t srs_estimated_channel_freq[][1 << srs_pdu->num_ant_ports] + [frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols)]) { + nr_srs_channel_iq_matrix->normalized_iq_representation = normalized_iq_representation; + nr_srs_channel_iq_matrix->num_gnb_antenna_elements = num_gnb_antenna_elements; + nr_srs_channel_iq_matrix->num_ue_srs_ports = num_ue_srs_ports; + nr_srs_channel_iq_matrix->prg_size = prg_size; + nr_srs_channel_iq_matrix->num_prgs = num_prgs; + uint8_t *channel_matrix = nr_srs_channel_iq_matrix->channel_matrix; const uint64_t subcarrier_offset = frame_parms->first_carrier_offset + srs_pdu->bwp_start*NR_NB_SC_PER_RB; const uint16_t step = prg_size*NR_NB_SC_PER_RB; @@ -837,75 +841,73 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N int pusch_decode_done = 0; int pusch_DTX = 0; + const NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; + const int symb_sz = frame_parms->ofdm_symbol_size; + const int nb_symb = frame_parms->symbols_per_slot; + const int ant = gNB->frame_parms.nb_antennas_rx; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_UESPEC_RX,1); LOG_D(PHY,"phy_procedures_gNB_uespec_RX frame %d, slot %d\n",frame_rx,slot_rx); - // Mask of occupied RBs, per symbol and PRB - uint32_t rb_mask_ul[14][9]; - fill_ul_rb_mask(gNB, frame_rx, slot_rx, rb_mask_ul); + { + // Mask of occupied RBs, per symbol and PRB + uint32_t rb_mask_ul[14][9]; + nfapi_nr_max_num_of_symbol_per_slot_t *slot_conf = NULL; + if (frame_parms->frame_type == TDD) + slot_conf = gNB->gNB_config.tdd_table.max_tdd_periodicity_list[slot_rx].max_num_of_symbol_per_slot_list; + fill_ul_rb_mask(gNB, frame_rx, slot_rx, rb_mask_ul, slot_conf); - int first_symb=0,num_symb=0; - if (gNB->frame_parms.frame_type == TDD) - for(int symbol_count=0; symbol_countgNB_config.tdd_table.max_tdd_periodicity_list[slot_rx].max_num_of_symbol_per_slot_list[symbol_count].slot_config.value==1) { - if (num_symb==0) first_symb=symbol_count; - num_symb++; + int first_symb = 0, num_symb = 0; + if (frame_parms->frame_type == TDD) + for (int symbol_count = 0; symbol_count < NR_NUMBER_OF_SYMBOLS_PER_SLOT; symbol_count++) { + if (slot_conf[symbol_count].slot_config.value == 1) { + if (num_symb == 0) + first_symb = symbol_count; + num_symb++; + } } - } - else - num_symb = NR_NUMBER_OF_SYMBOLS_PER_SLOT; - gNB_I0_measurements(gNB, slot_rx, first_symb, num_symb, rb_mask_ul); + else + num_symb = NR_NUMBER_OF_SYMBOLS_PER_SLOT; + gNB_I0_measurements(gNB, slot_rx, first_symb, num_symb, rb_mask_ul); + } - const int soffset = (slot_rx & 3) * gNB->frame_parms.symbols_per_slot * gNB->frame_parms.ofdm_symbol_size; + const int soffset = (slot_rx & 3) * nb_symb * symb_sz; start_meas(&gNB->phy_proc_rx); for (int i = 0; i < gNB->max_nb_pucch; i++) { NR_gNB_PUCCH_t *pucch = &gNB->pucch[i]; - if (pucch) { - if (pucch->active && (pucch->frame == frame_rx) && (pucch->slot == slot_rx)) { - c16_t **rxdataF = gNB->common_vars.rxdataF[pucch->beam_nb]; - pucch_decode_done = 1; - nfapi_nr_pucch_pdu_t *pucch_pdu = &pucch->pucch_pdu; - UL_INFO->uci_ind.uci_list = UL_INFO->uci_pdu_list; - nfapi_nr_uci_t *uci = UL_INFO->uci_ind.uci_list + UL_INFO->uci_ind.num_ucis; - switch (pucch_pdu->format_type) { - case 0: - UL_INFO->uci_ind.sfn = frame_rx; - UL_INFO->uci_ind.slot = slot_rx; - uci->pdu_type = NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE; - uci->pdu_size = sizeof(nfapi_nr_uci_pucch_pdu_format_0_1_t); - nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_pdu_format0 = &uci->pucch_pdu_format_0_1; - - int offset = pucch_pdu->start_symbol_index * gNB->frame_parms.ofdm_symbol_size - + (gNB->frame_parms.first_carrier_offset + pucch_pdu->prb_start * 12); - LOG_D(NR_PHY, - "frame %d, slot %d: PUCCH signal energy %d\n", - frame_rx, - slot_rx, - signal_energy_nodc(&rxdataF[0][soffset + offset], 12)); - - nr_decode_pucch0(gNB, rxdataF, frame_rx, slot_rx, uci_pdu_format0, pucch_pdu); - - UL_INFO->uci_ind.num_ucis += 1; - pucch->active = false; - break; - case 2: - UL_INFO->uci_ind.sfn = frame_rx; - UL_INFO->uci_ind.slot = slot_rx; - uci->pdu_type = NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE; - uci->pdu_size = sizeof(nfapi_nr_uci_pucch_pdu_format_2_3_4_t); - nfapi_nr_uci_pucch_pdu_format_2_3_4_t *uci_pdu_format2 = &uci->pucch_pdu_format_2_3_4; - - LOG_D(PHY, "%d.%d Calling nr_decode_pucch2\n", frame_rx, slot_rx); - nr_decode_pucch2(gNB, rxdataF, frame_rx, slot_rx, uci_pdu_format2, pucch_pdu); - - UL_INFO->uci_ind.num_ucis += 1; - pucch->active = false; - break; - default: - AssertFatal(1 == 0, "Only PUCCH formats 0 and 2 are currently supported\n"); - } - } + if (!(pucch && pucch->active && pucch->frame == frame_rx && pucch->slot == slot_rx)) + continue; + c16_t **rxdataF = gNB->common_vars.rxdataF[pucch->beam_nb]; + pucch_decode_done = 1; + nfapi_nr_pucch_pdu_t *pucch_pdu = &pucch->pucch_pdu; + UL_INFO->uci_ind.uci_list = UL_INFO->uci_pdu_list; + nfapi_nr_uci_t *uci = UL_INFO->uci_ind.uci_list + UL_INFO->uci_ind.num_ucis; + UL_INFO->uci_ind.sfn = frame_rx; + UL_INFO->uci_ind.slot = slot_rx; + switch (pucch_pdu->format_type) { + case 0: + uci->pdu_type = NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE; + uci->pdu_size = sizeof(nfapi_nr_uci_pucch_pdu_format_0_1_t); + nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_pdu_format0 = &uci->pucch_pdu_format_0_1; + int offset = pucch_pdu->start_symbol_index * symb_sz + (frame_parms->first_carrier_offset + pucch_pdu->prb_start * 12); + LOG_D(NR_PHY, + "frame %d, slot %d: PUCCH signal energy %d\n", + frame_rx, + slot_rx, + signal_energy_nodc(&rxdataF[0][soffset + offset], 12)); + nr_decode_pucch0(gNB, rxdataF, frame_rx, slot_rx, uci_pdu_format0, pucch_pdu); + break; + case 2: + uci->pdu_type = NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE; + uci->pdu_size = sizeof(nfapi_nr_uci_pucch_pdu_format_2_3_4_t); + nfapi_nr_uci_pucch_pdu_format_2_3_4_t *uci_pdu_format2 = &uci->pucch_pdu_format_2_3_4; + LOG_D(PHY, "%d.%d Calling nr_decode_pucch2\n", frame_rx, slot_rx); + nr_decode_pucch2(gNB, rxdataF, frame_rx, slot_rx, uci_pdu_format2, pucch_pdu); + break; + default: + AssertFatal(1 == 0, "Only PUCCH formats 0 and 2 are currently supported\n"); } + UL_INFO->uci_ind.num_ucis += 1; + pucch->active = false; } UL_INFO->crc_ind.sfn = frame_rx; @@ -915,104 +917,103 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N UL_INFO->rx_ind.slot = slot_rx; UL_INFO->rx_ind.pdu_list = UL_INFO->rx_pdu_list; bool ulsch_to_decode[gNB->max_nb_pusch]; - bzero((void *)ulsch_to_decode, sizeof(ulsch_to_decode)); + bzero(ulsch_to_decode, sizeof(ulsch_to_decode)); for (int ULSCH_id = 0; ULSCH_id < gNB->max_nb_pusch; ULSCH_id++) { NR_gNB_ULSCH_t *ulsch = &gNB->ulsch[ULSCH_id]; NR_UL_gNB_HARQ_t *ulsch_harq = ulsch->harq_process; AssertFatal(ulsch_harq != NULL, "harq_pid %d is not allocated\n", ulsch->harq_pid); - if ((ulsch->active == true) && (ulsch->frame == frame_rx) && (ulsch->slot == slot_rx) && (ulsch->handled == 0)) { - LOG_D(PHY, "PUSCH ID %d with RNTI %x detection started in frame %d slot %d\n", ULSCH_id, ulsch->rnti, frame_rx, slot_rx); - nfapi_nr_pusch_pdu_t *pdu = &ulsch_harq->ulsch_pdu; - int num_dmrs = count_bits64_with_mask(pdu->ul_dmrs_symb_pos, 0, NR_NUMBER_OF_SYMBOLS_PER_SLOT); + if (!(ulsch->active && ulsch->frame == frame_rx && ulsch->slot == slot_rx && !ulsch->handled)) + continue; + LOG_D(PHY, "PUSCH ID %d with RNTI %x detection started in frame %d slot %d\n", ULSCH_id, ulsch->rnti, frame_rx, slot_rx); + nfapi_nr_pusch_pdu_t *pdu = &ulsch_harq->ulsch_pdu; + int num_dmrs = count_bits64_with_mask(pdu->ul_dmrs_symb_pos, 0, NR_NUMBER_OF_SYMBOLS_PER_SLOT); #ifdef DEBUG_RXDATA - NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; - RU_t *ru = gNB->RU_list[0]; - int slot_offset = frame_parms->get_samples_slot_timestamp(slot_rx, frame_parms, 0); - slot_offset -= ru->N_TA_offset; - int32_t sample_offset = gNB->common_vars.debugBuff_sample_offset; - int16_t *buf = (int16_t *)&gNB->common_vars.debugBuff[offset]; - buf[0] = (int16_t)ulsch->rnti; - buf[1] = (int16_t)pdu->rb_size; - buf[2] = (int16_t)pdu->rb_start; - buf[3] = (int16_t)pdu->nr_of_symbols; - buf[4] = (int16_t)pdu->start_symbol_index; - buf[5] = (int16_t)pdu->mcs_index; - buf[6] = (int16_t)pdu->pusch_data.rv_index; - buf[7] = (int16_t)ulsch->harq_pid; - memcpy(&gNB->common_vars.debugBuff[gNB->common_vars.debugBuff_sample_offset + 4], - &ru->common.rxdata[0][slot_offset], - frame_parms->get_samples_per_slot(slot_rx, frame_parms) * sizeof(int32_t)); - gNB->common_vars.debugBuff_sample_offset += (frame_parms->get_samples_per_slot(slot_rx, frame_parms) + 1000 + 4); - if (gNB->common_vars.debugBuff_sample_offset > ((frame_parms->get_samples_per_slot(slot_rx, frame_parms) + 1000 + 2) * 20)) { - FILE *f; - f = fopen("rxdata_buff.raw", "w"); - if (f == NULL) - exit(1); - fwrite((int16_t *)gNB->common_vars.debugBuff, - 2, - (frame_parms->get_samples_per_slot(slot_rx, frame_parms) + 1000 + 4) * 20 * 2, - f); - fclose(f); - exit(-1); - } + RU_t *ru = gNB->RU_list[0]; + int slot_offset = frame_parms->get_samples_slot_timestamp(slot_rx, frame_parms, 0); + slot_offset -= ru->N_TA_offset; + int32_t sample_offset = gNB->common_vars.debugBuff_sample_offset; + int16_t buf = (int16_t *)&gNB->common_vars.debugBuff[offset]; + buf[0] = (int16_t)ulsch->rnti; + buf[1] = (int16_t)pdu->rb_size; + buf[2] = (int16_t)pdu->rb_start; + buf[3] = (int16_t)pdu->nr_of_symbols; + buf[4] = (int16_t)pdu->start_symbol_index; + buf[5] = (int16_t)pdu->mcs_index; + buf[6] = (int16_t)pdu->pusch_data.rv_index; + buf[7] = (int16_t)ulsch->harq_pid; + memcpy(&gNB->common_vars.debugBuff[gNB->common_vars.debugBuff_sample_offset + 4], + &ru->common.rxdata[0][slot_offset], + frame_parms->get_samples_per_slot(slot_rx, frame_parms) * sizeof(int32_t)); + gNB->common_vars.debugBuff_sample_offset += (frame_parms->get_samples_per_slot(slot_rx, frame_parms) + 1000 + 4); + if (gNB->common_vars.debugBuff_sample_offset > ((frame_parms->get_samples_per_slot(slot_rx, frame_parms) + 1000 + 2) * 20)) { + FILE *f; + f = fopen("rxdata_buff.raw", "w"); + if (f == NULL) + exit(1); + fwrite((int16_t *)gNB->common_vars.debugBuff, + 2, + (frame_parms->get_samples_per_slot(slot_rx, frame_parms) + 1000 + 4) * 20 * 2, + f); + fclose(f); + exit(-1); + } #endif - pusch_decode_done = 1; + pusch_decode_done = 1; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_RX_PUSCH, 1); - start_meas(&gNB->rx_pusch_stats); - nr_rx_pusch_tp(gNB, ULSCH_id, frame_rx, slot_rx, ulsch->harq_pid, ulsch->beam_nb); - NR_gNB_PUSCH *pusch_vars = &gNB->pusch_vars[ULSCH_id]; - pusch_vars->ulsch_power_tot = 0; - pusch_vars->ulsch_noise_power_tot = 0; - for (int aarx = 0; aarx < gNB->frame_parms.nb_antennas_rx; aarx++) { - pusch_vars->ulsch_power[aarx] /= num_dmrs; - pusch_vars->ulsch_power_tot += pusch_vars->ulsch_power[aarx]; - pusch_vars->ulsch_noise_power[aarx] /= num_dmrs; - pusch_vars->ulsch_noise_power_tot += pusch_vars->ulsch_noise_power[aarx]; - } - if (dB_fixed_x10(pusch_vars->ulsch_power_tot) < dB_fixed_x10(pusch_vars->ulsch_noise_power_tot) + gNB->pusch_thres) { - NR_gNB_PHY_STATS_t *stats = get_phy_stats(gNB, ulsch->rnti); - - LOG_D(PHY, - "PUSCH not detected in %d.%d (%d,%d,%d)\n", - frame_rx, - slot_rx, - dB_fixed_x10(pusch_vars->ulsch_power_tot), - dB_fixed_x10(pusch_vars->ulsch_noise_power_tot), - gNB->pusch_thres); - pusch_vars->ulsch_power_tot = pusch_vars->ulsch_noise_power_tot; - pusch_vars->DTX = 1; - if (stats) - stats->ulsch_stats.DTX++; - if (!get_softmodem_params()->phy_test) { - /* in case of phy_test mode, we still want to decode to measure execution time. - Therefore, we don't yet call nr_fill_indication, it will be called later */ - nfapi_nr_crc_t *crc = &UL_INFO->crc_ind.crc_list[UL_INFO->crc_ind.number_crcs++]; - nfapi_nr_rx_data_pdu_t *pdu = &UL_INFO->rx_ind.pdu_list[UL_INFO->rx_ind.number_of_pdus++]; - nr_fill_indication(gNB, frame_rx, slot_rx, ULSCH_id, ulsch->harq_pid, 1, 1, crc, pdu); - pusch_DTX++; - gNBdumpScopeData(gNB, ulsch->slot, ulsch->frame, "ULSCH_DTX"); - continue; - } - } else { - LOG_D(PHY, - "PUSCH detected in %d.%d (%d,%d,%d)\n", - frame_rx, - slot_rx, - dB_fixed_x10(pusch_vars->ulsch_power_tot), - dB_fixed_x10(pusch_vars->ulsch_noise_power_tot), - gNB->pusch_thres); - - pusch_vars->DTX = 0; - } - ulsch_to_decode[ULSCH_id] = true; - stop_meas(&gNB->rx_pusch_stats); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_RX_PUSCH, 0); - // LOG_M("rxdataF_comp.m","rxF_comp",gNB->pusch_vars[0]->rxdataF_comp[0],6900,1,1); - // LOG_M("rxdataF_ext.m","rxF_ext",gNB->pusch_vars[0]->rxdataF_ext[0],6900,1,1); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_RX_PUSCH, 1); + start_meas(&gNB->rx_pusch_stats); + nr_rx_pusch_tp(gNB, ULSCH_id, frame_rx, slot_rx, ulsch->harq_pid, ulsch->beam_nb); + NR_gNB_PUSCH *pusch_vars = &gNB->pusch_vars[ULSCH_id]; + pusch_vars->ulsch_power_tot = 0; + pusch_vars->ulsch_noise_power_tot = 0; + for (int aarx = 0; aarx < ant; aarx++) { + pusch_vars->ulsch_power[aarx] /= num_dmrs; + pusch_vars->ulsch_power_tot += pusch_vars->ulsch_power[aarx]; + pusch_vars->ulsch_noise_power[aarx] /= num_dmrs; + pusch_vars->ulsch_noise_power_tot += pusch_vars->ulsch_noise_power[aarx]; } + if (dB_fixed_x10(pusch_vars->ulsch_power_tot) < dB_fixed_x10(pusch_vars->ulsch_noise_power_tot) + gNB->pusch_thres) { + NR_gNB_PHY_STATS_t *stats = get_phy_stats(gNB, ulsch->rnti); + + LOG_D(PHY, + "PUSCH not detected in %d.%d (%d,%d,%d)\n", + frame_rx, + slot_rx, + dB_fixed_x10(pusch_vars->ulsch_power_tot), + dB_fixed_x10(pusch_vars->ulsch_noise_power_tot), + gNB->pusch_thres); + pusch_vars->ulsch_power_tot = pusch_vars->ulsch_noise_power_tot; + pusch_vars->DTX = 1; + if (stats) + stats->ulsch_stats.DTX++; + if (!get_softmodem_params()->phy_test) { + /* in case of phy_test mode, we still want to decode to measure execution time. + Therefore, we don't yet call nr_fill_indication, it will be called later */ + nfapi_nr_crc_t *crc = &UL_INFO->crc_ind.crc_list[UL_INFO->crc_ind.number_crcs++]; + nfapi_nr_rx_data_pdu_t *pdu = &UL_INFO->rx_ind.pdu_list[UL_INFO->rx_ind.number_of_pdus++]; + nr_fill_indication(gNB, frame_rx, slot_rx, ULSCH_id, ulsch->harq_pid, 1, 1, crc, pdu); + pusch_DTX++; + gNBdumpScopeData(gNB, ulsch->slot, ulsch->frame, "ULSCH_DTX"); + continue; + } + } else { + LOG_D(PHY, + "PUSCH detected in %d.%d (%d,%d,%d)\n", + frame_rx, + slot_rx, + dB_fixed_x10(pusch_vars->ulsch_power_tot), + dB_fixed_x10(pusch_vars->ulsch_noise_power_tot), + gNB->pusch_thres); + + pusch_vars->DTX = 0; + } + ulsch_to_decode[ULSCH_id] = true; + stop_meas(&gNB->rx_pusch_stats); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_RX_PUSCH, 0); + // LOG_M("rxdataF_comp.m","rxF_comp",gNB->pusch_vars[0]->rxdataF_comp[0],6900,1,1); + // LOG_M("rxdataF_ext.m","rxF_ext",gNB->pusch_vars[0]->rxdataF_ext[0],6900,1,1); } /* Do ULSCH decoding time measurement only when number of PUSCH is limited to 1 @@ -1033,249 +1034,259 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N * measurement per processed TB.*/ if (gNB->max_nb_pusch == 1) stop_meas(&gNB->ulsch_decoding_stats); + for (int i = 0; i < gNB->max_nb_srs; i++) { NR_gNB_SRS_t *srs = &gNB->srs[i]; - if (srs) { - if ((srs->active == true) && (srs->frame == frame_rx) && (srs->slot == slot_rx)) { - LOG_D(NR_PHY, "(%d.%d) gNB is waiting for SRS, id = %i\n", frame_rx, slot_rx, i); + if (!(srs && srs->active && srs->frame == frame_rx && srs->slot == slot_rx)) + continue; + LOG_D(NR_PHY, "(%d.%d) gNB is waiting for SRS, id = %i\n", frame_rx, slot_rx, i); - start_meas(&gNB->rx_srs_stats); + start_meas(&gNB->rx_srs_stats); - NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; - nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu; - uint8_t N_symb_SRS = 1 << srs_pdu->num_symbols; - c16_t srs_received_signal[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size * N_symb_SRS]; - c16_t srs_received_noise[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size * N_symb_SRS]; - c16_t srs_estimated_channel_freq[frame_parms->nb_antennas_rx][1 << srs_pdu->num_ant_ports] - [frame_parms->ofdm_symbol_size * N_symb_SRS] __attribute__((aligned(32))); - c16_t srs_estimated_channel_time[frame_parms->nb_antennas_rx][1 << srs_pdu->num_ant_ports][frame_parms->ofdm_symbol_size] - __attribute__((aligned(32))); - c16_t srs_estimated_channel_time_shifted[frame_parms->nb_antennas_rx][1 << srs_pdu->num_ant_ports] - [frame_parms->ofdm_symbol_size]; - int16_t snr_per_rb[srs_pdu->bwp_size]; + nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu; + uint8_t N_symb_SRS = 1 << srs_pdu->num_symbols; + c16_t srs_received_signal[ant][symb_sz * N_symb_SRS]; + c16_t srs_received_noise[ant][symb_sz * N_symb_SRS]; + c16_t srs_estimated_channel_freq[ant][1 << srs_pdu->num_ant_ports][symb_sz * N_symb_SRS] __attribute__((aligned(32))); + c16_t srs_estimated_channel_time[ant][1 << srs_pdu->num_ant_ports][symb_sz] __attribute__((aligned(32))); + c16_t srs_estimated_channel_time_shifted[ant][1 << srs_pdu->num_ant_ports][symb_sz]; + int16_t snr_per_rb[srs_pdu->bwp_size]; - start_meas(&gNB->generate_srs_stats); + start_meas(&gNB->generate_srs_stats); - if (check_and_configure_srs_info(srs_pdu, gNB->nr_srs_info[i])) { - generate_srs_nr(frame_parms, - gNB->nr_srs_info[i]->srs_generated_signal, - 0, - srs_pdu->bwp_start, - gNB->nr_srs_info[i], - AMP, - frame_rx, - slot_rx); - } - stop_meas(&gNB->generate_srs_stats); - c16_t **rxdataF = gNB->common_vars.rxdataF[srs->beam_nb]; - start_meas(&gNB->get_srs_signal_stats); - int srs_est = nr_get_srs_signal(gNB, rxdataF, frame_rx, slot_rx, srs_pdu, gNB->nr_srs_info[i], srs_received_signal, srs_received_noise); - stop_meas(&gNB->get_srs_signal_stats); - - if (srs_est >= 0) { - start_meas(&gNB->srs_channel_estimation_stats); - nr_srs_channel_estimation(gNB, - frame_rx, - slot_rx, - srs_pdu, - gNB->nr_srs_info[i], - (const c16_t**)gNB->nr_srs_info[i]->srs_generated_signal, - srs_received_signal, - srs_received_noise, - srs_estimated_channel_freq, - srs_estimated_channel_time, - srs_estimated_channel_time_shifted, - snr_per_rb, - &gNB->srs->snr); - stop_meas(&gNB->srs_channel_estimation_stats); - } - - if ((gNB->srs->snr * 10) < gNB->srs_thres) { - srs_est = -1; - } - - T(T_GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE, - T_INT(0), - T_INT(srs_pdu->rnti), - T_INT(frame_rx), - T_INT(0), - T_INT(0), - T_BUFFER(srs_estimated_channel_freq[0][0], frame_parms->ofdm_symbol_size * sizeof(int32_t))); - - T(T_GNB_PHY_UL_TIME_CHANNEL_ESTIMATE, - T_INT(0), - T_INT(srs_pdu->rnti), - T_INT(frame_rx), - T_INT(0), - T_INT(0), - T_BUFFER(srs_estimated_channel_time_shifted[0][0], frame_parms->ofdm_symbol_size * sizeof(int32_t))); - - T(T_GNB_PHY_UL_SNR_ESTIMATE, - T_INT(0), - T_INT(srs_pdu->rnti), - T_INT(frame_rx), - T_INT(0), - T_INT(0), - T_BUFFER(snr_per_rb, srs_pdu->bwp_size * sizeof(int16_t))); - - UL_INFO->srs_ind.sfn = frame_rx; - UL_INFO->srs_ind.slot = slot_rx; - - // data model difficult to understand, nfapi do malloc for this pointer - UL_INFO->srs_ind.pdu_list = UL_INFO->srs_pdu_list; - nfapi_nr_srs_indication_pdu_t *srs_indication = UL_INFO->srs_pdu_list + UL_INFO->srs_ind.number_of_pdus++; - srs_indication->handle = srs_pdu->handle; - srs_indication->rnti = srs_pdu->rnti; - start_meas(&gNB->srs_timing_advance_stats); - srs_indication->timing_advance_offset = srs_est >= 0 ? nr_est_timing_advance_srs(frame_parms, srs_estimated_channel_time[0]) : 0xFFFF; - stop_meas(&gNB->srs_timing_advance_stats); - srs_indication->timing_advance_offset_nsec = srs_est >= 0 ? (int16_t)((((int32_t)srs_indication->timing_advance_offset - 31) * ((int32_t)TC_NSEC_x32768)) >> 15) : 0xFFFF; - switch (srs_pdu->srs_parameters_v4.usage) { - case 0: - LOG_W(NR_PHY, "SRS report was not requested by MAC\n"); - return 0; - case 1 << NFAPI_NR_SRS_BEAMMANAGEMENT: - srs_indication->srs_usage = NFAPI_NR_SRS_BEAMMANAGEMENT; - break; - case 1 << NFAPI_NR_SRS_CODEBOOK: - srs_indication->srs_usage = NFAPI_NR_SRS_CODEBOOK; - break; - case 1 << NFAPI_NR_SRS_NONCODEBOOK: - srs_indication->srs_usage = NFAPI_NR_SRS_NONCODEBOOK; - break; - case 1 << NFAPI_NR_SRS_ANTENNASWITCH: - srs_indication->srs_usage = NFAPI_NR_SRS_ANTENNASWITCH; - break; - default: - LOG_E(NR_PHY, "Invalid srs_pdu->srs_parameters_v4.usage %i\n", srs_pdu->srs_parameters_v4.usage); - } - srs_indication->report_type = srs_pdu->srs_parameters_v4.report_type[0]; - -#ifdef SRS_IND_DEBUG - LOG_I(NR_PHY, "UL_INFO->srs_ind.sfn = %i\n", UL_INFO->srs_ind.sfn); - LOG_I(NR_PHY, "UL_INFO->srs_ind.slot = %i\n", UL_INFO->srs_ind.slot); - LOG_I(NR_PHY, "srs_indication->rnti = %04x\n", srs_indication->rnti); - LOG_I(NR_PHY, "srs_indication->timing_advance = %i\n", srs_indication->timing_advance_offset); - LOG_I(NR_PHY, "srs_indication->timing_advance_offset_nsec = %i\n", srs_indication->timing_advance_offset_nsec); - LOG_I(NR_PHY, "srs_indication->srs_usage = %i\n", srs_indication->srs_usage); - LOG_I(NR_PHY, "srs_indication->report_type = %i\n", srs_indication->report_type); -#endif - - nfapi_srs_report_tlv_t *report_tlv = &srs_indication->report_tlv; - report_tlv->tag = 0; - report_tlv->length = 0; - - start_meas(&gNB->srs_report_tlv_stats); - switch (srs_indication->srs_usage) { - case NFAPI_NR_SRS_BEAMMANAGEMENT: { - start_meas(&gNB->srs_beam_report_stats); - nfapi_nr_srs_beamforming_report_t nr_srs_bf_report; - nr_srs_bf_report.prg_size = srs_pdu->beamforming.prg_size; - nr_srs_bf_report.num_symbols = 1 << srs_pdu->num_symbols; - nr_srs_bf_report.wide_band_snr = srs_est >= 0 ? (gNB->srs->snr + 64) << 1 : 0xFF; // 0xFF will be set if this field is invalid - nr_srs_bf_report.num_reported_symbols = 1 << srs_pdu->num_symbols; - AssertFatal(nr_srs_bf_report.num_reported_symbols == 1, - "nr_srs_bf_report.num_reported_symbols %i not handled yet!\n", - nr_srs_bf_report.num_reported_symbols); - fill_srs_reported_symbol(&nr_srs_bf_report.reported_symbol_list[0], srs_pdu, frame_parms->N_RB_UL, snr_per_rb, srs_est); - -#ifdef SRS_IND_DEBUG - LOG_I(NR_PHY, "nr_srs_bf_report.prg_size = %i\n", nr_srs_bf_report.prg_size); - LOG_I(NR_PHY, "nr_srs_bf_report.num_symbols = %i\n", nr_srs_bf_report.num_symbols); - LOG_I(NR_PHY, "nr_srs_bf_report.wide_band_snr = %i (%i dB)\n", nr_srs_bf_report.wide_band_snr, (nr_srs_bf_report.wide_band_snr >> 1) - 64); - LOG_I(NR_PHY, "nr_srs_bf_report.num_reported_symbols = %i\n", nr_srs_bf_report.num_reported_symbols); - LOG_I(NR_PHY, "nr_srs_bf_report.reported_symbol_list[0].num_prgs = %i\n", nr_srs_bf_report.reported_symbol_list[0].num_prgs); - for (int prg_idx = 0; prg_idx < nr_srs_bf_report.reported_symbol_list[0].num_prgs; prg_idx++) { - LOG_I(NR_PHY, - "nr_srs_beamforming_report.reported_symbol_list[0].prg_list[%3i].rb_snr = %i (%i dB)\n", - prg_idx, - nr_srs_bf_report.reported_symbol_list[0].prg_list[prg_idx].rb_snr, - (nr_srs_bf_report.reported_symbol_list[0].prg_list[prg_idx].rb_snr >> 1) - 64); - } -#endif - - report_tlv->length = pack_nr_srs_beamforming_report(&nr_srs_bf_report, report_tlv->value, sizeof(report_tlv->value)); - stop_meas(&gNB->srs_beam_report_stats); - break; - } - - case NFAPI_NR_SRS_CODEBOOK: { - start_meas(&gNB->srs_iq_matrix_stats); - nfapi_nr_srs_normalized_channel_iq_matrix_t nr_srs_channel_iq_matrix; - nr_srs_channel_iq_matrix.normalized_iq_representation = srs_pdu->srs_parameters_v4.iq_representation; - nr_srs_channel_iq_matrix.num_gnb_antenna_elements = gNB->frame_parms.nb_antennas_rx; - nr_srs_channel_iq_matrix.num_ue_srs_ports = srs_pdu->srs_parameters_v4.num_total_ue_antennas; - nr_srs_channel_iq_matrix.prg_size = srs_pdu->srs_parameters_v4.prg_size; - nr_srs_channel_iq_matrix.num_prgs = srs_pdu->srs_parameters_v4.srs_bandwidth_size / srs_pdu->srs_parameters_v4.prg_size; - fill_srs_channel_matrix(nr_srs_channel_iq_matrix.channel_matrix, - srs_pdu, - gNB->nr_srs_info[i], - nr_srs_channel_iq_matrix.normalized_iq_representation, - nr_srs_channel_iq_matrix.num_gnb_antenna_elements, - nr_srs_channel_iq_matrix.num_ue_srs_ports, - nr_srs_channel_iq_matrix.prg_size, - nr_srs_channel_iq_matrix.num_prgs, - &gNB->frame_parms, - srs_estimated_channel_freq); - -#ifdef SRS_IND_DEBUG - LOG_I(NR_PHY, "nr_srs_channel_iq_matrix.normalized_iq_representation = %i\n", nr_srs_channel_iq_matrix.normalized_iq_representation); - LOG_I(NR_PHY, "nr_srs_channel_iq_matrix.num_gnb_antenna_elements = %i\n", nr_srs_channel_iq_matrix.num_gnb_antenna_elements); - LOG_I(NR_PHY, "nr_srs_channel_iq_matrix.num_ue_srs_ports = %i\n", nr_srs_channel_iq_matrix.num_ue_srs_ports); - LOG_I(NR_PHY, "nr_srs_channel_iq_matrix.prg_size = %i\n", nr_srs_channel_iq_matrix.prg_size); - LOG_I(NR_PHY, "nr_srs_channel_iq_matrix.num_prgs = %i\n", nr_srs_channel_iq_matrix.num_prgs); - c16_t *channel_matrix16 = (c16_t *)nr_srs_channel_iq_matrix.channel_matrix; - c8_t *channel_matrix8 = (c8_t *)nr_srs_channel_iq_matrix.channel_matrix; - for (int uI = 0; uI < nr_srs_channel_iq_matrix.num_ue_srs_ports; uI++) { - for (int gI = 0; gI < nr_srs_channel_iq_matrix.num_gnb_antenna_elements; gI++) { - for (int pI = 0; pI < nr_srs_channel_iq_matrix.num_prgs; pI++) { - uint16_t index = - uI * nr_srs_channel_iq_matrix.num_gnb_antenna_elements * nr_srs_channel_iq_matrix.num_prgs + gI * nr_srs_channel_iq_matrix.num_prgs + pI; - LOG_I(NR_PHY, - "(uI %i, gI %i, pI %i) channel_matrix --> real %i, imag %i\n", - uI, - gI, - pI, - nr_srs_channel_iq_matrix.normalized_iq_representation == 0 ? channel_matrix8[index].r : channel_matrix16[index].r, - nr_srs_channel_iq_matrix.normalized_iq_representation == 0 ? channel_matrix8[index].i : channel_matrix16[index].i); - } - } - } -#endif - - report_tlv->length = pack_nr_srs_normalized_channel_iq_matrix(&nr_srs_channel_iq_matrix, report_tlv->value, sizeof(report_tlv->value)); - stop_meas(&gNB->srs_iq_matrix_stats); - break; - } - - case NFAPI_NR_SRS_NONCODEBOOK: - case NFAPI_NR_SRS_ANTENNASWITCH: - LOG_W(NR_PHY, "PHY procedures for this SRS usage are not implemented yet!\n"); - break; - - default: - AssertFatal(1 == 0, "Invalid SRS usage\n"); - } - stop_meas(&gNB->srs_report_tlv_stats); - -#ifdef SRS_IND_DEBUG - LOG_I(NR_PHY, "report_tlv->tag = %i\n", report_tlv->tag); - LOG_I(NR_PHY, "report_tlv->length = %i\n", report_tlv->length); - char *value = (char *)report_tlv->value; - for (int b = 0; b < report_tlv->length; b++) { - LOG_I(NR_PHY, "value[%i] = 0x%02x\n", b, value[b] & 0xFF); - } -#endif - srs->active = false; - stop_meas(&gNB->rx_srs_stats); - } + if (check_and_configure_srs_info(srs_pdu, gNB->nr_srs_info[i])) { + generate_srs_nr(frame_parms, + gNB->nr_srs_info[i]->srs_generated_signal, + 0, + srs_pdu->bwp_start, + gNB->nr_srs_info[i], + AMP, + frame_rx, + slot_rx); } + stop_meas(&gNB->generate_srs_stats); + c16_t **rxdataF = gNB->common_vars.rxdataF[srs->beam_nb]; + start_meas(&gNB->get_srs_signal_stats); + int srs_est = + nr_get_srs_signal(gNB, rxdataF, frame_rx, slot_rx, srs_pdu, gNB->nr_srs_info[i], srs_received_signal, srs_received_noise); + stop_meas(&gNB->get_srs_signal_stats); + + if (srs_est >= 0) { + start_meas(&gNB->srs_channel_estimation_stats); + nr_srs_channel_estimation(gNB, + frame_rx, + slot_rx, + srs_pdu, + gNB->nr_srs_info[i], + (const c16_t **)gNB->nr_srs_info[i]->srs_generated_signal, + srs_received_signal, + srs_received_noise, + srs_estimated_channel_freq, + srs_estimated_channel_time, + srs_estimated_channel_time_shifted, + snr_per_rb, + &gNB->srs->snr); + stop_meas(&gNB->srs_channel_estimation_stats); + } + + if ((gNB->srs->snr * 10) < gNB->srs_thres) { + srs_est = -1; + } + + T(T_GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE, + T_INT(0), + T_INT(srs_pdu->rnti), + T_INT(frame_rx), + T_INT(0), + T_INT(0), + T_BUFFER(srs_estimated_channel_freq[0][0], symb_sz * sizeof(int32_t))); + + T(T_GNB_PHY_UL_TIME_CHANNEL_ESTIMATE, + T_INT(0), + T_INT(srs_pdu->rnti), + T_INT(frame_rx), + T_INT(0), + T_INT(0), + T_BUFFER(srs_estimated_channel_time_shifted[0][0], symb_sz * sizeof(int32_t))); + + T(T_GNB_PHY_UL_SNR_ESTIMATE, + T_INT(0), + T_INT(srs_pdu->rnti), + T_INT(frame_rx), + T_INT(0), + T_INT(0), + T_BUFFER(snr_per_rb, srs_pdu->bwp_size * sizeof(int16_t))); + + UL_INFO->srs_ind.sfn = frame_rx; + UL_INFO->srs_ind.slot = slot_rx; + + // data model difficult to understand, nfapi do malloc for this pointer + UL_INFO->srs_ind.pdu_list = UL_INFO->srs_pdu_list; + nfapi_nr_srs_indication_pdu_t *srs_indication = UL_INFO->srs_pdu_list + UL_INFO->srs_ind.number_of_pdus++; + srs_indication->handle = srs_pdu->handle; + srs_indication->rnti = srs_pdu->rnti; + start_meas(&gNB->srs_timing_advance_stats); + srs_indication->timing_advance_offset = + srs_est >= 0 ? nr_est_timing_advance_srs(frame_parms, srs_estimated_channel_time[0]) : 0xFFFF; + stop_meas(&gNB->srs_timing_advance_stats); + srs_indication->timing_advance_offset_nsec = + srs_est >= 0 ? (int16_t)((((int32_t)srs_indication->timing_advance_offset - 31) * ((int32_t)TC_NSEC_x32768)) >> 15) + : 0xFFFF; + switch (srs_pdu->srs_parameters_v4.usage) { + case 0: + LOG_W(NR_PHY, "SRS report was not requested by MAC\n"); + return 0; + case 1 << NFAPI_NR_SRS_BEAMMANAGEMENT: + srs_indication->srs_usage = NFAPI_NR_SRS_BEAMMANAGEMENT; + break; + case 1 << NFAPI_NR_SRS_CODEBOOK: + srs_indication->srs_usage = NFAPI_NR_SRS_CODEBOOK; + break; + case 1 << NFAPI_NR_SRS_NONCODEBOOK: + srs_indication->srs_usage = NFAPI_NR_SRS_NONCODEBOOK; + break; + case 1 << NFAPI_NR_SRS_ANTENNASWITCH: + srs_indication->srs_usage = NFAPI_NR_SRS_ANTENNASWITCH; + break; + default: + LOG_E(NR_PHY, "Invalid srs_pdu->srs_parameters_v4.usage %i\n", srs_pdu->srs_parameters_v4.usage); + } + srs_indication->report_type = srs_pdu->srs_parameters_v4.report_type[0]; + +#ifdef SRS_IND_DEBUG + LOG_I(NR_PHY, "UL_INFO->srs_ind.sfn = %i\n", UL_INFO->srs_ind.sfn); + LOG_I(NR_PHY, "UL_INFO->srs_ind.slot = %i\n", UL_INFO->srs_ind.slot); + LOG_I(NR_PHY, "srs_indication->rnti = %04x\n", srs_indication->rnti); + LOG_I(NR_PHY, "srs_indication->timing_advance = %i\n", srs_indication->timing_advance_offset); + LOG_I(NR_PHY, "srs_indication->timing_advance_offset_nsec = %i\n", srs_indication->timing_advance_offset_nsec); + LOG_I(NR_PHY, "srs_indication->srs_usage = %i\n", srs_indication->srs_usage); + LOG_I(NR_PHY, "srs_indication->report_type = %i\n", srs_indication->report_type); +#endif + + nfapi_srs_report_tlv_t *report_tlv = &srs_indication->report_tlv; + report_tlv->tag = 0; + report_tlv->length = 0; + + start_meas(&gNB->srs_report_tlv_stats); + switch (srs_indication->srs_usage) { + case NFAPI_NR_SRS_BEAMMANAGEMENT: { + start_meas(&gNB->srs_beam_report_stats); + nfapi_nr_srs_beamforming_report_t nr_srs_bf_report; + nr_srs_bf_report.prg_size = srs_pdu->beamforming.prg_size; + nr_srs_bf_report.num_symbols = 1 << srs_pdu->num_symbols; + nr_srs_bf_report.wide_band_snr = + srs_est >= 0 ? (gNB->srs->snr + 64) << 1 : 0xFF; // 0xFF will be set if this field is invalid + nr_srs_bf_report.num_reported_symbols = 1 << srs_pdu->num_symbols; + AssertFatal(nr_srs_bf_report.num_reported_symbols == 1, + "nr_srs_bf_report.num_reported_symbols %i not handled yet!\n", + nr_srs_bf_report.num_reported_symbols); + fill_srs_reported_symbol(&nr_srs_bf_report.reported_symbol_list[0], srs_pdu, frame_parms->N_RB_UL, snr_per_rb, srs_est); + +#ifdef SRS_IND_DEBUG + LOG_I(NR_PHY, "nr_srs_bf_report.prg_size = %i\n", nr_srs_bf_report.prg_size); + LOG_I(NR_PHY, "nr_srs_bf_report.num_symbols = %i\n", nr_srs_bf_report.num_symbols); + LOG_I(NR_PHY, + "nr_srs_bf_report.wide_band_snr = %i (%i dB)\n", + nr_srs_bf_report.wide_band_snr, + (nr_srs_bf_report.wide_band_snr >> 1) - 64); + LOG_I(NR_PHY, "nr_srs_bf_report.num_reported_symbols = %i\n", nr_srs_bf_report.num_reported_symbols); + LOG_I(NR_PHY, + "nr_srs_bf_report.reported_symbol_list[0].num_prgs = %i\n", + nr_srs_bf_report.reported_symbol_list[0].num_prgs); + for (int prg_idx = 0; prg_idx < nr_srs_bf_report.reported_symbol_list[0].num_prgs; prg_idx++) { + LOG_I(NR_PHY, + "nr_srs_beamforming_report.reported_symbol_list[0].prg_list[%3i].rb_snr = %i (%i dB)\n", + prg_idx, + nr_srs_bf_report.reported_symbol_list[0].prg_list[prg_idx].rb_snr, + (nr_srs_bf_report.reported_symbol_list[0].prg_list[prg_idx].rb_snr >> 1) - 64); + } +#endif + + report_tlv->length = pack_nr_srs_beamforming_report(&nr_srs_bf_report, report_tlv->value, sizeof(report_tlv->value)); + stop_meas(&gNB->srs_beam_report_stats); + break; + } + + case NFAPI_NR_SRS_CODEBOOK: { + start_meas(&gNB->srs_iq_matrix_stats); + nfapi_nr_srs_normalized_channel_iq_matrix_t nr_srs_channel_iq_matrix; + fill_srs_channel_matrix(&nr_srs_channel_iq_matrix, + srs_pdu, + gNB->nr_srs_info[i], + srs_pdu->srs_parameters_v4.iq_representation, + ant, + srs_pdu->srs_parameters_v4.num_total_ue_antennas, + srs_pdu->srs_parameters_v4.prg_size, + srs_pdu->srs_parameters_v4.srs_bandwidth_size / srs_pdu->srs_parameters_v4.prg_size, + frame_parms, + srs_estimated_channel_freq); + +#ifdef SRS_IND_DEBUG + LOG_I(NR_PHY, + "nr_srs_channel_iq_matrix.normalized_iq_representation = %i\n", + nr_srs_channel_iq_matrix.normalized_iq_representation); + LOG_I(NR_PHY, + "nr_srs_channel_iq_matrix.num_gnb_antenna_elements = %i\n", + nr_srs_channel_iq_matrix.num_gnb_antenna_elements); + LOG_I(NR_PHY, "nr_srs_channel_iq_matrix.num_ue_srs_ports = %i\n", nr_srs_channel_iq_matrix.num_ue_srs_ports); + LOG_I(NR_PHY, "nr_srs_channel_iq_matrix.prg_size = %i\n", nr_srs_channel_iq_matrix.prg_size); + LOG_I(NR_PHY, "nr_srs_channel_iq_matrix.num_prgs = %i\n", nr_srs_channel_iq_matrix.num_prgs); + c16_t *channel_matrix16 = (c16_t *)nr_srs_channel_iq_matrix.channel_matrix; + c8_t *channel_matrix8 = (c8_t *)nr_srs_channel_iq_matrix.channel_matrix; + for (int uI = 0; uI < nr_srs_channel_iq_matrix.num_ue_srs_ports; uI++) { + for (int gI = 0; gI < nr_srs_channel_iq_matrix.num_gnb_antenna_elements; gI++) { + for (int pI = 0; pI < nr_srs_channel_iq_matrix.num_prgs; pI++) { + uint16_t index = uI * nr_srs_channel_iq_matrix.num_gnb_antenna_elements * nr_srs_channel_iq_matrix.num_prgs + + gI * nr_srs_channel_iq_matrix.num_prgs + pI; + LOG_I( + NR_PHY, + "(uI %i, gI %i, pI %i) channel_matrix --> real %i, imag %i\n", + uI, + gI, + pI, + nr_srs_channel_iq_matrix.normalized_iq_representation == 0 ? channel_matrix8[index].r : channel_matrix16[index].r, + nr_srs_channel_iq_matrix.normalized_iq_representation == 0 ? channel_matrix8[index].i + : channel_matrix16[index].i); + } + } + } +#endif + + report_tlv->length = + pack_nr_srs_normalized_channel_iq_matrix(&nr_srs_channel_iq_matrix, report_tlv->value, sizeof(report_tlv->value)); + stop_meas(&gNB->srs_iq_matrix_stats); + break; + } + + case NFAPI_NR_SRS_NONCODEBOOK: + case NFAPI_NR_SRS_ANTENNASWITCH: + LOG_W(NR_PHY, "PHY procedures for this SRS usage are not implemented yet!\n"); + break; + + default: + AssertFatal(1 == 0, "Invalid SRS usage\n"); + } + stop_meas(&gNB->srs_report_tlv_stats); + +#ifdef SRS_IND_DEBUG + LOG_I(NR_PHY, "report_tlv->tag = %i\n", report_tlv->tag); + LOG_I(NR_PHY, "report_tlv->length = %i\n", report_tlv->length); + char *value = (char *)report_tlv->value; + for (int b = 0; b < report_tlv->length; b++) { + LOG_I(NR_PHY, "value[%i] = 0x%02x\n", b, value[b] & 0xFF); + } +#endif + srs->active = false; + stop_meas(&gNB->rx_srs_stats); } stop_meas(&gNB->phy_proc_rx); if (pucch_decode_done || pusch_decode_done) { - T(T_GNB_PHY_PUCCH_PUSCH_IQ, T_INT(frame_rx), T_INT(slot_rx), T_BUFFER(&gNB->common_vars.rxdataF[0][0][0], gNB->frame_parms.symbols_per_slot * gNB->frame_parms.ofdm_symbol_size * 4)); + T(T_GNB_PHY_PUCCH_PUSCH_IQ, + T_INT(frame_rx), + T_INT(slot_rx), + T_BUFFER(&gNB->common_vars.rxdataF[0][0][0], nb_symb * symb_sz * 4)); } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_UESPEC_RX,0); From d2c191b0eaaf7c906f5297dedc47314aaf81e4c3 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Sun, 27 Jul 2025 11:16:22 +0200 Subject: [PATCH 06/80] Add two LOG_Ds to debug PUSCH allocations --- openair1/PHY/NR_TRANSPORT/nr_ulsch.c | 80 +++++++++++++++++++++++++++ openair1/SCHED_NR_UE/fapi_nr_ue_l1.c | 83 ++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+) diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c index 4621e184a6..06aef61935 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c @@ -59,8 +59,88 @@ static NR_gNB_ULSCH_t *find_nr_ulsch(PHY_VARS_gNB *gNB, uint16_t rnti, int pid) return ulsch; } +static void dump_pusch_pdu(int instance, int frame, int slot, nfapi_nr_pusch_pdu_t *pusch_pdu) +{ + LOG_D(PHY, + "[gNB %d] %d.%d ULSCH PDU pdu_bit_map %u " + "rnti %u " + "handle %u " + "bwp_size %u " + "bwp_start %u " + "subcarrier_spacing %u " + "cyclic_prefix %u " + "target_code_rate %u " + "qam_mod_order %u " + "mcs_index %u " + "mcs_table %u " + "transform_precoding %u " + "data_scrambling_id %u " + "nrOfLayers %u " + "ul_dmrs_symb_pos %u " + "dmrs_config_type %u " + "ul_dmrs_scrambling_id %u " + "scid %u " + "num_dmrs_cdm_grps_no_data %u " + "dmrs_ports %u " + "resource_alloc %u " + "rb_start %u " + "rb_size %u " + "vrb_to_prb_mapping %u " + "frequency_hopping %u " + "tx_direct_current_location %u " + "uplink_frequency_shift_7p5khz %u " + "start_symbol_index %u " + "nr_of_symbols %u " + "tbslbrm %u " + "ldpcBaseGraph %u " + "pusch_data->rv_index %u " + "pusch_data->harq_process_id %u " + "pusch_data->new_data_indicator %u " + "pusch_data->num_cb %u\n", + instance, + frame, + slot, + pusch_pdu->pdu_bit_map, + pusch_pdu->rnti, + pusch_pdu->handle, + pusch_pdu->bwp_size, + pusch_pdu->bwp_start, + pusch_pdu->subcarrier_spacing, + pusch_pdu->cyclic_prefix, + pusch_pdu->target_code_rate, + pusch_pdu->qam_mod_order, + pusch_pdu->mcs_index, + pusch_pdu->mcs_table, + pusch_pdu->transform_precoding, + pusch_pdu->data_scrambling_id, + pusch_pdu->nrOfLayers, + pusch_pdu->ul_dmrs_symb_pos, + pusch_pdu->dmrs_config_type, + pusch_pdu->ul_dmrs_scrambling_id, + pusch_pdu->scid, + pusch_pdu->num_dmrs_cdm_grps_no_data, + pusch_pdu->dmrs_ports, + pusch_pdu->resource_alloc, + pusch_pdu->rb_start, + pusch_pdu->rb_size, + pusch_pdu->vrb_to_prb_mapping, + pusch_pdu->frequency_hopping, + pusch_pdu->tx_direct_current_location, + pusch_pdu->uplink_frequency_shift_7p5khz, + pusch_pdu->start_symbol_index, + pusch_pdu->nr_of_symbols, + pusch_pdu->maintenance_parms_v3.tbSizeLbrmBytes, + pusch_pdu->maintenance_parms_v3.ldpcBaseGraph, + pusch_pdu->pusch_data.rv_index, + pusch_pdu->pusch_data.harq_process_id, + pusch_pdu->pusch_data.new_data_indicator, + pusch_pdu->pusch_data.num_cb); +} + + void nr_fill_ulsch(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_pusch_pdu_t *ulsch_pdu) { + dump_pusch_pdu(gNB->Mod_id, frame, slot, ulsch_pdu); int harq_pid = ulsch_pdu->pusch_data.harq_process_id; NR_gNB_ULSCH_t *ulsch = find_nr_ulsch(gNB, ulsch_pdu->rnti, harq_pid); if (ulsch == NULL) { diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c index cbdd91c949..a3e86ce433 100644 --- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c +++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c @@ -230,6 +230,88 @@ static void nr_ue_scheduled_response_dl(NR_UE_MAC_INST_t *mac, dl_config->number_pdus = 0; } +static void dump_pusch_pdu(int instance, int frame, int slot, nfapi_nr_ue_pusch_pdu_t *pusch_pdu) +{ + LOG_D(PHY, + "[UE %d] %d.%d ULSCH PDU pdu_bit_map %u " + "rnti %u " + "handle %u " + "bwp_size %u " + "bwp_start %u " + "subcarrier_spacing %u " + "cyclic_prefix %u " + "target_code_rate %u " + "qam_mod_order %u " + "mcs_index %u " + "mcs_table %u " + "transform_precoding %u " + "data_scrambling_id %u " + "nrOfLayers %u " + "Tpmi %u " + "ul_dmrs_symb_pos %u " + "dmrs_config_type %u " + "ul_dmrs_scrambling_id %u " + "scid %u " + "num_dmrs_cdm_grps_no_data %u " + "dmrs_ports %u " + "resource_alloc %u " + "rb_start %u " + "rb_size %u " + "vrb_to_prb_mapping %u " + "frequency_hopping %u " + "tx_direct_current_location %u " + "uplink_frequency_shift_7p5khz %u " + "start_symbol_index %u " + "nr_of_symbols %u " + "tbslbrm %u " + "ldpcBaseGraph %u " + "ulsch_indicator %u " + "pusch_data->rv_index %u " + "pusch_data->harq_process_id %u " + "pusch_data->new_data_indicator %u " + "pusch_data->num_cb %u\n", + instance, + frame, + slot, + pusch_pdu->pdu_bit_map, + pusch_pdu->rnti, + pusch_pdu->handle, + pusch_pdu->bwp_size, + pusch_pdu->bwp_start, + pusch_pdu->subcarrier_spacing, + pusch_pdu->cyclic_prefix, + pusch_pdu->target_code_rate, + pusch_pdu->qam_mod_order, + pusch_pdu->mcs_index, + pusch_pdu->mcs_table, + pusch_pdu->transform_precoding, + pusch_pdu->data_scrambling_id, + pusch_pdu->nrOfLayers, + pusch_pdu->Tpmi, + pusch_pdu->ul_dmrs_symb_pos, + pusch_pdu->dmrs_config_type, + pusch_pdu->ul_dmrs_scrambling_id, + pusch_pdu->scid, + pusch_pdu->num_dmrs_cdm_grps_no_data, + pusch_pdu->dmrs_ports, + pusch_pdu->resource_alloc, + pusch_pdu->rb_start, + pusch_pdu->rb_size, + pusch_pdu->vrb_to_prb_mapping, + pusch_pdu->frequency_hopping, + pusch_pdu->tx_direct_current_location, + pusch_pdu->uplink_frequency_shift_7p5khz, + pusch_pdu->start_symbol_index, + pusch_pdu->nr_of_symbols, + pusch_pdu->tbslbrm, + pusch_pdu->ldpcBaseGraph, + pusch_pdu->ulsch_indicator, + pusch_pdu->pusch_data.rv_index, + pusch_pdu->pusch_data.harq_process_id, + pusch_pdu->pusch_data.new_data_indicator, + pusch_pdu->pusch_data.num_cb); +} + static void nr_ue_scheduled_response_ul(PHY_VARS_NR_UE *phy, fapi_nr_ul_config_request_t *ul_config, nr_phy_data_tx_t *phy_data) { fapi_nr_ul_config_request_pdu_t *pdu = fapiLockIterator(ul_config, ul_config->frame, ul_config->slot); @@ -251,6 +333,7 @@ static void nr_ue_scheduled_response_ul(PHY_VARS_NR_UE *phy, fapi_nr_ul_config_r pdu->pusch_config_pdu.num_dmrs_cdm_grps_no_data); memcpy(pusch_pdu, &pdu->pusch_config_pdu, sizeof(*pusch_pdu)); + dump_pusch_pdu(phy->Mod_id, ul_config->frame, ul_config->slot, pusch_pdu); if (pdu->pusch_config_pdu.tx_request_body.fapiTxPdu) { LOG_D(PHY, "%d.%d Copying %d bytes to harq_process_ul_ue->a (harq_pid %d)\n", From ac93fe590cecc6d8d3159db67ebd1bc0cd99d70a Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Sun, 27 Jul 2025 13:04:34 +0200 Subject: [PATCH 07/80] Fix NR UE MAC not setting subcarrier_spacing field in PUSCH PDU Set the subcarrier_spacing field in nfapi_nr_ue_pusch_pdu_t from MAC to PHY. This has no consequence for the NR UE Softmodem operation as this field is never read, but prevents a potential future bug in case L1 was modified to read it. --- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 714d2eacfd..bd9ea09041 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -555,6 +555,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, pusch_config_pdu->tbslbrm = 0; } else if (dci) { + pusch_config_pdu->subcarrier_spacing = scs; pusch_config_pdu->ulsch_indicator = dci->ulsch_indicator; if (dci->csi_request.nbits > 0 && dci->csi_request.val > 0) { AssertFatal(csi_report, "CSI report needs to be present in case of CSI request\n"); From 3f27ae26ae9cd88c8e9c59dbf8dab7317cad1b89 Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Thu, 23 Oct 2025 18:20:33 +0200 Subject: [PATCH 08/80] C code cleaning, no change --- openair1/PHY/NR_TRANSPORT/nr_prs.c | 2 +- .../PHY/NR_TRANSPORT/nr_transport_proto.h | 2 +- openair1/SCHED_NR/fapi_nr_l1.h | 9 -- openair1/SCHED_NR/phy_frame_config_nr.c | 2 +- openair1/SCHED_NR/phy_frame_config_nr.h | 2 +- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 83 ++++++++++--------- 6 files changed, 49 insertions(+), 51 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_prs.c b/openair1/PHY/NR_TRANSPORT/nr_prs.c index 6f26b9a07f..799912713d 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prs.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prs.c @@ -13,7 +13,7 @@ int nr_generate_prs(int slot, int16_t amp, prs_config_t *prs_cfg, nfapi_nr_config_request_scf_t *config, - NR_DL_FRAME_PARMS *frame_parms) + const NR_DL_FRAME_PARMS *frame_parms) { int k_prime = 0, k = 0, idx; diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index 0714f3dde3..29fca5975e 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -45,7 +45,7 @@ int nr_generate_prs(int slot, int16_t amp, prs_config_t *prs_cfg, nfapi_nr_config_request_scf_t *config, - NR_DL_FRAME_PARMS *frame_parms); + const NR_DL_FRAME_PARMS *frame_parms); /*! \fn int nr_generate_pss diff --git a/openair1/SCHED_NR/fapi_nr_l1.h b/openair1/SCHED_NR/fapi_nr_l1.h index 59df4fb30d..4d426d92ce 100644 --- a/openair1/SCHED_NR/fapi_nr_l1.h +++ b/openair1/SCHED_NR/fapi_nr_l1.h @@ -53,15 +53,6 @@ void handle_nr_nfapi_pdsch_pdu(processingData_L1tx_t *msgTx, nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu, uint8_t *sdu); -void nr_fill_indication(PHY_VARS_gNB *gNB, - int frame, - int slot_rx, - int UE_id, - uint8_t harq_pid, - uint8_t crc_flag, - int dtx_flag, - nfapi_nr_crc_t *crc, - nfapi_nr_rx_data_pdu_t *pdu); //added void handle_nfapi_nr_ul_dci_pdu(PHY_VARS_gNB *gNB, diff --git a/openair1/SCHED_NR/phy_frame_config_nr.c b/openair1/SCHED_NR/phy_frame_config_nr.c index 085ce8e087..9479e960a8 100644 --- a/openair1/SCHED_NR/phy_frame_config_nr.c +++ b/openair1/SCHED_NR/phy_frame_config_nr.c @@ -152,7 +152,7 @@ void set_tdd_config_nr(nfapi_nr_config_request_scf_t *cfg, frame_structure_t *fs } } -int nr_slot_select(nfapi_nr_config_request_scf_t *cfg, int nr_frame, int nr_slot) +int nr_slot_select(const nfapi_nr_config_request_scf_t *cfg, int nr_frame, int nr_slot) { (void) nr_frame; diff --git a/openair1/SCHED_NR/phy_frame_config_nr.h b/openair1/SCHED_NR/phy_frame_config_nr.h index 11ae4bf5c6..687fd2bc51 100644 --- a/openair1/SCHED_NR/phy_frame_config_nr.h +++ b/openair1/SCHED_NR/phy_frame_config_nr.h @@ -53,7 +53,7 @@ void set_tdd_config_nr(nfapi_nr_config_request_scf_t *cfg, frame_structure_t *fs * @param nr_slot : slot number @returns int : downlink, uplink or mixed slot type*/ -int nr_slot_select(nfapi_nr_config_request_scf_t *cfg, int nr_frame, int nr_slot); +int nr_slot_select(const nfapi_nr_config_request_scf_t *cfg, int nr_frame, int nr_slot); void do_tdd_config_sim(PHY_VARS_gNB *gNB, int mu); diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 44d0a24d1c..e28d22ede9 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -45,6 +45,15 @@ //#define DEBUG_RXDATA //#define SRS_IND_DEBUG +static void nr_fill_indication(PHY_VARS_gNB *gNB, + int frame, + int slot_rx, + int UE_id, + uint8_t harq_pid, + uint8_t crc_flag, + int dtx_flag, + nfapi_nr_crc_t *crc, + nfapi_nr_rx_data_pdu_t *pdu); int beam_index_allocation(bool das, int fapi_beam_index, @@ -186,10 +195,10 @@ void nr_common_signal_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_n void clear_slot_beamid(PHY_VARS_gNB *gNB, int slot) { LOG_D(PHY, "Clearing beam_id structure for slot %d\n", slot); - NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; + int slot_sz = gNB->frame_parms.symbols_per_slot; for (int i = 0; i < gNB->common_vars.num_beams_period; i++) { if (gNB->common_vars.beam_id) - memset(&gNB->common_vars.beam_id[i][slot * fp->symbols_per_slot], -1, fp->symbols_per_slot * sizeof(int)); + memset(&gNB->common_vars.beam_id[i][slot * slot_sz], -1, slot_sz * sizeof(**gNB->common_vars.beam_id)); } } @@ -199,11 +208,9 @@ void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx, int do_meas) { PHY_VARS_gNB *gNB = msgTx->gNB; - NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; + const NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config; - int slot_prs = 0; - int txdataF_offset = slot * fp->samples_per_slot_wCP; - prs_config_t *prs_config = NULL; + const int txdataF_offset = slot * fp->samples_per_slot_wCP; if ((cfg->cell_config.frame_duplex_type.value == TDD) && (nr_slot_select(cfg,frame,slot) == NR_UPLINK_SLOT)) return; @@ -213,19 +220,19 @@ void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx, // clear the transmit data array and beam index for the current slot for (int i = 0; i < gNB->common_vars.num_beams_period; i++) { for (int aa = 0; aa < cfg->carrier_config.num_tx_ant.value; aa++) { - memset(&gNB->common_vars.txdataF[i][aa][txdataF_offset], 0, fp->samples_per_slot_wCP * sizeof(int32_t)); + memset(&gNB->common_vars.txdataF[i][aa][txdataF_offset], 0, fp->samples_per_slot_wCP * sizeof(***gNB->common_vars.txdataF)); } } // Check for PRS slot - section 7.4.1.7.4 in 3GPP rel16 38.211 for(int rsc_id = 0; rsc_id < gNB->prs_vars.NumPRSResources; rsc_id++) { - prs_config = &gNB->prs_vars.prs_cfg[rsc_id]; + prs_config_t *prs_config = &gNB->prs_vars.prs_cfg[rsc_id]; for (int i = 0; i < prs_config->PRSResourceRepetition; i++) { if( (((frame*fp->slots_per_frame + slot) - (prs_config->PRSResourceSetPeriod[1] + prs_config->PRSResourceOffset)+prs_config->PRSResourceSetPeriod[0])%prs_config->PRSResourceSetPeriod[0]) == i*prs_config->PRSResourceTimeGap ) { - slot_prs = (slot - i*prs_config->PRSResourceTimeGap + fp->slots_per_frame)%fp->slots_per_frame; + int slot_prs = (slot - i * prs_config->PRSResourceTimeGap + fp->slots_per_frame) % fp->slots_per_frame; LOG_D(PHY,"gNB_TX: frame %d, slot %d, slot_prs %d, PRS Resource ID %d\n",frame, slot, slot_prs, rsc_id); nr_generate_prs(slot_prs, &gNB->common_vars.txdataF[0][0][txdataF_offset], AMP, prs_config, cfg, fp); } @@ -537,24 +544,24 @@ static int nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, boo return ret_nr_ulsch_decoding; } -void nr_fill_indication(PHY_VARS_gNB *gNB, - int frame, - int slot_rx, - int ULSCH_id, - uint8_t harq_pid, - uint8_t crc_flag, - int dtx_flag, - nfapi_nr_crc_t *crc, - nfapi_nr_rx_data_pdu_t *pdu) +static void nr_fill_indication(PHY_VARS_gNB *gNB, + int frame, + int slot_rx, + int ULSCH_id, + uint8_t harq_pid, + uint8_t crc_flag, + int dtx_flag, + nfapi_nr_crc_t *crc, + nfapi_nr_rx_data_pdu_t *pdu) { - NR_gNB_ULSCH_t *ulsch = &gNB->ulsch[ULSCH_id]; - NR_UL_gNB_HARQ_t *harq_process = ulsch->harq_process; - NR_gNB_PHY_STATS_t *stats = get_phy_stats(gNB, ulsch->rnti); + NR_UL_gNB_HARQ_t *harq_process = gNB->ulsch[ULSCH_id].harq_process; + NR_gNB_PHY_STATS_t *stats = get_phy_stats(gNB, gNB->ulsch[ULSCH_id].rnti); + NR_gNB_PUSCH *pusch = &gNB->pusch_vars[ULSCH_id]; nfapi_nr_pusch_pdu_t *pusch_pdu = &harq_process->ulsch_pdu; // Get estimated timing advance for MAC - int sync_pos = ulsch->delay.est_delay; + const int sync_pos = gNB->ulsch[ULSCH_id].delay.est_delay; // scale the 16 factor in N_TA calculation in 38.213 section 4.2 according to the used FFT size uint16_t bw_scaling = 16 * gNB->frame_parms.ofdm_symbol_size / 2048; @@ -584,16 +591,15 @@ void nr_fill_indication(PHY_VARS_gNB *gNB, timing_advance_update); // estimate UL_CQI for MAC - int SNRtimes10 = - dB_fixed_x10(gNB->pusch_vars[ULSCH_id].ulsch_power_tot) - dB_fixed_x10(gNB->pusch_vars[ULSCH_id].ulsch_noise_power_tot); + int SNRtimes10 = dB_fixed_x10(pusch->ulsch_power_tot) - dB_fixed_x10(pusch->ulsch_noise_power_tot); LOG_D(PHY, "%d.%d: Estimated SNR for PUSCH is = %f dB (ulsch_power %f, noise %f) delay %d\n", frame, slot_rx, SNRtimes10 / 10.0, - dB_fixed_x10(gNB->pusch_vars[ULSCH_id].ulsch_power_tot) / 10.0, - dB_fixed_x10(gNB->pusch_vars[ULSCH_id].ulsch_noise_power_tot) / 10.0, + dB_fixed_x10(pusch->ulsch_power_tot) / 10.0, + dB_fixed_x10(pusch->ulsch_noise_power_tot) / 10.0, sync_pos); int cqi; @@ -609,8 +615,7 @@ void nr_fill_indication(PHY_VARS_gNB *gNB, crc->ul_cqi = cqi; crc->timing_advance = timing_advance_update; // in terms of dBFS range -128 to 0 with 0.1 step - crc->rssi = - (dtx_flag == 0) ? 1280 - (10 * dB_fixed(32767 * 32767) - dB_fixed_times10(gNB->pusch_vars[ULSCH_id].ulsch_power[0])) : 0; + crc->rssi = (dtx_flag == 0) ? 1280 - (10 * dB_fixed(32767 * 32767) - dB_fixed_times10(pusch->ulsch_power[0])) : 0; pdu->handle = pusch_pdu->handle; pdu->rnti = pusch_pdu->rnti; @@ -704,21 +709,23 @@ static void fill_ul_rb_mask(PHY_VARS_gNB *gNB, } } -int fill_srs_reported_symbol(nfapi_nr_srs_reported_symbol_t *reported_symbol, - const nfapi_nr_srs_pdu_t *srs_pdu, - const int N_RB_UL, - const int16_t *snr_per_rb, - const int srs_est) { +static int fill_srs_reported_symbol(nfapi_nr_srs_reported_symbol_t *reported_symbol, + const nfapi_nr_srs_pdu_t *srs_pdu, + const int N_RB_UL, + const int16_t *snr_per_rb, + const int srs_est) +{ reported_symbol->num_prgs = srs_pdu->beamforming.num_prgs; for (int prg_idx = 0; prg_idx < reported_symbol->num_prgs; prg_idx++) { - if (srs_est<0) { - reported_symbol->prg_list[prg_idx].rb_snr = 0xFF; + uint8_t *snr = &reported_symbol->prg_list[prg_idx].rb_snr; + if (srs_est < 0) { + *snr = 0xFF; } else if (snr_per_rb[prg_idx] < -64) { - reported_symbol->prg_list[prg_idx].rb_snr = 0; + *snr = 0; } else if (snr_per_rb[prg_idx] > 63) { - reported_symbol->prg_list[prg_idx].rb_snr = 0xFE; + *snr = 0xFE; } else { - reported_symbol->prg_list[prg_idx].rb_snr = (snr_per_rb[prg_idx] + 64) << 1; + *snr = (snr_per_rb[prg_idx] + 64) << 1; } } From 7274e7c4347ab969f5a2c36ff0b41680444acc81 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 6 Nov 2025 11:08:38 +0100 Subject: [PATCH 09/80] SDAP: guard RX header parsing with enable_sdap and init per-entity !3519 refactored the SDAP to use the QFI from the header rather than pass it to the rx function and got rid of the initialization of QFI to -1. However, entity roles are stored into the drb2qfi table, and the indexing implies that the QFI is known. While in TX it is not an issue since packets are forwarded based on the QFI, in RX the QFI can only be parsed from the heaedr, therefore if headers are disabled (--enable_sdap) the QFI is not there and it is wrong to access the header (`buf[0]`) and looking for it. This commit adds `enable_sdap` to `nr_sdap_entity_t` and initialize it in `nr_sdap_add_entity()` from `sdap->role` (disabled when `NO_SDAP_HEADER`). In `nr_sdap_rx_entity()`, only parse `buf[0]` for QFI and derive `sdap_ul_rx`/`sdap_dl_rx` when `enable_sdap` is true; otherwise, keep `offset=0` and forward payload unchanged. --- openair2/SDAP/nr_sdap/nr_sdap_entity.c | 20 +++++++++++++------- openair2/SDAP/nr_sdap/nr_sdap_entity.h | 1 + 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index 389213986e..9056c6e733 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -210,15 +210,20 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity, { /* The offset of the SDAP header, it might be 0 if has_sdap_rx is not true in the pdcp entity. */ int offset=0; - uint8_t qfi = buf[0] & 0x3F; // QFI is always the first 6 bits in the first octet - if (qfi >= SDAP_MAX_QFI) { - LOG_E(SDAP, "Invalid QFI %d received in SDAP header\n", qfi); - return; + bool sdap_ul_rx = false; + bool sdap_dl_rx = false; + /* If SDAP header is disabled for this entity, bypass header parsing */ + if (entity->enable_sdap) { + uint8_t qfi = buf[0] & 0x3F; // QFI is always the first 6 bits in the first octet + if (qfi >= SDAP_MAX_QFI) { + LOG_E(SDAP, "Invalid QFI %d received in SDAP header\n", qfi); + return; + } + // Fetch entity role from the qfi2drb_table + sdap_ul_rx = entity->qfi2drb_table[qfi].entity_role & SDAP_UL_RX; // gNB RX entity + sdap_dl_rx = entity->qfi2drb_table[qfi].entity_role & SDAP_DL_RX; // UE RX entity } - // Fetch entity role from the qfi2drb_table - bool sdap_ul_rx = entity->qfi2drb_table[qfi].entity_role & SDAP_UL_RX; // gNB RX entity - bool sdap_dl_rx = entity->qfi2drb_table[qfi].entity_role & SDAP_DL_RX; // UE RX entity if (is_gnb) { // gNB if (sdap_ul_rx) { // UL Data/Control PDU with SDAP header @@ -495,6 +500,7 @@ static void nr_sdap_add_entity(const int is_gnb, const ue_id_t ue_id, const sdap sdap_entity->ue_id = ue_id; sdap_entity->pdusession_id = sdap->pdusession_id; sdap_entity->is_gnb = is_gnb; + sdap_entity->enable_sdap = (sdap->role != NO_SDAP_HEADER); // rx/tx entities sdap_entity->tx_entity = nr_sdap_tx_entity; diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h index e96836ac79..9f85ac21cf 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -99,6 +99,7 @@ typedef struct nr_sdap_entity_s { /// sdap_tun_read_thread needs to know if we are gNB/UE, so for noS1 mode, /// store which one we are bool is_gnb; + bool enable_sdap; int pdusession_id; int pdusession_sock; pthread_t pdusession_thread; From c47ddc570f9ebeb06df91d7314475c28e888f774 Mon Sep 17 00:00:00 2001 From: francescomani Date: Sat, 8 Nov 2025 14:34:41 +0100 Subject: [PATCH 10/80] add check for CellGroup decoding at RRC UE (issue #1024) --- openair2/RRC/NR_UE/rrc_UE.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 15c713cb26..9086ad25eb 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -747,12 +747,15 @@ static void nr_rrc_ue_process_masterCellGroup(NR_UE_RRC_INST_t *rrc, { AssertFatal(!fullConfig, "fullConfig not supported yet\n"); NR_CellGroupConfig_t *cellGroupConfig = NULL; - uper_decode(NULL, - &asn_DEF_NR_CellGroupConfig, //might be added prefix later - (void **)&cellGroupConfig, - (uint8_t *)masterCellGroup->buf, - masterCellGroup->size, 0, 0); - + asn_dec_rval_t dec_rval = uper_decode(NULL, + &asn_DEF_NR_CellGroupConfig, //might be added prefix later + (void **)&cellGroupConfig, + (uint8_t *)masterCellGroup->buf, + masterCellGroup->size, 0, 0); + if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) { + LOG_E(NR_RRC, "CellGroupConfig decode error\n"); + return; + } if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *) cellGroupConfig); } From f9ca8431c0b1715972953e05575119dba4ac1a21 Mon Sep 17 00:00:00 2001 From: Nada Bouknana Date: Tue, 11 Nov 2025 13:58:43 +0100 Subject: [PATCH 11/80] add PDCCH IQ and LLR plots to the UE scope --- openair1/PHY/TOOLS/imscope/imscope.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/openair1/PHY/TOOLS/imscope/imscope.cpp b/openair1/PHY/TOOLS/imscope/imscope.cpp index cce7a595f7..b70587614d 100644 --- a/openair1/PHY/TOOLS/imscope/imscope.cpp +++ b/openair1/PHY/TOOLS/imscope/imscope.cpp @@ -444,6 +444,23 @@ void ShowUeScope(void *data_void_ptr, float t) } ImGui::End(); + if (ImGui::Begin("UE PDCCH IQ")) { + static auto iq_data = new IQData(); + static auto pdcch_iq_hist = new IQHist("PDCCH IQ"); + bool new_data = false; + if (pdcch_iq_hist->ShouldReadData()) { + new_data = iq_data->TryCollect(&scope_array[pdcchRxdataF_comp], t, pdcch_iq_hist->GetEpsilon(), iq_procedure_timer); + } + pdcch_iq_hist->Draw(iq_data, t, new_data); + } + ImGui::End(); + + if (ImGui::Begin("UE PDCCH LLR")) { + static auto llr_plot = new LLRPlot(); + llr_plot->Draw(t, pdcchLlr, "PDCCH LLR"); + } + ImGui::End(); + if (ImGui::Begin("UE PDSCH IQ")) { static auto iq_data = new IQData(); static auto pdsch_iq_hist = new IQHist("PDSCH IQ"); From 530812ff381092abd579a6a0bd13c0c12e21021a Mon Sep 17 00:00:00 2001 From: Nada Bouknana Date: Tue, 11 Nov 2025 14:01:23 +0100 Subject: [PATCH 12/80] add ImPlotAxisFlags_AutoFit flag to enable autofitting by default in imscope plots --- openair1/PHY/TOOLS/imscope/imscope.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openair1/PHY/TOOLS/imscope/imscope.cpp b/openair1/PHY/TOOLS/imscope/imscope.cpp index b70587614d..a858409d9e 100644 --- a/openair1/PHY/TOOLS/imscope/imscope.cpp +++ b/openair1/PHY/TOOLS/imscope/imscope.cpp @@ -100,6 +100,7 @@ class LLRPlot { ImScopeDataWrapper &scope_data = scope_array[type]; if (ImPlot::BeginPlot(label)) { + ImPlot::SetupAxes(nullptr, nullptr, ImPlotAxisFlags_AutoFit, ImPlotAxisFlags_AutoFit); if (!frozen || next) { if (scope_data.is_data_ready) { iq_procedure_timer.Add(scope_data.data.time_taken_in_ns); @@ -205,6 +206,7 @@ class IQHist { if (plot_type == 0) { float x = ImGui::CalcItemWidth(); if (ImPlot::BeginPlot(label.c_str(), {x, x})) { + ImPlot::SetupAxes(nullptr, nullptr, ImPlotAxisFlags_AutoFit, ImPlotAxisFlags_AutoFit); ImPlot::PlotHistogram2D(label.c_str(), iq_data->real.data(), iq_data->imag.data(), @@ -217,6 +219,7 @@ class IQHist { } else if (plot_type == 2) { float x = ImGui::CalcItemWidth(); if (ImPlot::BeginPlot(label.c_str(), {x, x})) { + ImPlot::SetupAxes(nullptr, nullptr, ImPlotAxisFlags_AutoFit, ImPlotAxisFlags_AutoFit); int points_drawn = 0; while (points_drawn < iq_data->len) { // Limit the amount of data plotted with PlotScatter call (issue with vertices/draw call) @@ -232,6 +235,7 @@ class IQHist { } } else if (plot_type == 1) { if (ImPlot::BeginPlot(label.c_str())) { + ImPlot::SetupAxes(nullptr, nullptr, ImPlotAxisFlags_AutoFit, ImPlotAxisFlags_AutoFit); ImPlot::PlotLine(label.c_str(), iq_data->power.data(), iq_data->len); ImPlot::EndPlot(); } @@ -364,6 +368,7 @@ class IQSlotHeatmap { static std::vector symbol_boundaries = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; if (ImPlot::BeginPlot(label.c_str(), {(float)ImGui::GetWindowWidth() * 0.9f, 0})) { auto num_sc = num_rb * NR_NB_SC_PER_RB; + ImPlot::SetupAxes(nullptr, nullptr, ImPlotAxisFlags_AutoFit, ImPlotAxisFlags_AutoFit); ImPlot::SetupAxes("symbols", "subcarriers"); ImPlot::SetupAxisLimits(ImAxis_X1, num_symbols, 0); ImPlot::SetupAxisLimits(ImAxis_Y1, num_sc, 0); @@ -429,6 +434,7 @@ void ShowUeScope(void *data_void_ptr, float t) rbs_buffer.AddPoint(t, getKPIUE()->nofRBs); bler.AddPoint(t, (float)getKPIUE()->nb_nack / (float)getKPIUE()->nb_total); mcs.AddPoint(t, (float)getKPIUE()->dl_mcs); + ImPlot::SetupAxes(nullptr, nullptr, ImPlotAxisFlags_AutoFit, ImPlotAxisFlags_AutoFit); ImPlot::SetupAxes("time", "noOfRbs"); ImPlot::SetupAxisLimits(ImAxis_X1, t - history, t, ImGuiCond_Always); ImPlot::SetupAxisLimits(ImAxis_Y1, 0, NR_MAX_RB); From 05570bb8d825560c3a93113136e65c651358bf89 Mon Sep 17 00:00:00 2001 From: Nada Bouknana Date: Tue, 11 Nov 2025 14:06:31 +0100 Subject: [PATCH 13/80] move global scope settings to a menu item --- openair1/PHY/TOOLS/imscope/imscope.cpp | 31 +++++++++++++++++--------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/openair1/PHY/TOOLS/imscope/imscope.cpp b/openair1/PHY/TOOLS/imscope/imscope.cpp index a858409d9e..a80b5cfd98 100644 --- a/openair1/PHY/TOOLS/imscope/imscope.cpp +++ b/openair1/PHY/TOOLS/imscope/imscope.cpp @@ -733,6 +733,7 @@ void *imscope_thread(void *data_void_ptr) static float t = 0; static bool show_imgui_demo_window = false; static bool show_implot_demo_window = false; + static bool show_scope_settings_window = false; ImGui::DockSpaceOverViewport(); if (ImGui::BeginMainMenuBar()) { if (ImGui::BeginMenu("File")) { @@ -752,6 +753,12 @@ void *imscope_thread(void *data_void_ptr) } ImGui::EndMenu(); } + if (ImGui::BeginMenu("Settings")) { + if (ImGui::MenuItem("Global scope settings")) { + show_scope_settings_window = !show_scope_settings_window; + } + ImGui::EndMenu(); + } ImGui::EndMainMenuBar(); } @@ -762,16 +769,6 @@ void *imscope_thread(void *data_void_ptr) } ImGui::End(); - ImGui::Begin("Global scope settings"); - ImGui::ShowStyleSelector("ImGui Style"); - ImPlot::ShowStyleSelector("ImPlot Style"); - ImPlot::ShowColormapSelector("ImPlot Colormap"); - ImGui::SliderInt("FPS target", &target_fps, 12, 60); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Reduces scope flickering in unfrozen mode. Can reduce impact on perfromance of the modem"); - } - ImGui::End(); - t += ImGui::GetIO().DeltaTime; iq_procedure_timer.UpdateAverage(t); @@ -788,7 +785,19 @@ void *imscope_thread(void *data_void_ptr) ImPlot::ShowDemoWindow(); if (show_imgui_demo_window) ImGui::ShowDemoWindow(); - + // Settings + if (show_scope_settings_window) { + ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f)); + ImGui::Begin("Global scope settings", &show_scope_settings_window); + ImGui::ShowStyleSelector("ImGui Style"); + ImPlot::ShowStyleSelector("ImPlot Style"); + ImPlot::ShowColormapSelector("ImPlot Colormap"); + ImGui::SliderInt("FPS target", &target_fps, 12, 60); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Reduces scope flickering in unfrozen mode. Can reduce impact on perfromance of the modem"); + } + ImGui::End(); + } // Rendering ImGui::Render(); glViewport(0, 0, display_w, display_h); From 1d235ce6fa72aa245bd76c895af39a85976d7c2e Mon Sep 17 00:00:00 2001 From: Nada Bouknana Date: Tue, 11 Nov 2025 14:38:30 +0100 Subject: [PATCH 14/80] modify the default imscope docking layout from imgui.ini --- openair1/PHY/TOOLS/imscope/imgui.ini | 286 ++++++++++++++++++++++----- 1 file changed, 232 insertions(+), 54 deletions(-) diff --git a/openair1/PHY/TOOLS/imscope/imgui.ini b/openair1/PHY/TOOLS/imscope/imgui.ini index 3fc08b6f7c..f3269ebfc6 100644 --- a/openair1/PHY/TOOLS/imscope/imgui.ini +++ b/openair1/PHY/TOOLS/imscope/imgui.ini @@ -1,13 +1,47 @@ +[Window][WindowOverViewport_11111111] +Pos=0,19 +Size=1920,927 +Collapsed=0 + [Window][Debug##Default] Pos=60,60 Size=400,400 Collapsed=0 +[Window][Status bar] +Pos=0,914 +Size=1920,32 +Collapsed=0 +DockId=0x00000004,0 + +[Window][Global scope settings] +Pos=697,153 +Size=545,478 +Collapsed=0 + +[Window][PUSCH SLOT IQ] +Pos=0,257 +Size=789,655 +Collapsed=0 +DockId=0x0000000B,0 + +[Window][PUSCH LLRs] +Pos=791,257 +Size=1129,655 +Collapsed=0 +DockId=0x0000000C,0 + +[Window][Time domain samples] +Pos=997,201 +Size=923,711 +Collapsed=0 +DockId=0x0000000E,0 + [Window][NR KPI] Pos=0,19 Size=1133,667 Collapsed=0 -DockId=0x00000005,0 +DockId=0x00000007,0 [Window][Dear ImGui Demo] Pos=531,19 @@ -21,79 +55,223 @@ Size=529,667 Collapsed=0 DockId=0x00000002,0 -[Window][WindowOverViewport_11111111] -Pos=0,19 -Size=1280,701 -Collapsed=0 - -[Window][Status bar] -Pos=0,688 -Size=1280,32 -Collapsed=0 -DockId=0x00000004,0 - -[Window][Global scope settings] -Pos=1038,19 -Size=242,667 -Collapsed=0 -DockId=0x00000006,0 - [Window][UE KPI] -Pos=532,19 -Size=528,667 +Pos=0,19 +Size=1920,180 Collapsed=0 -DockId=0x00000008,0 +DockId=0x00000007,0 [Window][UE PDSCH IQ] -Pos=0,19 -Size=530,667 +Pos=997,201 +Size=923,711 Collapsed=0 -DockId=0x00000005,1 - -[Window][Time domain samples] -Pos=0,19 -Size=1036,667 -Collapsed=0 -DockId=0x00000005,0 +DockId=0x0000000E,3 [Window][Time domain samples - before sync] -Pos=0,19 -Size=530,667 +Pos=0,201 +Size=995,711 Collapsed=0 -DockId=0x00000005,2 +DockId=0x0000000D,0 [Window][Broadcast channel] -Pos=0,19 -Size=530,667 +Pos=997,201 +Size=923,711 Collapsed=0 -DockId=0x00000005,3 +DockId=0x0000000E,1 [Window][RX IQ] Pos=532,19 Size=528,667 Collapsed=0 -DockId=0x00000008,0 +DockId=0x00000001,0 -[Window][PUSCH SLOT IQ] -Pos=0,19 -Size=1036,667 +[Window][UE PDSCH Chan est] +Pos=997,201 +Size=923,711 Collapsed=0 -DockId=0x00000005,1 +DockId=0x0000000E,2 -[Window][PUSCH LLRs] -Pos=0,19 -Size=1036,667 +[Window][UE PDSCH IQ before compensation] +Pos=0,201 +Size=995,711 Collapsed=0 -DockId=0x00000005,2 +DockId=0x0000000D,1 + +[Window][gNB Scope] +Pos=-4,30 +Size=1728,834 +Collapsed=0 + +[Window][UE Scope] +Pos=-1,23 +Size=1922,902 +Collapsed=0 + +[Window][Dear ImGui Demo/##Basket_379447C1] +IsChild=1 +Size=1202,260 + +[Window][Dear ImGui Demo/ResizableChild_D5443E47] +IsChild=1 +Size=1153,32 + +[Window][Dear ImGui Demo/Red_1D4E05CE] +IsChild=1 +Size=200,100 + +[Window][Delete?] +Pos=804,420 +Size=311,105 +Collapsed=0 + +[Window][Stacked 1] +Pos=755,387 +Size=409,172 +Collapsed=0 + +[Window][Example: Simple layout] +Pos=354,164 +Size=981,698 +Collapsed=0 + +[Window][Example: Simple layout/left pane_AED60EF8] +IsChild=1 +Size=150,644 + +[Window][Example: Log] +Pos=60,60 +Size=500,400 +Collapsed=0 + +[Window][Example: Auto-resizing window] +Pos=179,108 +Size=654,437 +Collapsed=0 + +[Window][gNB Scope/##pusch_time_domain_5637DE0C] +IsChild=1 +Size=1728,302 + +[Window][gNB Scope/##pusch_iq_903C5250] +IsChild=1 +Size=408,500 + +[Window][gNB Scope/##pusch_llr_FE553CCC] +IsChild=1 +Size=1443,502 + +[Window][Dear ImGui Demo/##Tree_C1CE970E] +IsChild=1 +Size=1132,260 + +[Window][Dear ImGui Demo/##Basket_97A64F14] +IsChild=1 +Size=1132,260 + +[Window][Dear ImGui Demo/##Basket_745C408A] +IsChild=1 +Size=1132,260 + +[Window][UE Scope/##ue_kpi_A22981AC] +IsChild=1 +Size=1839,183 + +[Window][UE Scope/##ue_iq_plots_F23AA7B4] +IsChild=1 +Size=814,517 + +[Window][UE Scope/##ue_plots0_D75041C0] +IsChild=1 +Size=1067,610 + +[Window][UE Scope/##ue_plots1_A0577156] +IsChild=1 +Size=733,604 + +[Window][UE PDCCH IQ] +Pos=997,201 +Size=923,711 +Collapsed=0 +DockId=0x0000000E,4 + +[Window][UE PDCCH LLR] +Pos=0,201 +Size=995,711 +Collapsed=0 +DockId=0x0000000D,2 + +[Table][0xC9935533,3] +Column 0 Weight=1.0000 +Column 1 Weight=1.0000 +Column 2 Weight=1.0000 + +[Table][0xE0773582,3] +Column 0 Weight=1.0000 +Column 1 Weight=1.0000 +Column 2 Weight=1.0000 + +[Table][0x45A0E60D,7] +RefScale=13 +Column 0 Width=49 +Column 1 Width=112 +Column 2 Width=112 +Column 3 Width=112 +Column 4 Width=112 +Column 5 Width=112 +Column 6 Width=112 + +[Table][0xDA36A7E0,6] +RefScale=13 +Column 0 Width=28 Sort=0v +Column 1 Width=42 +Column 2 Width=73 +Column 3 Width=68 +Column 4 Weight=1.0000 +Column 5 Width=-1 + +[Table][0x0919F5A2,14] +RefScale=13 +Column 0 Width=56 +Column 1 Width=19 +Column 2 Width=19 +Column 3 Width=19 +Column 4 Width=19 +Column 5 Width=19 +Column 6 Width=19 +Column 7 Width=19 +Column 8 Width=19 +Column 9 Width=19 +Column 10 Width=19 +Column 11 Width=19 +Column 12 Width=19 +Column 13 Width=19 + +[Table][0x8DFA6E86,2] +Column 0 Weight=1.0000 +Column 1 Weight=1.0000 + +[Table][0xFABAAEF7,2] +Column 0 Weight=1.0000 +Column 1 Weight=1.0000 + +[Table][0xC179E37C,3] +RefScale=13 +Column 0 Width=108 Sort=0v +Column 1 Width=63 +Column 2 Width=-1 [Docking][Data] -DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,19 Size=1280,701 Split=Y Selected=0x71C89FCB - DockNode ID=0x00000003 Parent=0x7C6B3D9B SizeRef=1280,667 Split=X - DockNode ID=0x00000001 Parent=0x00000003 SizeRef=1319,720 Split=X Selected=0x6627CA6C - DockNode ID=0x00000007 Parent=0x00000001 SizeRef=530,667 Split=X Selected=0x93FDECFF - DockNode ID=0x00000005 Parent=0x00000007 SizeRef=1036,334 CentralNode=1 Selected=0x93FDECFF - DockNode ID=0x00000006 Parent=0x00000007 SizeRef=242,334 Selected=0xFAA8D9D5 - DockNode ID=0x00000008 Parent=0x00000001 SizeRef=528,667 Selected=0x6627CA6C - DockNode ID=0x00000002 Parent=0x00000003 SizeRef=529,720 Selected=0xB903C8C9 - DockNode ID=0x00000004 Parent=0x7C6B3D9B SizeRef=1280,32 HiddenTabBar=1 Selected=0xD9B9B9C7 +DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,19 Size=1920,927 Split=Y Selected=0x71C89FCB + DockNode ID=0x00000003 Parent=0x7C6B3D9B SizeRef=1280,667 Split=X + DockNode ID=0x00000001 Parent=0x00000003 SizeRef=1319,720 Split=Y Selected=0x6627CA6C + DockNode ID=0x00000009 Parent=0x00000001 SizeRef=1920,236 Split=Y Selected=0x6627CA6C + DockNode ID=0x00000007 Parent=0x00000009 SizeRef=1920,180 CentralNode=1 Selected=0x6627CA6C + DockNode ID=0x00000008 Parent=0x00000009 SizeRef=1920,711 Split=X Selected=0x3A5D5B36 + DockNode ID=0x0000000D Parent=0x00000008 SizeRef=995,711 Selected=0xF0B5A18D + DockNode ID=0x0000000E Parent=0x00000008 SizeRef=923,711 Selected=0x752F58D8 + DockNode ID=0x0000000A Parent=0x00000001 SizeRef=1920,655 Split=X Selected=0x93FDECFF + DockNode ID=0x0000000B Parent=0x0000000A SizeRef=789,444 Selected=0x93FDECFF + DockNode ID=0x0000000C Parent=0x0000000A SizeRef=1129,444 Selected=0x43E927D5 + DockNode ID=0x00000002 Parent=0x00000003 SizeRef=529,720 Selected=0xB903C8C9 + DockNode ID=0x00000004 Parent=0x7C6B3D9B SizeRef=1280,32 HiddenTabBar=1 Selected=0xD9B9B9C7 From 812420348184073fa5b2d89ffbecba0e6c115c1e Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Mon, 10 Nov 2025 09:48:45 +0100 Subject: [PATCH 15/80] gNB: fix MAC TA command scheduling if measurement gaps are configured In the current implementation, if UE transmission is interrupted via nr_mac_interrupt_ue_transmission(), UE_sched_ctrl.ta_frame is modified to be the previous frame avoiding TA scheduling in the measurement gap. So the next scheduled TA is shifted to be in 99 frames. As there are other measurement gaps before that, the scheduled TA is always shifted, but actually never reached, effectively disabling the MAC TA commands. To fix this, UE_sched_ctrl.ta_frame is changed to not indicate the last TA command transmission, but the next one. This allows to check in nr_mac_interrupt_ue_transmission() if the next TA command transmission is within the measurement gap and if so shift it to just after that gap. --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 16 ++++++++-------- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 18 ++++++++++-------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 2 +- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 1 - 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index d848cf99c8..1466099ab1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -649,9 +649,8 @@ static void pf_dl(gNB_MAC_INST *mac, stats->current_bytes = 0; stats->current_rbs = 0; - /* Check if this UE should get TA (every 100 frames). If we add the CE, - * ta_apply will be reset */ - if (frame == ((sched_ctrl->ta_frame + 100) % 1024)) + /* Check if this UE should get TA. If we add the CE, ta_apply will be reset */ + if (frame == sched_ctrl->ta_frame) sched_ctrl->ta_apply = true; int total_rem_ues = 0; @@ -690,7 +689,7 @@ static void pf_dl(gNB_MAC_INST *mac, update_dlsch_buffer(pp_pdsch->frame, pp_pdsch->slot, UE); /* Check DL buffer and skip this UE if no bytes and no TA necessary */ - if (sched_ctrl->num_total_bytes == 0 && frame != (sched_ctrl->ta_frame + 100) % 1024) + if (sched_ctrl->num_total_bytes == 0 && sched_ctrl->ta_apply == false) continue; /* Calculate coeff */ @@ -871,8 +870,8 @@ static void pf_dl(gNB_MAC_INST *mac, // awaiting. Therefore, for the time being, we put a fixed overhead of 12 // (for 4 PDUs) and optionally + 2 for TA. Once RLC gives the number of // PDUs, we replace with 3 * numPDUs - const int oh = 3 * 4 + 2 * (frame == (sched_ctrl->ta_frame + 100) % 1024); - //const int oh = 3 * sched_ctrl->dl_pdus_total + 2 * (frame == (sched_ctrl->ta_frame + 100) % 1024); + const int oh = 3 * 4 + (sched_ctrl->ta_apply ? 2 : 0); + //const int oh = 3 * sched_ctrl->dl_pdus_total + (sched_ctrl->ta_apply ? 2 : 0); nr_find_nb_rb(sched_pdsch.Qm, sched_pdsch.R, 1, // no transform precoding for DL @@ -1349,8 +1348,9 @@ void post_process_dlsch(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pdsch, NR_UE // ta command is sent, values are reset if (sched_ctrl->ta_apply) { sched_ctrl->ta_apply = false; - sched_ctrl->ta_frame = frame; - LOG_D(NR_MAC, "%d.%2d UE %04x TA scheduled, resetting TA frame\n", frame, slot, UE->rnti); + sched_ctrl->ta_update = 31; + sched_ctrl->ta_frame = (frame + 100) % MAX_FRAME_NUMBER; + LOG_D(NR_MAC, "%d.%2d UE %04x TA scheduled, setting next TA frame to %d\n", frame, slot, UE->rnti, sched_ctrl->ta_frame); } T(T_GNB_MAC_DL_PDU_WITH_DATA, T_INT(module_id), T_INT(CC_id), T_INT(rnti), diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index a81841d9c0..128f2db336 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -125,6 +125,8 @@ static const uint16_t cqi_table3[16][2] = {{0, 0}, static void determine_aggregation_level_search_order(int agg_level_search_order[NUM_PDCCH_AGG_LEVELS], float pdcch_cl_adjust); +static int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, int slots, int slots_per_frame); + uint8_t get_dl_nrOfLayers(const NR_UE_sched_ctrl_t *sched_ctrl, const nr_dci_format_t dci_format) { // TODO check this but it should be enough for now @@ -3435,7 +3437,7 @@ void nr_measgap_scheduling(gNB_MAC_INST *nr_mac, frame_t frame, sub_frame_t slot continue; const int slots_frame = nr_mac->frame_structure.numb_slots_frame; - const frame_t f = (frame + (slot + mgc->n_slots_advance) / slots_frame) % 1024; + const frame_t f = (frame + (slot + mgc->n_slots_advance) / slots_frame) % MAX_FRAME_NUMBER; const slot_t s = (slot + mgc->n_slots_advance) % slots_frame; // TS 38 331 - Section 5.5.2.9 Measurement gap configuration @@ -3446,7 +3448,7 @@ void nr_measgap_scheduling(gNB_MAC_INST *nr_mac, frame_t frame, sub_frame_t slot // start a timer to stop scheduling UE during MeasGap, or extend timer for // duration of measGap with existing follow-up action if (!nr_timer_is_active(t) || nr_timer_remaining_time(t) < mgc->mgl_slots) { - nr_mac_interrupt_ue_transmission(nr_mac, UE, mgc->mgl_slots); + nr_mac_interrupt_ue_transmission(nr_mac, UE, mgc->mgl_slots, slots_frame); } } } @@ -3530,7 +3532,7 @@ int nr_mac_get_reconfig_delay_slots(NR_SubcarrierSpacing_t scs) return (delay_ms << scs) + sl_ahead; } -int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, int slots) +static int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, int slots, int slots_per_frame) { DevAssert(mac != NULL); DevAssert(UE != NULL); @@ -3539,11 +3541,11 @@ int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, int sl nr_timer_setup(&UE->UE_sched_ctrl.transm_interrupt, slots, 1); nr_timer_start(&UE->UE_sched_ctrl.transm_interrupt); - // it might happen that timing advance command should be sent during the UE - // inactivity time. To prevent this, set a variable as if we would have just - // sent it. This way, another TA command will for sure be sent in some - // frames, after the inactivity of the UE. - UE->UE_sched_ctrl.ta_frame = (mac->frame - 1 + 1024) % 1024; + // it might happen that timing advance command should be sent during the UE inactivity time. + // To prevent this, delay next TA command just after the UE inactivity time. + const int inactive_frames = slots / slots_per_frame + 1; + if ((UE->UE_sched_ctrl.ta_frame - mac->frame + MAX_FRAME_NUMBER) % MAX_FRAME_NUMBER < inactive_frames) + UE->UE_sched_ctrl.ta_frame = (mac->frame + inactive_frames) % MAX_FRAME_NUMBER; LOG_D(NR_MAC, "UE %04x: Interrupt UE transmission (%d slots)\n", UE->rnti, slots); return 0; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 94325bf26b..17a4ad5a42 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -811,7 +811,7 @@ static void nr_rx_ra_sdu(const module_id_t mod_id, } // re-initialize ta update variables after RA procedure completion - UE->UE_sched_ctrl.ta_frame = frame; + UE->UE_sched_ctrl.ta_frame = (frame + 100) % MAX_FRAME_NUMBER; LOG_A(NR_MAC, "%4d.%2d PUSCH with TC_RNTI 0x%04x received correctly\n", frame, slot, rnti); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index cfe02755b2..41f6fd5755 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -65,7 +65,6 @@ void nr_mac_prepare_ra_ue(gNB_MAC_INST *nrmac, NR_UE_info_t *UE); bool add_new_UE_RA(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE); int nr_mac_get_reconfig_delay_slots(NR_SubcarrierSpacing_t scs); -int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, int slots); int nr_transmission_action_indicator_stop(gNB_MAC_INST *mac, NR_UE_info_t *UE_info); void clear_nr_nfapi_information(gNB_MAC_INST *gNB, From 4057cdaa80218a71f2e0f8b22de6ba5ce54a1964 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Mon, 10 Nov 2025 13:32:36 +0000 Subject: [PATCH 16/80] NR UE: correctly provide measured SSB SINR value from PHY to MAC Fixes: e5ea77f629f7cc8be8756ae837de30b455a6d386 --- openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c index 7d6ab8e6f2..4c8c57d9fd 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c @@ -236,6 +236,7 @@ void nr_ue_ssb_rsrp_measurements(PHY_VARS_NR_UE *ue, .meas_type = NFAPI_NR_SS_MEAS, .Nid_cell = ue->frame_parms.Nid_cell, .rsrp_dBm = ue->measurements.ssb_rsrp_dBm[ssb_index], + .sinr_dB = ue->measurements.ssb_sinr_dB[ssb_index], .ssb_index = ssb_index, .is_neighboring_cell = false, }; From 561fbf56368888e18a939aa813a8089370552f64 Mon Sep 17 00:00:00 2001 From: Reem Bahsoun Date: Wed, 12 Nov 2025 10:29:49 +0100 Subject: [PATCH 17/80] Modify aerial config file to improve UL throughput when using 2L layer. --- ci-scripts/conf_files/gnb-vnf.sa.band78.273prb.aerial.conf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ci-scripts/conf_files/gnb-vnf.sa.band78.273prb.aerial.conf b/ci-scripts/conf_files/gnb-vnf.sa.band78.273prb.aerial.conf index f26891d8f2..9446d08ebf 100644 --- a/ci-scripts/conf_files/gnb-vnf.sa.band78.273prb.aerial.conf +++ b/ci-scripts/conf_files/gnb-vnf.sa.band78.273prb.aerial.conf @@ -32,7 +32,7 @@ gNBs = pdsch_AntennaPorts_N1 = 2; pusch_AntennaPorts = 2; do_CSIRS = 1; - do_SRS = 0; + do_SRS = 1; min_rxtxtime = 2; servingCellConfigCommon = ( @@ -155,7 +155,7 @@ gNBs = nrofUplinkSlots = 3; #1; nrofUplinkSymbols = 0; - ssPBCH_BlockPower = -25; + ssPBCH_BlockPower = -15; } ); @@ -195,7 +195,7 @@ MACRLCs = ( remote_s_portd = 50010; // pnf p7 port [!] tr_s_preference = "aerial"; tr_n_preference = "local_RRC"; - pusch_TargetSNRx10 = 200; # 150; + pusch_TargetSNRx10 = 280; # 150; pucch_TargetSNRx10 = 200; #200; dl_max_mcs = 28; ul_max_mcs = 28; From 4cc6275a7d04016dcad1c43848ec82bba87e6c4d Mon Sep 17 00:00:00 2001 From: Reem Bahsoun Date: Wed, 12 Nov 2025 10:39:36 +0100 Subject: [PATCH 18/80] Update XML file to increase tested DL and UL throughput for CI. --- ci-scripts/xml_files/container_sa_aerial_quectel.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ci-scripts/xml_files/container_sa_aerial_quectel.xml b/ci-scripts/xml_files/container_sa_aerial_quectel.xml index 05d35d0171..bf3f702219 100644 --- a/ci-scripts/xml_files/container_sa_aerial_quectel.xml +++ b/ci-scripts/xml_files/container_sa_aerial_quectel.xml @@ -88,8 +88,8 @@ Iperf - iperf (DL/UDP/500M)(30 sec)(single-ue profile) - -u -b 500M -t 30 -R + iperf (DL/UDP/800M)(30 sec)(single-ue profile) + -u -b 800M -t 30 -R oc-cn5g-20897-aerial up2-aerial 25 @@ -98,8 +98,8 @@ Iperf - iperf (UL/UDP/40M)(30 sec)(single-ue profile) - -u -b 40M -t 30 -l 1428 + iperf (UL/UDP/150M)(30 sec)(single-ue profile) + -u -b 150M -t 30 -l 1428 oc-cn5g-20897-aerial up2-aerial 25 @@ -119,9 +119,9 @@ Iperf - Optional iperf (UL/UDP/90M)(30 sec)(single-ue profile) + Optional iperf (UL/UDP/200M)(30 sec)(single-ue profile) true - -u -b 90M -t 30 -l 1428 + -u -b 200M -t 30 -l 1428 oc-cn5g-20897-aerial up2-aerial 25 From 6471d91e2aaf687acab219d9d494508d1517b910 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 6 Nov 2025 13:23:49 +0100 Subject: [PATCH 19/80] Correct PNF config: sl_ahead to 2 Using nFAPI introduces additional delays. At the same time, RFsim does not run in real-time, and we can allow a low sl_ahead, as RFsim will "wait" for the gNB. Therefore, reduce sl_ahead to ensure that the response window does not run out during handling of RA in nFAPI. --- targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-pnf.band78.rfsim.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-pnf.band78.rfsim.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-pnf.band78.rfsim.conf index 887ff6eced..08691c3b62 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-pnf.band78.rfsim.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-pnf.band78.rfsim.conf @@ -22,6 +22,7 @@ RUs = ({ att_tx = 0 att_rx = 0; bands = [78]; + sl_ahead = 2; max_pdschReferenceSignalPower = -27; max_rxgain = 125; }); From 27203c9504553eda85fcc6da43ed67a572e7d449 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 5 Nov 2025 14:44:15 +0100 Subject: [PATCH 20/80] Remove useless function definitions Unused code --- CMakeLists.txt | 8 +--- openair1/SCHED/nfapi_lte_dummy.c | 18 --------- openair1/SCHED/nfapi_nr_dummy.c | 49 ----------------------- openair1/SCHED_NR/fapi_nr_l1.c | 5 +-- openair1/SCHED_NR/fapi_nr_l1.h | 32 --------------- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 28 ++++++++----- 6 files changed, 22 insertions(+), 118 deletions(-) delete mode 100644 openair1/SCHED/nfapi_nr_dummy.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 57d165ea05..c5f54f1e67 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1283,12 +1283,6 @@ set (MISC_NFAPI_LTE add_library(MISC_NFAPI_LTE_LIB ${MISC_NFAPI_LTE}) -set (MISC_NFAPI_NR - ${OPENAIR1_DIR}/SCHED/nfapi_nr_dummy.c - ) - -add_library(MISC_NFAPI_NR_LIB ${MISC_NFAPI_NR}) - add_library(L2 ${L2_SRC} ${MAC_SRC} @@ -2091,7 +2085,7 @@ if (${T_TRACER}) oai_eth_transpro HASHTABLE UTIL SECURITY SCHED_LIB SCHED_NR_LIB SCHED_RU_LIB SCHED_UE_LIB SCHED_NR_UE_LIB NFAPI_LIB NFAPI_PNF_LIB NFAPI_VNF_LIB NFAPI_USER_LIB - MISC_NFAPI_LTE_LIB MISC_NFAPI_NR_LIB + MISC_NFAPI_LTE_LIB PHY_COMMON PHY PHY_UE PHY_NR PHY_NR_COMMON PHY_NR_UE PHY_RU L2 L2_LTE L2_NR L2_LTE_NR L2_UE NR_L2_UE MAC_NR_COMMON MAC_UE_NR ngap GTPV1U SCTP_CLIENT MME_APP LIB_NAS_UE SIMU diff --git a/openair1/SCHED/nfapi_lte_dummy.c b/openair1/SCHED/nfapi_lte_dummy.c index be532a0c54..3e56b51fc1 100644 --- a/openair1/SCHED/nfapi_lte_dummy.c +++ b/openair1/SCHED/nfapi_lte_dummy.c @@ -9,30 +9,12 @@ typedef struct pnf_p7_t pnf_p7_t; typedef struct vnf_t vnf_t; typedef struct vnf_p7_t vnf_p7_t; -void handle_nfapi_nr_pdcch_pdu(PHY_VARS_gNB *gNB, - int frame, int slot, - nfapi_nr_dl_tti_pdcch_pdu *pdcch_pdu){} - -void handle_nr_nfapi_ssb_pdu(PHY_VARS_gNB *gNB,int frame,int slot, - nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdu){} - -void handle_nr_nfapi_pdsch_pdu(processingData_L1tx_t *msgTx, - nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu, - uint8_t *sdu){ -} -void handle_nfapi_nr_csirs_pdu(processingData_L1tx_t *msgTx, - int frame, int slot, - nfapi_nr_dl_tti_csi_rs_pdu *csirs_pdu){ - } int l1_north_init_gNB(void){return 0;} int slot_ahead = 6; //uint8_t nfapi_mode=0; NR_IF_Module_t *NR_IF_Module_init(int Mod_id) {return NULL;} -void handle_nfapi_nr_ul_dci_pdu(PHY_VARS_gNB *gNB, - int frame, int slot, - nfapi_nr_ul_dci_request_pdus_t *ul_dci_request_pdu){} void nr_fill_ulsch(PHY_VARS_gNB *gNB, int frame, int slot, diff --git a/openair1/SCHED/nfapi_nr_dummy.c b/openair1/SCHED/nfapi_nr_dummy.c deleted file mode 100644 index 7377a455dd..0000000000 --- a/openair1/SCHED/nfapi_nr_dummy.c +++ /dev/null @@ -1,49 +0,0 @@ -//Dummy NR defs to avoid linking errors - -#include "PHY/defs_gNB.h" -#include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h" -#include "openair2/NR_PHY_INTERFACE/NR_IF_Module.h" -#include "openair1/PHY/LTE_TRANSPORT/transport_common.h" - -void handle_nfapi_nr_pdcch_pdu(PHY_VARS_gNB *gNB, - int frame, int slot, - nfapi_nr_dl_tti_pdcch_pdu *pdcch_pdu){} - -void handle_nr_nfapi_ssb_pdu(PHY_VARS_gNB *gNB,int frame,int slot, - nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdu){} - -void handle_nr_nfapi_pdsch_pdu(processingData_L1tx_t *msgTx, - nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu, - uint8_t *sdu){ -} -void handle_nfapi_nr_csirs_pdu(processingData_L1tx_t *msgTx, - int frame, int slot, - nfapi_nr_dl_tti_csi_rs_pdu *csirs_pdu){ - } -int l1_north_init_gNB(void){return 0;} - -int slot_ahead = 6; -//uint8_t nfapi_mode=0; -NR_IF_Module_t *NR_IF_Module_init(int Mod_id) {return NULL;} - -void handle_nfapi_nr_ul_dci_pdu(PHY_VARS_gNB *gNB, - int frame, int slot, - nfapi_nr_ul_dci_request_pdus_t *ul_dci_request_pdu){} -void nr_fill_ulsch(PHY_VARS_gNB *gNB, - int frame, - int slot, - nfapi_nr_pusch_pdu_t *ulsch_pdu){} -void nr_fill_pucch(PHY_VARS_gNB *gNB, - int frame, - int slot, - nfapi_nr_pucch_pdu_t *pucch_pdu){} -void nr_schedule_rx_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) -{ -} - -void nr_phy_config_request(NR_PHY_Config_t *gNB){} - -void install_nr_schedule_handlers(NR_IF_Module_t *if_inst){} - -//void nr_dump_frame_parms(NR_DL_FRAME_PARMS *fp){} - diff --git a/openair1/SCHED_NR/fapi_nr_l1.c b/openair1/SCHED_NR/fapi_nr_l1.c index 9e4ab67efc..7b27b51c02 100644 --- a/openair1/SCHED_NR/fapi_nr_l1.c +++ b/openair1/SCHED_NR/fapi_nr_l1.c @@ -38,8 +38,7 @@ #include "openair2/NR_PHY_INTERFACE/nr_sched_response.h" #include "nfapi/oai_integration/nfapi_vnf.h" -void handle_nr_nfapi_ssb_pdu(processingData_L1tx_t *msgTx,int frame,int slot, - nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdu) +static void handle_nr_nfapi_ssb_pdu(processingData_L1tx_t *msgTx, int frame, int slot, nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdu) { AssertFatal(dl_tti_pdu->ssb_pdu.ssb_pdu_rel15.bchPayloadFlag== 1, "bchPayloadFlat %d != 1\n", @@ -56,7 +55,7 @@ void handle_nr_nfapi_ssb_pdu(processingData_L1tx_t *msgTx,int frame,int slot, } } -void handle_nfapi_nr_csirs_pdu(processingData_L1tx_t *msgTx, int frame, int slot, nfapi_nr_dl_tti_csi_rs_pdu *csirs_pdu) +static void handle_nfapi_nr_csirs_pdu(processingData_L1tx_t *msgTx, int frame, int slot, nfapi_nr_dl_tti_csi_rs_pdu *csirs_pdu) { int found = 0; diff --git a/openair1/SCHED_NR/fapi_nr_l1.h b/openair1/SCHED_NR/fapi_nr_l1.h index 59df4fb30d..b8f1b6e238 100644 --- a/openair1/SCHED_NR/fapi_nr_l1.h +++ b/openair1/SCHED_NR/fapi_nr_l1.h @@ -34,36 +34,4 @@ #include "SCHED_NR/sched_nr.h" #include "nfapi_nr_interface_scf.h" -// added -void handle_nr_nfapi_ssb_pdu(processingData_L1tx_t *msgTx, - int frame,int slot, - nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdu); - void nr_schedule_response(NR_Sched_Rsp_t *Sched_INFO); - -void handle_nfapi_nr_csirs_pdu(processingData_L1tx_t *msgTx, - int frame, int slot, - nfapi_nr_dl_tti_csi_rs_pdu *csirs_pdu); - -void handle_nfapi_nr_pdcch_pdu(PHY_VARS_gNB *gNB, - int frame, int subframe, - nfapi_nr_dl_tti_pdcch_pdu *dcl_dl_pdu); - -void handle_nr_nfapi_pdsch_pdu(processingData_L1tx_t *msgTx, - nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu, - uint8_t *sdu); - -void nr_fill_indication(PHY_VARS_gNB *gNB, - int frame, - int slot_rx, - int UE_id, - uint8_t harq_pid, - uint8_t crc_flag, - int dtx_flag, - nfapi_nr_crc_t *crc, - nfapi_nr_rx_data_pdu_t *pdu); -//added - -void handle_nfapi_nr_ul_dci_pdu(PHY_VARS_gNB *gNB, - int frame, int slot, - nfapi_nr_ul_dci_request_pdus_t *ul_dci_request_pdu); diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 51e8c771e5..5111394211 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -46,6 +46,16 @@ //#define DEBUG_RXDATA //#define SRS_IND_DEBUG +static void nr_fill_indication(PHY_VARS_gNB *gNB, + int frame, + int slot_rx, + int ULSCH_id, + uint8_t harq_pid, + uint8_t crc_flag, + int dtx_flag, + nfapi_nr_crc_t *crc, + nfapi_nr_rx_data_pdu_t *pdu); + int beam_index_allocation(bool das, int fapi_beam_index, nfapi_nr_analog_beamforming_ve_t *analog_bf, @@ -537,15 +547,15 @@ static int nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, boo return ret_nr_ulsch_decoding; } -void nr_fill_indication(PHY_VARS_gNB *gNB, - int frame, - int slot_rx, - int ULSCH_id, - uint8_t harq_pid, - uint8_t crc_flag, - int dtx_flag, - nfapi_nr_crc_t *crc, - nfapi_nr_rx_data_pdu_t *pdu) +static void nr_fill_indication(PHY_VARS_gNB *gNB, + int frame, + int slot_rx, + int ULSCH_id, + uint8_t harq_pid, + uint8_t crc_flag, + int dtx_flag, + nfapi_nr_crc_t *crc, + nfapi_nr_rx_data_pdu_t *pdu) { NR_gNB_ULSCH_t *ulsch = &gNB->ulsch[ULSCH_id]; NR_UL_gNB_HARQ_t *harq_process = ulsch->harq_process; From 383c94311e188ee6434f10b79286c55e5f7f67d3 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 5 Nov 2025 15:17:04 +0100 Subject: [PATCH 21/80] Pass big struct through pointer --- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 10 +++++----- openair1/SCHED_NR/sched_nr.h | 2 +- openair1/SIMULATION/NR_PHY/pbchsim.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 5111394211..09415dd86f 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -94,10 +94,10 @@ int beam_index_allocation(bool das, return idx; } -void nr_common_signal_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_dl_tti_ssb_pdu ssb_pdu) +void nr_common_signal_procedures(PHY_VARS_gNB *gNB, int frame, int slot, const nfapi_nr_dl_tti_ssb_pdu *ssb_pdu) { NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; - nfapi_nr_dl_tti_ssb_pdu_rel15_t *pdu = &ssb_pdu.ssb_pdu_rel15; + const nfapi_nr_dl_tti_ssb_pdu_rel15_t *pdu = &ssb_pdu->ssb_pdu_rel15; uint8_t ssb_index = pdu->SsbBlockIndex; LOG_D(PHY,"common_signal_procedures: frame %d, slot %d ssb index %d\n", frame, slot, ssb_index); @@ -145,7 +145,7 @@ void nr_common_signal_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_n fp->ssb_start_subcarrier); LOG_D(PHY,"SS TX: frame %d, slot %d, start_symbol %d\n", frame, slot, ssb_start_symbol); - nfapi_nr_tx_precoding_and_beamforming_t *pb = &pdu->precoding_and_beamforming; + const nfapi_nr_tx_precoding_and_beamforming_t *pb = &pdu->precoding_and_beamforming; c16_t ***txdataF = gNB->common_vars.txdataF; int txdataF_offset = slot * fp->samples_per_slot_wCP; // beam number in a scenario with multiple concurrent beams @@ -183,7 +183,7 @@ void nr_common_signal_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_n #endif nr_generate_pbch(gNB, - &ssb_pdu, + ssb_pdu, &txdataF[beam_nb][0][txdataF_offset], ssb_start_symbol, n_hf, @@ -245,7 +245,7 @@ void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx, VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_COMMON_TX,1); for (int i = 0; i < fp->Lmax; i++) { if (msgTx->ssb[i].active) { - nr_common_signal_procedures(gNB, frame, slot, msgTx->ssb[i].ssb_pdu); + nr_common_signal_procedures(gNB, frame, slot, &msgTx->ssb[i].ssb_pdu); msgTx->ssb[i].active = false; } } diff --git a/openair1/SCHED_NR/sched_nr.h b/openair1/SCHED_NR/sched_nr.h index 40c32c2199..cbec9fa1db 100644 --- a/openair1/SCHED_NR/sched_nr.h +++ b/openair1/SCHED_NR/sched_nr.h @@ -36,7 +36,7 @@ void nr_set_ssb_first_subcarrier(nfapi_nr_config_request_scf_t *cfg, NR_DL_FRAME void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx, int frame_tx, int slot_tx, int do_meas); int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, NR_UL_IND_t *UL_INFO); void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rach_indication_t *rach_ind); -void nr_common_signal_procedures (PHY_VARS_gNB *gNB,int frame,int slot,nfapi_nr_dl_tti_ssb_pdu ssb_pdu); +void nr_common_signal_procedures (PHY_VARS_gNB *gNB,int frame,int slot, const nfapi_nr_dl_tti_ssb_pdu *ssb_pdu); void nr_feptx_ofdm(RU_t *ru,int frame_tx,int tti_tx); void nr_feptx0(RU_t *ru,int tti_tx,int first_symbol, int num_symbols, int aa); void nr_feptx_prec(RU_t *ru,int frame_tx,int tti_tx); diff --git a/openair1/SIMULATION/NR_PHY/pbchsim.c b/openair1/SIMULATION/NR_PHY/pbchsim.c index 4b44b34091..97421130af 100644 --- a/openair1/SIMULATION/NR_PHY/pbchsim.c +++ b/openair1/SIMULATION/NR_PHY/pbchsim.c @@ -541,7 +541,7 @@ int main(int argc, char **argv) for (aa=0; aaframe_parms.nb_antennas_tx; aa++) memset(gNB->common_vars.txdataF[0][aa], 0, frame_parms->samples_per_slot_wCP * sizeof(int32_t)); - nr_common_signal_procedures (gNB,frame,slot,msgDataTx.ssb[i].ssb_pdu); + nr_common_signal_procedures (gNB,frame,slot, &msgDataTx.ssb[i].ssb_pdu); int samp = frame_parms->get_samples_slot_timestamp(slot, frame_parms, 0); for (aa=0; aaframe_parms.nb_antennas_tx; aa++) { From 17ee9db07281d51a4cc7a681b1e454af3f022f89 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 10 Nov 2025 18:29:36 +0100 Subject: [PATCH 22/80] MAC: total_prb_aggregate: collect over carrierBandwidth --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index d848cf99c8..1990eb2e26 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -1387,8 +1387,8 @@ void nr_schedule_ue_spec(module_id_t module_id, return; NR_ServingCellConfigCommon_t *scc = gNB_mac->common_channels[CC_id].ServingCellConfigCommon; - const NR_BWP_t *initialDL = &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; - gNB_mac->mac_stats.total_prb_aggregate += NRRIV2BW(initialDL->locationAndBandwidth, MAX_BWP_SIZE); + int bw = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth; + gNB_mac->mac_stats.total_prb_aggregate += bw; nfapi_nr_dl_tti_request_body_t *dl_req = &DL_req->dl_tti_request_body; post_process_pdsch_t pdsch = { frame, slot, dl_req, TX_req }; From 021b546cf3f79663b2db9f65bead3b8767331cbf Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 24 Oct 2025 16:27:45 +0200 Subject: [PATCH 23/80] Add UL mac stats and create a common struct for both DL and UL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DL stats (aggregated total and used PRBs) previosuly used only for O1 interface, now finds the purpose for E2 interface as well. New UL stats (aggregated total and used PRBs) serve for E2 interface only. Co-authored-by: Teodora Vladiฤ‡ --- common/utils/telnetsrv/telnetsrv_o1.c | 8 ++++---- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 6 +++--- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 2 ++ openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 7 ++++++- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/common/utils/telnetsrv/telnetsrv_o1.c b/common/utils/telnetsrv/telnetsrv_o1.c index ac368885f6..9ff56e3521 100644 --- a/common/utils/telnetsrv/telnetsrv_o1.c +++ b/common/utils/telnetsrv/telnetsrv_o1.c @@ -105,10 +105,10 @@ static int get_stats(char *buf, int debug, telnet_printfunc_t prnt) int bw_index = get_supported_band_index(scs, fr, nrb); int bw_mhz = get_supported_bw_mhz(fr, bw_index); - const mac_stats_t *stat = &mac->mac_stats; - static mac_stats_t last = {0}; - int diff_used = stat->used_prb_aggregate - last.used_prb_aggregate; - int diff_total = stat->total_prb_aggregate - last.total_prb_aggregate; + const dlul_mac_stats_t *stat = &mac->mac_stats; + static dlul_mac_stats_t last = {0}; + int diff_used = stat->dl.used_prb_aggregate - last.dl.used_prb_aggregate; + int diff_total = stat->dl.total_prb_aggregate - last.dl.total_prb_aggregate; int load = diff_total > 0 ? 100 * diff_used / diff_total : 0; last = *stat; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 1990eb2e26..adf091ed7c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -1224,7 +1224,7 @@ void post_process_dlsch(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pdsch, NR_UE T(T_GNB_MAC_RETRANSMISSION_DL_PDU_WITH_DATA, T_INT(module_id), T_INT(CC_id), T_INT(rnti), T_INT(frame), T_INT(slot), T_INT(current_harq_pid), T_INT(harq->round), T_BUFFER(harq->transportBlock.buf, TBS)); UE->mac_stats.dl.total_rbs_retx += sched_pdsch->rbSize; - nr_mac->mac_stats.used_prb_aggregate += sched_pdsch->rbSize; + nr_mac->mac_stats.dl.used_prb_aggregate += sched_pdsch->rbSize; } else { /* initial transmission */ LOG_D(NR_MAC, "Initial HARQ transmission in %d.%d\n", frame, slot); uint8_t *buf = allocate_transportBlock_buffer(&harq->transportBlock, TBS); @@ -1338,7 +1338,7 @@ void post_process_dlsch(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pdsch, NR_UE UE->mac_stats.dl.num_mac_sdu += sdus; UE->mac_stats.dl.current_rbs = sched_pdsch->rbSize; UE->mac_stats.dl.total_sdu_bytes += dlsch_total_bytes; - nr_mac->mac_stats.used_prb_aggregate += sched_pdsch->rbSize; + nr_mac->mac_stats.dl.used_prb_aggregate += sched_pdsch->rbSize; /* save retransmission information */ harq->sched_pdsch = *sched_pdsch; @@ -1388,7 +1388,7 @@ void nr_schedule_ue_spec(module_id_t module_id, NR_ServingCellConfigCommon_t *scc = gNB_mac->common_channels[CC_id].ServingCellConfigCommon; int bw = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth; - gNB_mac->mac_stats.total_prb_aggregate += bw; + gNB_mac->mac_stats.dl.total_prb_aggregate += bw; nfapi_nr_dl_tti_request_body_t *dl_req = &DL_req->dl_tti_request_body; post_process_pdsch_t pdsch = { frame, slot, dl_req, TX_req }; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 94325bf26b..cf699d1bae 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -2455,6 +2455,7 @@ void post_process_ulsch(gNB_MAC_INST *nr_mac, post_process_pusch_t *pusch, NR_UE } UE->mac_stats.ul.current_bytes = sched_pusch->tb_size; UE->mac_stats.ul.current_rbs = sched_pusch->rbSize; + nr_mac->mac_stats.ul.used_prb_aggregate += sched_pusch->rbSize; sched_ctrl->last_ul_frame = sched_pusch->frame; sched_ctrl->last_ul_slot = sched_pusch->slot; @@ -2697,6 +2698,7 @@ static void nr_ulsch_preprocessor(gNB_MAC_INST *nr_mac, post_process_pusch_t *pp int tda = seq_arr_dist(&nr_mac->ul_tda, seq_arr_front(&nr_mac->ul_tda), tda_info); AssertFatal(tda >= 0 && tda < 16, "illegal TDA index %d\n", tda); + nr_mac->mac_stats.ul.total_prb_aggregate += bw; int len[num_beams]; for (int i = 0; i < num_beams; i++) len[i] = rb_len; diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index d6a9ae1497..aa8b2b8644 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -870,6 +870,11 @@ typedef struct { uint64_t used_prb_aggregate; } mac_stats_t; +typedef struct dlul_mac_stats { + mac_stats_t dl; + mac_stats_t ul; +} dlul_mac_stats_t; + /// helper type to encapsulate a frame/slot combination in a single type. /// Currently only used in the UL preprocessor. Note: if you use this type /// further, please refactor it into a common type first. @@ -996,7 +1001,7 @@ typedef struct gNB_MAC_INST_s { pthread_mutex_t sched_lock; - mac_stats_t mac_stats; + dlul_mac_stats_t mac_stats; uint64_t num_scheduled_prach_rx; } gNB_MAC_INST; From d0a582e73d0ac2c1f2c3f070daad8a53a22c3e5b Mon Sep 17 00:00:00 2001 From: Teodora Date: Fri, 24 Oct 2025 16:36:44 +0200 Subject: [PATCH 24/80] Implement E2 node level stats For now, only DL/UL MAC stats. This commit fixes the "RRU.PrbTotDl" and "RRU.PrbTotUl" measurement calculation to align with the TS 28.552 specifications. --- .../E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c | 16 ++++++-- .../RAN_FUNCTION/O-RAN/ran_func_kpm_subs.c | 40 ++++++++++++------- .../RAN_FUNCTION/O-RAN/ran_func_kpm_subs.h | 10 ++++- 3 files changed, 46 insertions(+), 20 deletions(-) diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c index 02760c4984..8933b802a0 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c @@ -54,10 +54,12 @@ typedef struct { ue_id_e2sm_t* ue_id; // Optional - // only used to retreive MAC/RLC stats + // only used to retrieve MAC/RLC stats NR_UE_info_t** ue_info_list; }arr_ue_id_t; +static e2_node_level_stats_t node_stats[2] = {0}; // [0] node stats collected in previous reporting period; [1] current node stats + static meas_data_lst_t fill_kpm_meas_data_item(const meas_info_format_1_lst_t* meas_info_lst, const size_t len, const uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx) { meas_data_lst_t data_item = {0}; @@ -74,7 +76,7 @@ static meas_data_lst_t fill_kpm_meas_data_item(const meas_info_format_1_lst_t* m char* meas_info_name_str = cp_ba_to_str(meas_info_lst[i].meas_type.name); - data_item.meas_record_lst[i] = get_kpm_meas_value(meas_info_name_str, gran_period_ms, ue_info, ue_idx); + data_item.meas_record_lst[i] = get_kpm_meas_value(meas_info_name_str, gran_period_ms, ue_info, ue_idx, node_stats); free(meas_info_name_str); } @@ -153,6 +155,8 @@ static kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3(arr_ue_id_t* arr_ue_id, con msg_frm_3.meas_report_per_ue[i].ind_msg_format_1 = fill_kpm_ind_msg_frm_1(ue_info, i, act_def_fr_1); } + node_stats[0] = cp_node_level_stats(&node_stats[1]); + return msg_frm_3; } @@ -288,8 +292,10 @@ static arr_ue_id_t filter_ues_by_s_nssai_in_du_or_monolithic(const test_info_lst const ngran_node_t node_type = get_e2_node_type(); + gNB_MAC_INST *mac = RC.nrmac[0]; + NR_SCHED_LOCK(&mac->sched_lock); // Take MAC info - UE_iterator(RC.nrmac[0]->UE_info.connected_ue_list, ue) { + UE_iterator(mac->UE_info.connected_ue_list, ue) { NR_UE_sched_ctrl_t *sched_ctrl = &ue->UE_sched_ctrl; // UE matches if any of its DRBs matches for (size_t l = 0; l < seq_arr_size(&sched_ctrl->lc_config); ++l) { @@ -316,6 +322,10 @@ static arr_ue_id_t filter_ues_by_s_nssai_in_du_or_monolithic(const test_info_lst AssertFatal(arr_ue_id.sz < MAX_MOBILES_PER_GNB, "cannot have more UEs than global UE number maximum\n"); } + node_stats[1].mac_stats.dl.total_prb_aggregate = mac->mac_stats.dl.total_prb_aggregate; + node_stats[1].mac_stats.ul.total_prb_aggregate = mac->mac_stats.ul.total_prb_aggregate; + NR_SCHED_UNLOCK(&mac->sched_lock); + free(sd); // if NULL, nothing happens return arr_ue_id; diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.c b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.c index 80579e1754..a8ebe580ab 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.c +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.c @@ -23,6 +23,18 @@ #include +e2_node_level_stats_t cp_node_level_stats(const e2_node_level_stats_t *src) +{ + e2_node_level_stats_t dst = { + .mac_stats.dl.total_prb_aggregate = src->mac_stats.dl.total_prb_aggregate, + .mac_stats.dl.used_prb_aggregate = src->mac_stats.dl.used_prb_aggregate, + .mac_stats.ul.total_prb_aggregate = src->mac_stats.ul.total_prb_aggregate, + .mac_stats.ul.used_prb_aggregate = src->mac_stats.ul.used_prb_aggregate, + }; + + return dst; +} + /* measurements that need to store values from previous reporting period have a limitation when it comes to multiple subscriptions to the same UEs; ric_req_id is unique per subscription */ typedef struct uldlcounter { @@ -46,7 +58,7 @@ static nr_pdcp_statistics_t get_pdcp_stats_per_drb(const uint32_t rrc_ue_id, con /* 3GPP TS 28.522 - section 5.1.2.1.1.1 note: this measurement is calculated as per spec */ -static meas_record_lst_t fill_DRB_PdcpSduVolumeDL(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx) +static meas_record_lst_t fill_DRB_PdcpSduVolumeDL(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, __attribute__((unused))e2_node_level_stats_t* node_stats) { meas_record_lst_t meas_record = {0}; @@ -65,7 +77,7 @@ static meas_record_lst_t fill_DRB_PdcpSduVolumeDL(__attribute__((unused))uint32_ /* 3GPP TS 28.522 - section 5.1.2.1.2.1 note: this measurement is calculated as per spec */ -static meas_record_lst_t fill_DRB_PdcpSduVolumeUL(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx) +static meas_record_lst_t fill_DRB_PdcpSduVolumeUL(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, __attribute__((unused))e2_node_level_stats_t* node_stats) { meas_record_lst_t meas_record = {0}; @@ -103,7 +115,7 @@ static nr_rlc_statistics_t get_rlc_stats_per_drb(const rnti_t rnti, const int rb /* 3GPP TS 28.522 - section 5.1.3.3.3 note: by default this measurement is calculated for previous 100ms (openair2/LAYER2/nr_rlc/nr_rlc_entity.c:118, 173, 213); please, update according to your needs */ -static meas_record_lst_t fill_DRB_RlcSduDelayDl(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, __attribute__((unused))const size_t ue_idx) +static meas_record_lst_t fill_DRB_RlcSduDelayDl(__attribute__((unused))uint32_t gran_period_ms, 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}; @@ -122,7 +134,7 @@ static meas_record_lst_t fill_DRB_RlcSduDelayDl(__attribute__((unused))uint32_t /* 3GPP TS 28.522 - section 5.1.1.3.1 note: per spec, average UE throughput in DL (taken into consideration values from all UEs, and averaged) here calculated as: UE specific throughput in DL */ -static meas_record_lst_t fill_DRB_UEThpDl(uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx) +static meas_record_lst_t fill_DRB_UEThpDl(uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, __attribute__((unused))e2_node_level_stats_t* node_stats) { meas_record_lst_t meas_record = {0}; @@ -141,7 +153,7 @@ static meas_record_lst_t fill_DRB_UEThpDl(uint32_t gran_period_ms, cudu_ue_info_ /* 3GPP TS 28.522 - section 5.1.1.3.3 note: per spec, average UE throughput in UL (taken into consideration values from all UEs, and averaged) here calculated as: UE specific throughput in UL */ -static meas_record_lst_t fill_DRB_UEThpUl(uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx) +static meas_record_lst_t fill_DRB_UEThpUl(uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, __attribute__((unused))e2_node_level_stats_t* node_stats) { meas_record_lst_t meas_record = {0}; @@ -159,32 +171,30 @@ static meas_record_lst_t fill_DRB_UEThpUl(uint32_t gran_period_ms, cudu_ue_info_ } /* 3GPP TS 28.522 - section 5.1.1.2.1 - note: per spec, DL PRB usage [%] = (total used PRBs for DL traffic / total available PRBs for DL traffic) * 100 - here calculated as: aggregated DL PRBs (t) - aggregated DL PRBs (t-gran_period) */ -static meas_record_lst_t fill_RRU_PrbTotDl(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx) + note: this measurement is calculated as per spec */ +static meas_record_lst_t fill_RRU_PrbTotDl(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, e2_node_level_stats_t* node_stats) { meas_record_lst_t meas_record = {0}; meas_record.value = INTEGER_MEAS_VALUE; // Get the number of DL PRBs - meas_record.int_val = ue_info.ue->mac_stats.dl.total_rbs - last_total_prbs[ue_idx].dl; // [PRBs] + meas_record.int_val = (ue_info.ue->mac_stats.dl.total_rbs - last_total_prbs[ue_idx].dl) * 100 / (node_stats[1].mac_stats.dl.total_prb_aggregate - node_stats[0].mac_stats.dl.total_prb_aggregate); // [%] last_total_prbs[ue_idx].dl = ue_info.ue->mac_stats.dl.total_rbs; return meas_record; } /* 3GPP TS 28.522 - section 5.1.1.2.2 - note: per spec, UL PRB usage [%] = (total used PRBs for UL traffic / total available PRBs for UL traffic) * 100 - here calculated as: aggregated UL PRBs (t) - aggregated UL PRBs (t-gran_period) */ -static meas_record_lst_t fill_RRU_PrbTotUl(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx) + note: this measurement is calculated as per spec */ +static meas_record_lst_t fill_RRU_PrbTotUl(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, e2_node_level_stats_t* node_stats) { meas_record_lst_t meas_record = {0}; meas_record.value = INTEGER_MEAS_VALUE; // Get the number of UL PRBs - meas_record.int_val = ue_info.ue->mac_stats.ul.total_rbs - last_total_prbs[ue_idx].ul; // [PRBs] + meas_record.int_val = (ue_info.ue->mac_stats.ul.total_rbs - last_total_prbs[ue_idx].ul) * 100 / (node_stats[1].mac_stats.ul.total_prb_aggregate - node_stats[0].mac_stats.ul.total_prb_aggregate); // [%] last_total_prbs[ue_idx].ul = ue_info.ue->mac_stats.ul.total_rbs; return meas_record; @@ -217,7 +227,7 @@ void init_kpm_subs_data(void) } } -meas_record_lst_t get_kpm_meas_value(char* kpm_meas_name, uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx) +meas_record_lst_t get_kpm_meas_value(char* kpm_meas_name, uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, e2_node_level_stats_t* node_stats) { assert(kpm_meas_name != NULL); @@ -226,7 +236,7 @@ meas_record_lst_t get_kpm_meas_value(char* kpm_meas_name, uint32_t gran_period_m assert(found_entry != NULL && "Unsupported KPM measurement name"); kv_measure_t *kv_found = (kv_measure_t *)found_entry->data; - meas_record_lst_t meas_record = kv_found->value(gran_period_ms, ue_info, ue_idx); + meas_record_lst_t meas_record = kv_found->value(gran_period_ms, ue_info, ue_idx, node_stats); return meas_record; } diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.h b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.h index 7dbd807fa1..e612ca2bab 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.h +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.h @@ -34,7 +34,13 @@ typedef struct { } cudu_ue_info_pair_t; -typedef meas_record_lst_t (*kpm_meas_fp)(uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx); +typedef struct { + dlul_mac_stats_t mac_stats; +} e2_node_level_stats_t; + +e2_node_level_stats_t cp_node_level_stats(const e2_node_level_stats_t *src); + +typedef meas_record_lst_t (*kpm_meas_fp)(uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, e2_node_level_stats_t* node_stats); typedef struct{ char* key; @@ -44,6 +50,6 @@ typedef struct{ void init_kpm_subs_data(void); -meas_record_lst_t get_kpm_meas_value(char* kpm_meas_name, uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx); +meas_record_lst_t get_kpm_meas_value(char* kpm_meas_name, uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, e2_node_level_stats_t* node_stats); #endif From f88b93d14729e911a6dab262967c3ca3147b5e0f Mon Sep 17 00:00:00 2001 From: Teodora Date: Mon, 3 Nov 2025 12:14:50 +0100 Subject: [PATCH 25/80] Use the correct unit for PDCP SDU volume: [Mb] instead of [kb] --- openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.c b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.c index a8ebe580ab..d3381cadd3 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.c +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm_subs.c @@ -69,7 +69,7 @@ static meas_record_lst_t fill_DRB_PdcpSduVolumeDL(__attribute__((unused))uint32_ meas_record.value = INTEGER_MEAS_VALUE; // Get DL data volume delivered to PDCP layer - meas_record.int_val = (pdcp.rxsdu_bytes - last_pdcp_sdu_total_bytes[ue_idx].dl)*8/1000; // [kb] + meas_record.int_val = (pdcp.rxsdu_bytes - last_pdcp_sdu_total_bytes[ue_idx].dl)*8/1000000; // [Mb] last_pdcp_sdu_total_bytes[ue_idx].dl = pdcp.rxsdu_bytes; return meas_record; @@ -88,7 +88,7 @@ static meas_record_lst_t fill_DRB_PdcpSduVolumeUL(__attribute__((unused))uint32_ meas_record.value = INTEGER_MEAS_VALUE; // Get UL data volume delivered from PDCP layer - meas_record.int_val = (pdcp.txsdu_bytes - last_pdcp_sdu_total_bytes[ue_idx].ul)*8/1000; // [kb] + meas_record.int_val = (pdcp.txsdu_bytes - last_pdcp_sdu_total_bytes[ue_idx].ul)*8/1000000; // [Mb] last_pdcp_sdu_total_bytes[ue_idx].ul = pdcp.txsdu_bytes; return meas_record; From e96cfbd88a8607aded713ecb8f287edd48b8cc41 Mon Sep 17 00:00:00 2001 From: Teodora Date: Thu, 6 Nov 2025 15:30:46 +0100 Subject: [PATCH 26/80] Update the FlexRIC submodule Needed notably due to https://gitlab.eurecom.fr/mosaic5g/flexric/-/merge_requests/68. --- openair2/E2AP/flexric | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/E2AP/flexric b/openair2/E2AP/flexric index df754a8553..6a595d8b24 160000 --- a/openair2/E2AP/flexric +++ b/openair2/E2AP/flexric @@ -1 +1 @@ -Subproject commit df754a85537f6db255b5330b8d83eda6a2742f25 +Subproject commit 6a595d8b243601b7148f60b5cb2cec47658e58c5 From b6bda6d97461dc1bffa6ef5f5f4e1e584cc5ea34 Mon Sep 17 00:00:00 2001 From: Teodora Date: Thu, 6 Nov 2025 15:26:49 +0100 Subject: [PATCH 27/80] RIC IP address within fr_args_t struct is not const anymore Related FlexRIC commit ID: https://gitlab.eurecom.fr/mosaic5g/flexric/-/commit/fd26e7474d18e90097bc1b2487d00598e9383400 --- executables/nr-cuup.c | 5 +++-- executables/nr-softmodem.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/executables/nr-cuup.c b/executables/nr-cuup.c index 0c2c9cdf3f..df2f633d95 100644 --- a/executables/nr-cuup.c +++ b/executables/nr-cuup.c @@ -51,8 +51,9 @@ static void initialize_agent(ngran_node_t node_type, e2_agent_args_t oai_args) printf("After RCconfig_NR_E2agent %s %s \n",oai_args.sm_dir, oai_args.ip ); - fr_args_t args = { .ip = oai_args.ip }; // init_fr_args(0, NULL); - memcpy(args.libs_dir, oai_args.sm_dir, 128); + fr_args_t args = {0}; + memcpy(args.ip, oai_args.ip, FR_IP_ADDRESS_LEN); + memcpy(args.libs_dir, oai_args.sm_dir, FR_CONF_FILE_LEN); sleep(1); diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index 0bd583662b..945e7e4cae 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -473,8 +473,9 @@ static void initialize_agent(ngran_node_t node_type, e2_agent_args_t oai_args) printf("After RCconfig_NR_E2agent %s %s \n",oai_args.sm_dir, oai_args.ip ); - fr_args_t args = { .ip = oai_args.ip }; // init_fr_args(0, NULL); - memcpy(args.libs_dir, oai_args.sm_dir, 128); + fr_args_t args = {0}; + memcpy(args.ip, oai_args.ip, FR_IP_ADDRESS_LEN); + memcpy(args.libs_dir, oai_args.sm_dir, FR_CONF_FILE_LEN); sleep(1); const gNB_RRC_INST* rrc = RC.nrrrc[0]; From 8cf7dd860796d1b7937f376bccbe8df976fe09b2 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 10 Nov 2025 17:49:54 +0100 Subject: [PATCH 28/80] CI: use intermediate variable for YAML file This harmonizes with DeployObject() (which uses the same variable) and shortens some lines for readability. --- ci-scripts/cls_containerize.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index 3cebcb24d7..32ce498be0 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -760,17 +760,18 @@ class Containerize(): logging.debug(f'\u001B[1m Undeploying OAI Object from server: {node}\u001B[0m') yaml = self.yamlPath.strip('/') wd = f'{lSourcePath}/{yaml}' + wd_yaml = f'{wd}/docker-compose.y*ml' with cls_cmd.getConnection(node) as ssh: ExistEnvFilePrint(ssh, wd) - services = GetRunningServices(ssh, f"{wd}/docker-compose.y*ml") + services = GetRunningServices(ssh, wd_yaml) copyin_res = None if services is not None: all_serv = " ".join([s for s, _ in services]) - ssh.run(f'docker compose -f {wd}/docker-compose.y*ml stop -- {all_serv}') - copyin_res = [CopyinServiceLog(ssh, lSourcePath, s, f"{wd}/docker-compose.y*ml", ctx) for s, _ in services] + ssh.run(f'docker compose -f {wd_yaml} stop -- {all_serv}') + copyin_res = [CopyinServiceLog(ssh, lSourcePath, s, wd_yaml, ctx) for s, _ in services] else: logging.warning('could not identify services to stop => no log file') - ssh.run(f'docker compose -f {wd}/docker-compose.y*ml down -v') + ssh.run(f'docker compose -f {wd_yaml} down -v') ssh.run(f'rm {wd}/.env') if not copyin_res: HTML.CreateHtmlTestRowQueue('N/A', 'KO', ['Could not copy logfile(s)']) From 4b91022387d17a31931b207c7800f4abec13ff69 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 10 Nov 2025 08:57:42 +0100 Subject: [PATCH 29/80] Pass read-only parameters as const --- common/utils/nr/nr_common.c | 6 +++--- common/utils/nr/nr_common.h | 4 ++-- openair1/PHY/NR_TRANSPORT/nr_dci.c | 2 +- openair1/PHY/NR_TRANSPORT/nr_dci.h | 2 +- openair1/PHY/NR_TRANSPORT/nr_dci_tools.c | 2 +- openair1/PHY/NR_TRANSPORT/nr_dlsch.c | 14 +++++++------- openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c | 4 ++-- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 2 +- openair1/SCHED_NR/sched_nr.h | 2 +- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index 8e6a16c97d..25f645d79f 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -541,8 +541,8 @@ int cce_to_reg_interleaving(const int R, int k, int n_shift, const int C, int L, return f; } -void get_coreset_rballoc(uint8_t *FreqDomainResource,int *n_rb,int *rb_offset) { - +void get_coreset_rballoc(const uint8_t *FreqDomainResource, int *n_rb, int *rb_offset) +{ uint8_t count=0, start=0, start_set=0; uint64_t bitmap = (((uint64_t)FreqDomainResource[0])<<37)| @@ -565,7 +565,7 @@ void get_coreset_rballoc(uint8_t *FreqDomainResource,int *n_rb,int *rb_offset) { } // According to 38.211 7.3.2.2 -int get_coreset_num_cces(uint8_t *FreqDomainResource, int duration) +int get_coreset_num_cces(const uint8_t *FreqDomainResource, int duration) { int num_rbs; int rb_offset; diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index e0d68a45ad..2a1e77cb30 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -280,8 +280,8 @@ uint32_t to_nrarfcn(int nr_bandP, uint64_t dl_CarrierFreq, uint8_t scs_index, ui int cce_to_reg_interleaving(const int R, int k, int n_shift, const int C, int L, const int N_regs); int get_SLIV(uint8_t S, uint8_t L); -void get_coreset_rballoc(uint8_t *FreqDomainResource,int *n_rb,int *rb_offset); -int get_coreset_num_cces(uint8_t *FreqDomainResource, int duration); +void get_coreset_rballoc(const uint8_t *FreqDomainResource, int *n_rb, int *rb_offset); +int get_coreset_num_cces(const uint8_t *FreqDomainResource, int duration); int get_nr_table_idx(int nr_bandP, uint8_t scs_index); int32_t get_delta_duplex(int nr_bandP, uint8_t scs_index); frame_type_t get_frame_type(uint16_t nr_bandP, uint8_t scs_index); diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.c b/openair1/PHY/NR_TRANSPORT/nr_dci.c index 0548c8fc10..0566eb428c 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dci.c @@ -52,7 +52,7 @@ static void nr_pdcch_scrambling(uint32_t *in, uint32_t size, uint32_t Nid, uint3 } static void nr_generate_dci(PHY_VARS_gNB *gNB, - nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15, + const nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15, int txdataF_offset, NR_DL_FRAME_PARMS *frame_parms, int slot) diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.h b/openair1/PHY/NR_TRANSPORT/nr_dci.h index e735069975..2fb0f5aedd 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci.h +++ b/openair1/PHY/NR_TRANSPORT/nr_dci.h @@ -42,6 +42,6 @@ void nr_fill_ul_dci(PHY_VARS_gNB *gNB, int slot, nfapi_nr_ul_dci_request_pdus_t *pdcch_pdu); -void nr_fill_reg_list(int cce_list[MAX_DCI_CORESET][NR_MAX_PDCCH_AGG_LEVEL * NR_NB_REG_PER_CCE], nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15); +void nr_fill_reg_list(int cce_list[MAX_DCI_CORESET][NR_MAX_PDCCH_AGG_LEVEL * NR_NB_REG_PER_CCE], const nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15); #endif //__PHY_NR_TRANSPORT_DCI__H diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci_tools.c b/openair1/PHY/NR_TRANSPORT/nr_dci_tools.c index 538b54ac0b..c2d2ab7a24 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci_tools.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dci_tools.c @@ -42,7 +42,7 @@ int compfunc(const void *a, const void *b) return (*(int *)a - *(int *)b); } -void nr_fill_reg_list(int reg_list[MAX_DCI_CORESET][NR_MAX_PDCCH_AGG_LEVEL * NR_NB_REG_PER_CCE], nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15) +void nr_fill_reg_list(int reg_list[MAX_DCI_CORESET][NR_MAX_PDCCH_AGG_LEVEL * NR_NB_REG_PER_CCE], const nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15) { int bsize = pdcch_pdu_rel15->RegBundleSize; int R = pdcch_pdu_rel15->InterleaverSize; diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index 535c68f419..c5b981d301 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -51,7 +51,7 @@ static void nr_pdsch_codeword_scrambling(uint8_t *in, uint32_t size, uint8_t q, nr_codeword_scrambling(in, size, q, Nid, n_RNTI, out); } -static int do_ptrs_symbol(nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15, +static int do_ptrs_symbol(const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15, int start_sc, int symbol_sz, c16_t *txF, @@ -339,7 +339,7 @@ static inline void neg_dmrs(c16_t *in, c16_t *out, int sz) static inline int do_onelayer(NR_DL_FRAME_PARMS *frame_parms, int slot, - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15, + const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15, int layer, c16_t *output, c16_t *txl_start, @@ -457,7 +457,7 @@ static inline void do_txdataF(c16_t **txdataF, int symbol_sz, c16_t txdataF_precoding[][symbol_sz], PHY_VARS_gNB *gNB, - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15, + const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15, int ant, int start_sc, int txdataF_offset_per_symbol) @@ -465,7 +465,7 @@ static inline void do_txdataF(c16_t **txdataF, NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; int rb = 0; uint16_t subCarrier = start_sc; - nfapi_nr_tx_precoding_and_beamforming_t *pb = &rel15->precodingAndBeamforming; + const nfapi_nr_tx_precoding_and_beamforming_t *pb = &rel15->precodingAndBeamforming; while (rb < rel15->rbSize) { // get pmi info const int pmi = (pb->prg_size > 0) ? (pb->prgs_list[(int)rb / pb->prg_size].pm_idx) : 0; @@ -556,7 +556,7 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC time_stats_t *dlsch_scrambling_stats = &gNB->dlsch_scrambling_stats; time_stats_t *dlsch_modulation_stats = &gNB->dlsch_modulation_stats; NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15; + const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15; const int layerSz = frame_parms->N_RB_DL * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB; const int symbol_sz=frame_parms->ofdm_symbol_size; const int dmrs_Type = rel15->dmrsConfigType; @@ -680,7 +680,7 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC // pmi = prgs_list[rbidx/prg_size].pm_idx, rbidx =0,...,rbSize-1 // The Precoding matrix: // The Codebook Type I - nfapi_nr_tx_precoding_and_beamforming_t *pb = &rel15->precodingAndBeamforming; + const nfapi_nr_tx_precoding_and_beamforming_t *pb = &rel15->precodingAndBeamforming; // beam number in multi-beam scenario (concurrent beams) int bitmap = SL_to_bitmap(rel15->StartSymbolIndex, rel15->NrOfSymbols); int beam_nb = beam_index_allocation(gNB->enable_analog_das, @@ -795,7 +795,7 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot) for (int dlsch_id = 0; dlsch_id < msgTx->num_pdsch_slot; dlsch_id++) { NR_gNB_DLSCH_t *dlsch = msgTx->dlsch[dlsch_id]; NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15; + const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15; LOG_D(PHY, "pdsch: BWPStart %d, BWPSize %d, rbStart %d, rbsize %d\n", diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c index 56a849a4af..4cbfdde2e2 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c @@ -141,7 +141,7 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; unsigned int crc = 1; - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15; + const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15; uint32_t A = rel15->TBSize[0] << 3; unsigned char *a = harq->pdu; if (rel15->rnti != SI_RNTI) { @@ -231,7 +231,7 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, for (int dlsch_id = 0; dlsch_id < msgTx->num_pdsch_slot; dlsch_id++) { NR_gNB_DLSCH_t *dlsch = msgTx->dlsch[dlsch_id]; NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15; + const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15; nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[dlsch_id]; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 09415dd86f..e515f15b02 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -58,7 +58,7 @@ static void nr_fill_indication(PHY_VARS_gNB *gNB, int beam_index_allocation(bool das, int fapi_beam_index, - nfapi_nr_analog_beamforming_ve_t *analog_bf, + const nfapi_nr_analog_beamforming_ve_t *analog_bf, NR_gNB_COMMON *common_vars, int slot, int symbols_per_slot, diff --git a/openair1/SCHED_NR/sched_nr.h b/openair1/SCHED_NR/sched_nr.h index cbec9fa1db..aade6e766c 100644 --- a/openair1/SCHED_NR/sched_nr.h +++ b/openair1/SCHED_NR/sched_nr.h @@ -49,7 +49,7 @@ void nr_phy_free_RU(RU_t *ru); void clear_slot_beamid(PHY_VARS_gNB *gNB, int slot); int beam_index_allocation(bool das, int fapi_beam_index, - nfapi_nr_analog_beamforming_ve_t *analog_bf, + const nfapi_nr_analog_beamforming_ve_t *analog_bf, NR_gNB_COMMON *common_vars, int slot, int symbols_per_slot, From 34aa69828adddbb0f18434fdb60ce647f7874a82 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 5 Nov 2025 16:59:07 +0100 Subject: [PATCH 30/80] Harmonize UL PDCCH PDU type for further refactoring Both (DL) PDCCH and UL PDCCH PDU types are fundamentally of the same type, so correct the array's type to facilitate refactoring later (a later commit will reuse a single "generate DCI" function for both cases). --- openair1/PHY/NR_TRANSPORT/nr_dci.c | 2 +- openair1/PHY/defs_gNB.h | 3 ++- openair1/SCHED_NR/fapi_nr_l1.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.c b/openair1/PHY/NR_TRANSPORT/nr_dci.c index 0566eb428c..d43bc04752 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dci.c @@ -244,7 +244,7 @@ void nr_generate_dci_top(processingData_L1tx_t *msgTx, int slot, int txdataF_off NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; start_meas(&gNB->dci_generation_stats); for (int i = 0; i < msgTx->num_ul_pdcch; i++) - nr_generate_dci(msgTx->gNB, &msgTx->ul_pdcch_pdu[i].pdcch_pdu.pdcch_pdu_rel15, txdataF_offset, frame_parms, slot); + nr_generate_dci(msgTx->gNB, &msgTx->ul_pdcch_pdu[i].pdcch_pdu_rel15, txdataF_offset, frame_parms, slot); for (int i = 0; i < msgTx->num_dl_pdcch; i++) nr_generate_dci(msgTx->gNB, &msgTx->pdcch_pdu[i].pdcch_pdu_rel15, txdataF_offset, frame_parms, slot); stop_meas(&gNB->dci_generation_stats); diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index ef12f20ce5..ed10ff70cd 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -600,7 +600,8 @@ typedef struct processingData_L1tx { openair0_timestamp timestamp_tx; PHY_VARS_gNB *gNB; nfapi_nr_dl_tti_pdcch_pdu pdcch_pdu[NFAPI_NR_MAX_NB_CORESETS]; - nfapi_nr_ul_dci_request_pdus_t ul_pdcch_pdu[NFAPI_NR_MAX_NB_CORESETS]; + /// corresponds to UL_dci_req->ul_dci_pdu_list + nfapi_nr_dl_tti_pdcch_pdu ul_pdcch_pdu[NFAPI_NR_MAX_NB_CORESETS]; NR_gNB_CSIRS_t csirs_pdu[NR_SYMBOLS_PER_SLOT]; NR_gNB_DLSCH_t **dlsch; NR_gNB_SSB_t ssb[64]; diff --git a/openair1/SCHED_NR/fapi_nr_l1.c b/openair1/SCHED_NR/fapi_nr_l1.c index 7b27b51c02..01955a0c18 100644 --- a/openair1/SCHED_NR/fapi_nr_l1.c +++ b/openair1/SCHED_NR/fapi_nr_l1.c @@ -174,7 +174,7 @@ void nr_schedule_ul_dci_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_dci_request_t *UL_dci msgTx->num_ul_pdcch = UL_dci_req->numPdus; for (int i = 0; i < UL_dci_req->numPdus; i++) - msgTx->ul_pdcch_pdu[i] = UL_dci_req->ul_dci_pdu_list[i]; + msgTx->ul_pdcch_pdu[i] = UL_dci_req->ul_dci_pdu_list[i].pdcch_pdu; } void nr_schedule_response(NR_Sched_Rsp_t *Sched_INFO) From be9e7987490c0c77e11f082406bd99cfce9a68ed Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 17 Feb 2025 18:44:53 +0000 Subject: [PATCH 31/80] E1AP: Add PDU Session Resource To Remove List to Bearer Context Modification enc/dec According to TS 38.463 - clause 9.2.2.4 and 9.3.3.12. Also, fix response message by encoding choice IE only with presence of modified PDU sessions. Co-authored-by: rmagueta --- openair2/COMMON/e1ap_messages_types.h | 11 + .../E1AP/lib/e1ap_bearer_context_management.c | 277 ++++++++++-------- openair2/E1AP/lib/e1ap_lib_includes.h | 1 + openair2/E1AP/tests/e1ap_lib_test.c | 10 + 4 files changed, 180 insertions(+), 119 deletions(-) diff --git a/openair2/COMMON/e1ap_messages_types.h b/openair2/COMMON/e1ap_messages_types.h index 788236ca05..6906d54704 100644 --- a/openair2/COMMON/e1ap_messages_types.h +++ b/openair2/COMMON/e1ap_messages_types.h @@ -475,6 +475,14 @@ typedef struct pdu_session_to_mod_s { DRB_nGRAN_to_mod_t DRBnGRanModList[E1AP_MAX_NUM_DRBS]; } pdu_session_to_mod_t; +/** PDU Session Resource To Remove List (3GPP TS 38.463 clause 9.3.3.12) */ +typedef struct { + // PDU Session ID (M) + long sessionId; + // Cause (O) + e1ap_cause_t cause; +} pdu_session_to_remove_t; + /** * Bearer Context Setup Request message, clause 9.2.2.1 of 3GPP TS 38.463 */ @@ -534,6 +542,9 @@ typedef struct e1ap_bearer_mod_req_s { // NG-RAN PDU Session Resource To Modify List (O) int numPDUSessionsMod; pdu_session_to_mod_t pduSessionMod[E1AP_MAX_NUM_PDU_SESSIONS]; + // NG-RAN PDU Session Resource To Remove List (O) + int numPDUSessionsRem; + pdu_session_to_remove_t pduSessionRem[E1AP_MAX_NUM_PDU_SESSIONS]; } e1ap_bearer_mod_req_t; typedef struct e1ap_bearer_release_cmd_s { diff --git a/openair2/E1AP/lib/e1ap_bearer_context_management.c b/openair2/E1AP/lib/e1ap_bearer_context_management.c index 109b0008d3..f2593f103c 100644 --- a/openair2/E1AP/lib/e1ap_bearer_context_management.c +++ b/openair2/E1AP/lib/e1ap_bearer_context_management.c @@ -1631,6 +1631,20 @@ E1AP_E1AP_PDU_t *encode_E1_bearer_context_mod_request(const e1ap_bearer_mod_req_ *ieC3_1 = e1_encode_pdu_session_to_mod_item(i); } } + + // NG-RAN PDU Session Resource To Remove List (O) + if (in->numPDUSessionsRem) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, remList); + E1AP_NG_RAN_BearerContextModificationRequest_t *msgNGRAN = encode_ng_ran_to_mod(remList); + msgNGRAN->id = E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Remove_List; + msgNGRAN->criticality = E1AP_Criticality_reject; + msgNGRAN->value.present = E1AP_NG_RAN_BearerContextModificationRequest__value_PR_PDU_Session_Resource_To_Remove_List; + E1AP_PDU_Session_Resource_To_Remove_List_t *pdu2Remove = &msgNGRAN->value.choice.PDU_Session_Resource_To_Remove_List; + for (const pdu_session_to_remove_t *i = in->pduSessionRem; i < in->pduSessionRem + in->numPDUSessionsRem; i++) { + asn1cSequenceAdd(pdu2Remove->list, E1AP_PDU_Session_Resource_To_Remove_Item_t, ieC4_1); + ieC4_1->pDU_Session_ID = i->sessionId; + } + } return pdu; } @@ -1854,6 +1868,19 @@ bool decode_E1_bearer_context_mod_request(const E1AP_E1AP_PDU_t *pdu, e1ap_beare CHECK_E1AP_DEC(e1_decode_pdu_session_to_mod_item(out->pduSessionMod + i, modList->list.array[i])); } break; + case E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Remove_List: + /* PDU Session Resource To Remove List (see 9.3.3.12 of TS 38.463) */ + _E1_EQ_CHECK_INT(msgNGRAN->value.present, + E1AP_NG_RAN_BearerContextModificationRequest__value_PR_PDU_Session_Resource_To_Remove_List); + E1AP_PDU_Session_Resource_To_Remove_List_t *remList = &msgNGRAN->value.choice.PDU_Session_Resource_To_Remove_List; + out->numPDUSessionsRem = remList->list.count; + // Loop through all PDU sessions to remove + for (int i = 0; i < remList->list.count; i++) { + E1AP_PDU_Session_Resource_To_Remove_Item_t *remItem = remList->list.array[i]; + pdu_session_to_remove_t *pduRem = &out->pduSessionRem[i]; + pduRem->sessionId = remItem->pDU_Session_ID; + } + break; default: PRINT_ERROR("Unknown msgNGRAN->id in E1 Setup Modification Request\n"); return false; @@ -1924,6 +1951,9 @@ e1ap_bearer_mod_req_t cp_bearer_context_mod_request(const e1ap_bearer_mod_req_t cp.pduSession[i] = cp_pdu_session_item(&msg->pduSession[i]); for (int i = 0; i < msg->numPDUSessionsMod; i++) cp.pduSessionMod[i] = cp_pdu_session_to_mod_item(&msg->pduSessionMod[i]); + // Copy PDU sessions to remove (simple struct copy, no deep copy needed) + for (int i = 0; i < msg->numPDUSessionsRem; i++) + cp.pduSessionRem[i] = msg->pduSessionRem[i]; return cp; } @@ -2037,6 +2067,15 @@ bool eq_bearer_context_mod_request(const e1ap_bearer_mod_req_t *a, const e1ap_be if (!eq_pdu_session_to_mod_item(&a->pduSessionMod[i], &b->pduSessionMod[i])) return false; } + // PDU Sessions to Remove + _E1_EQ_CHECK_INT(a->numPDUSessionsRem, b->numPDUSessionsRem); + for (int i = 0; i < a->numPDUSessionsRem; i++) { + const pdu_session_to_remove_t *pduRemA = &a->pduSessionRem[i]; + const pdu_session_to_remove_t *pduRemB = &b->pduSessionRem[i]; + _E1_EQ_CHECK_LONG(pduRemA->sessionId, pduRemB->sessionId); + _E1_EQ_CHECK_INT(pduRemA->cause.type, pduRemB->cause.type); + _E1_EQ_CHECK_INT(pduRemA->cause.value, pduRemB->cause.value); + } return true; } @@ -2114,129 +2153,129 @@ struct E1AP_E1AP_PDU *encode_E1_bearer_context_mod_response(const e1ap_bearer_mo ie2->criticality = E1AP_Criticality_reject; ie2->value.present = E1AP_BearerContextModificationResponseIEs__value_PR_GNB_CU_UP_UE_E1AP_ID; ie2->value.choice.GNB_CU_UP_UE_E1AP_ID = msg->gNB_cu_up_ue_id; - // NG-RAN PDU Session Resource Modified List (O) - asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationResponseIEs_t, ie3); - ie3->id = E1AP_ProtocolIE_ID_id_System_BearerContextModificationResponse; - ie3->criticality = E1AP_Criticality_ignore; - // CHOICE System (O) - ie3->value.present = E1AP_BearerContextModificationResponseIEs__value_PR_System_BearerContextModificationResponse; - E1AP_System_BearerContextModificationResponse_t *sys = &ie3->value.choice.System_BearerContextModificationResponse; - // NG-RAN - E1AP_ProtocolIE_Container_4932P29_t *ngran = calloc_or_fail(1, sizeof(*ngran)); - sys->present = E1AP_System_BearerContextModificationResponse_PR_nG_RAN_BearerContextModificationResponse; - sys->choice.nG_RAN_BearerContextModificationResponse = (struct E1AP_ProtocolIE_Container *)ngran; - asn1cSequenceAdd(ngran->list, E1AP_NG_RAN_BearerContextModificationResponse_t, list); - // PDU Session Resource Modified List (O) - list->id = E1AP_ProtocolIE_ID_id_PDU_Session_Resource_Modified_List; - list->criticality = E1AP_Criticality_reject; - list->value.present = E1AP_NG_RAN_BearerContextModificationResponse__value_PR_PDU_Session_Resource_Modified_List; - E1AP_PDU_Session_Resource_Modified_List_t *pdu_mod_l = &list->value.choice.PDU_Session_Resource_Modified_List; - for (int i = 0; i < msg->numPDUSessionsMod; ++i) { - // PDU Session Resource Modified Item (1..maxnoofPDUSessionResource) - const pdu_session_modif_t *pdu = &msg->pduSessionMod[i]; - asn1cSequenceAdd(pdu_mod_l->list, E1AP_PDU_Session_Resource_Modified_Item_t, iePdu); - // PDU Session ID (M) - iePdu->pDU_Session_ID = pdu->id; - // Security Result (O) - if (pdu->confidentialityProtectionIndication || pdu->integrityProtectionIndication) { - iePdu->securityResult = calloc_or_fail(1, sizeof(*iePdu->securityResult)); - if (pdu->confidentialityProtectionIndication) - iePdu->securityResult->confidentialityProtectionResult = *pdu->confidentialityProtectionIndication; - if (pdu->integrityProtectionIndication) - iePdu->securityResult->integrityProtectionResult = *pdu->integrityProtectionIndication; - } - // NG DL UP Transport Layer Information (O) - if (pdu->ng_DL_UP_TL_info) { - iePdu->nG_DL_UP_TNL_Information = calloc_or_fail(1, sizeof(*iePdu->nG_DL_UP_TNL_Information)); - *iePdu->nG_DL_UP_TNL_Information = e1_encode_up_tnl_info(pdu->ng_DL_UP_TL_info); - } - // DRB Modified List (O) - if (pdu->numDRBModified > 0) { - iePdu->dRB_Modified_List_NG_RAN = calloc_or_fail(1, sizeof(*iePdu->dRB_Modified_List_NG_RAN)); - E1AP_DRB_Modified_List_NG_RAN_t *drb_mod_l = iePdu->dRB_Modified_List_NG_RAN; - for (int j = 0; j < pdu->numDRBModified; ++j) { - const DRB_nGRAN_modified_t *drb = &pdu->DRBnGRanModList[j]; - asn1cSequenceAdd(drb_mod_l->list, E1AP_DRB_Modified_Item_NG_RAN_t, drb_mod); - // DRB ID (M) - drb_mod->dRB_ID = drb->id; - // Flow Setup List (O) - if (drb->numQosFlowSetup) - drb_mod->flow_Setup_List = calloc_or_fail(1, sizeof(*drb_mod->flow_Setup_List)); - for (int q = 0; q < drb->numQosFlowSetup; ++q) { - asn1cSequenceAdd(drb_mod->flow_Setup_List->list, E1AP_QoS_Flow_Item_t, qos_mod); - qos_mod->qoS_Flow_Identifier = drb->qosFlows[q].qfi; - } - // Flow Failed List (O) - if (drb->numQosFlowFailed) - drb_mod->flow_Failed_List = calloc_or_fail(1, sizeof(*drb_mod->flow_Failed_List)); - for (int q = 0; q < drb->numQosFlowFailed; ++q) { - asn1cSequenceAdd(drb_mod->flow_Failed_List->list, E1AP_QoS_Flow_Failed_Item_t, fail); - encode_qos_flow_failed_item(fail, &drb->qosFlowsFailed[q]); - } - - // PDCP Status Information (O) - if (drb->pdcp_status) { - asn1cCalloc(drb_mod->pDCP_SN_Status_Information, pdcp); - *pdcp = encode_pdcp_status_info(drb->pdcp_status); - } - - // UL UP Parameters (O) - if (drb->numUpParam) - drb_mod->uL_UP_Transport_Parameters = calloc_or_fail(1, sizeof(*drb_mod->uL_UP_Transport_Parameters)); - for (const up_params_t *k = drb->ul_UP_Params; k < drb->ul_UP_Params + drb->numUpParam; k++) { - asn1cSequenceAdd(drb_mod->uL_UP_Transport_Parameters->list, E1AP_UP_Parameters_Item_t, up); - up->uP_TNL_Information = e1_encode_up_tnl_info(&k->tl_info); - up->cell_Group_ID = k->cell_group_id; + if (msg->numPDUSessionsMod > 0) { + // NG-RAN PDU Session Resource Modified List (O) + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationResponseIEs_t, ie3); + ie3->id = E1AP_ProtocolIE_ID_id_System_BearerContextModificationResponse; + ie3->criticality = E1AP_Criticality_ignore; + // CHOICE System (O) + ie3->value.present = E1AP_BearerContextModificationResponseIEs__value_PR_System_BearerContextModificationResponse; + E1AP_System_BearerContextModificationResponse_t *sys = &ie3->value.choice.System_BearerContextModificationResponse; + // NG-RAN + E1AP_ProtocolIE_Container_4932P29_t *ngran = calloc_or_fail(1, sizeof(*ngran)); + sys->present = E1AP_System_BearerContextModificationResponse_PR_nG_RAN_BearerContextModificationResponse; + sys->choice.nG_RAN_BearerContextModificationResponse = (struct E1AP_ProtocolIE_Container *)ngran; + asn1cSequenceAdd(ngran->list, E1AP_NG_RAN_BearerContextModificationResponse_t, list); + // PDU Session Resource Modified List (O) + list->id = E1AP_ProtocolIE_ID_id_PDU_Session_Resource_Modified_List; + list->criticality = E1AP_Criticality_reject; + list->value.present = E1AP_NG_RAN_BearerContextModificationResponse__value_PR_PDU_Session_Resource_Modified_List; + E1AP_PDU_Session_Resource_Modified_List_t *pdu_mod_l = &list->value.choice.PDU_Session_Resource_Modified_List; + for (int i = 0; i < msg->numPDUSessionsMod; ++i) { + // PDU Session Resource Modified Item (1..maxnoofPDUSessionResource) + const pdu_session_modif_t *pdu = &msg->pduSessionMod[i]; + asn1cSequenceAdd(pdu_mod_l->list, E1AP_PDU_Session_Resource_Modified_Item_t, iePdu); + // PDU Session ID (M) + iePdu->pDU_Session_ID = pdu->id; + // Security Result (O) + if (pdu->confidentialityProtectionIndication || pdu->integrityProtectionIndication) { + iePdu->securityResult = calloc_or_fail(1, sizeof(*iePdu->securityResult)); + if (pdu->confidentialityProtectionIndication) + iePdu->securityResult->confidentialityProtectionResult = *pdu->confidentialityProtectionIndication; + if (pdu->integrityProtectionIndication) + iePdu->securityResult->integrityProtectionResult = *pdu->integrityProtectionIndication; + } + // NG DL UP Transport Layer Information (O) + if (pdu->ng_DL_UP_TL_info) { + iePdu->nG_DL_UP_TNL_Information = calloc_or_fail(1, sizeof(*iePdu->nG_DL_UP_TNL_Information)); + *iePdu->nG_DL_UP_TNL_Information = e1_encode_up_tnl_info(pdu->ng_DL_UP_TL_info); + } + // DRB Modified List (O) + if (pdu->numDRBModified > 0) { + iePdu->dRB_Modified_List_NG_RAN = calloc_or_fail(1, sizeof(*iePdu->dRB_Modified_List_NG_RAN)); + E1AP_DRB_Modified_List_NG_RAN_t *drb_mod_l = iePdu->dRB_Modified_List_NG_RAN; + for (int j = 0; j < pdu->numDRBModified; ++j) { + const DRB_nGRAN_modified_t *drb = &pdu->DRBnGRanModList[j]; + asn1cSequenceAdd(drb_mod_l->list, E1AP_DRB_Modified_Item_NG_RAN_t, drb_mod); + // DRB ID (M) + drb_mod->dRB_ID = drb->id; + // Flow Setup List (O) + if (drb->numQosFlowSetup) + drb_mod->flow_Setup_List = calloc_or_fail(1, sizeof(*drb_mod->flow_Setup_List)); + for (int q = 0; q < drb->numQosFlowSetup; ++q) { + asn1cSequenceAdd(drb_mod->flow_Setup_List->list, E1AP_QoS_Flow_Item_t, qos_mod); + qos_mod->qoS_Flow_Identifier = drb->qosFlows[q].qfi; + } + // Flow Failed List (O) + if (drb->numQosFlowFailed) + drb_mod->flow_Failed_List = calloc_or_fail(1, sizeof(*drb_mod->flow_Failed_List)); + for (int q = 0; q < drb->numQosFlowFailed; ++q) { + asn1cSequenceAdd(drb_mod->flow_Failed_List->list, E1AP_QoS_Flow_Failed_Item_t, fail); + encode_qos_flow_failed_item(fail, &drb->qosFlowsFailed[q]); + } + // PDCP Status Information (O) + if (drb->pdcp_status) { + asn1cCalloc(drb_mod->pDCP_SN_Status_Information, pdcp); + *pdcp = encode_pdcp_status_info(drb->pdcp_status); + } + // UL UP Parameters (O) + if (drb->numUpParam) + drb_mod->uL_UP_Transport_Parameters = calloc_or_fail(1, sizeof(*drb_mod->uL_UP_Transport_Parameters)); + for (const up_params_t *k = drb->ul_UP_Params; k < drb->ul_UP_Params + drb->numUpParam; k++) { + asn1cSequenceAdd(drb_mod->uL_UP_Transport_Parameters->list, E1AP_UP_Parameters_Item_t, up); + up->uP_TNL_Information = e1_encode_up_tnl_info(&k->tl_info); + up->cell_Group_ID = k->cell_group_id; + } } } - } - // DRB Failed To Modify List (O) - if (pdu->numDRBFailedToMod > 0) { - iePdu->dRB_Failed_To_Modify_List_NG_RAN = calloc_or_fail(1, sizeof(*iePdu->dRB_Failed_To_Modify_List_NG_RAN)); - E1AP_DRB_Failed_To_Modify_List_NG_RAN_t *ngran = iePdu->dRB_Failed_To_Modify_List_NG_RAN; - for (int j = 0; j < pdu->numDRBFailedToMod; ++j) { - const DRB_nGRAN_failed_t *drb = &pdu->DRBnGRanFailedModList[j]; - asn1cSequenceAdd(ngran->list, E1AP_DRB_Failed_To_Modify_Item_NG_RAN_t, fail_to_mod); - encode_drb_failed_item((E1AP_DRB_Failed_Item_NG_RAN_t *)fail_to_mod, drb); - } - } - // DRB Setup List (O) - if (pdu->numDRBSetup > 0) { - iePdu->dRB_Setup_List_NG_RAN = calloc_or_fail(1, sizeof(*iePdu->dRB_Setup_List_NG_RAN)); - E1AP_DRB_Setup_List_NG_RAN_t *drb_setup = iePdu->dRB_Setup_List_NG_RAN; - for (int j = 0; j < pdu->numDRBModified; ++j) { - const DRB_nGRAN_setup_t *drb = &pdu->DRBnGRanSetupList[j]; - asn1cSequenceAdd(drb_setup->list, E1AP_DRB_Setup_Item_NG_RAN_t, item); - // DRB ID (M) - item->dRB_ID = drb->id; - // UL UP Parameters (M) - for (const up_params_t *k = drb->UpParamList; k < drb->UpParamList + drb->numUpParam; k++) { - asn1cSequenceAdd(item->uL_UP_Transport_Parameters.list, E1AP_UP_Parameters_Item_t, up); - up->uP_TNL_Information = e1_encode_up_tnl_info(&k->tl_info); - up->cell_Group_ID = drb->UpParamList->cell_group_id; - } - // Flow Setup List (M) - for (int q = 0; q < drb->numQosFlowSetup; ++q) { - asn1cSequenceAdd(item->flow_Setup_List.list, E1AP_QoS_Flow_Item_t, qos); - qos->qoS_Flow_Identifier = drb->qosFlows[q].qfi; - } - // Flow Failed List (O) - if (drb->numQosFlowFailed) - item->flow_Failed_List = calloc_or_fail(1, sizeof(*item->flow_Failed_List)); - for (int q = 0; q < drb->numQosFlowFailed; ++q) { - asn1cSequenceAdd(item->flow_Failed_List->list, E1AP_QoS_Flow_Failed_Item_t, fail); - encode_qos_flow_failed_item(fail, &drb->qosFlowsFailed[q]); + // DRB Failed To Modify List (O) + if (pdu->numDRBFailedToMod > 0) { + iePdu->dRB_Failed_To_Modify_List_NG_RAN = calloc_or_fail(1, sizeof(*iePdu->dRB_Failed_To_Modify_List_NG_RAN)); + E1AP_DRB_Failed_To_Modify_List_NG_RAN_t *ngran = iePdu->dRB_Failed_To_Modify_List_NG_RAN; + for (int j = 0; j < pdu->numDRBFailedToMod; ++j) { + const DRB_nGRAN_failed_t *drb = &pdu->DRBnGRanFailedModList[j]; + asn1cSequenceAdd(ngran->list, E1AP_DRB_Failed_To_Modify_Item_NG_RAN_t, fail_to_mod); + encode_drb_failed_item((E1AP_DRB_Failed_Item_NG_RAN_t *)fail_to_mod, drb); } } - } - // DRB Failed List (O) - if (pdu->numDRBFailed) { - iePdu->dRB_Failed_List_NG_RAN = calloc_or_fail(1, sizeof(*iePdu->dRB_Failed_List_NG_RAN)); - E1AP_DRB_Failed_List_NG_RAN_t *ngran = iePdu->dRB_Failed_List_NG_RAN; - for (int j = 0; j < pdu->numDRBFailed; ++j) { - const DRB_nGRAN_failed_t *drb = &pdu->DRBnGRanFailedList[j]; - asn1cSequenceAdd(ngran->list, E1AP_DRB_Failed_Item_NG_RAN_t, fail); - encode_drb_failed_item(fail, drb); + // DRB Setup List (O) + if (pdu->numDRBSetup > 0) { + iePdu->dRB_Setup_List_NG_RAN = calloc_or_fail(1, sizeof(*iePdu->dRB_Setup_List_NG_RAN)); + E1AP_DRB_Setup_List_NG_RAN_t *drb_setup = iePdu->dRB_Setup_List_NG_RAN; + for (int j = 0; j < pdu->numDRBModified; ++j) { + const DRB_nGRAN_setup_t *drb = &pdu->DRBnGRanSetupList[j]; + asn1cSequenceAdd(drb_setup->list, E1AP_DRB_Setup_Item_NG_RAN_t, item); + // DRB ID (M) + item->dRB_ID = drb->id; + // UL UP Parameters (M) + for (const up_params_t *k = drb->UpParamList; k < drb->UpParamList + drb->numUpParam; k++) { + asn1cSequenceAdd(item->uL_UP_Transport_Parameters.list, E1AP_UP_Parameters_Item_t, up); + up->uP_TNL_Information = e1_encode_up_tnl_info(&k->tl_info); + up->cell_Group_ID = drb->UpParamList->cell_group_id; + } + // Flow Setup List (M) + for (int q = 0; q < drb->numQosFlowSetup; ++q) { + asn1cSequenceAdd(item->flow_Setup_List.list, E1AP_QoS_Flow_Item_t, qos); + qos->qoS_Flow_Identifier = drb->qosFlows[q].qfi; + } + // Flow Failed List (O) + if (drb->numQosFlowFailed) + item->flow_Failed_List = calloc_or_fail(1, sizeof(*item->flow_Failed_List)); + for (int q = 0; q < drb->numQosFlowFailed; ++q) { + asn1cSequenceAdd(item->flow_Failed_List->list, E1AP_QoS_Flow_Failed_Item_t, fail); + encode_qos_flow_failed_item(fail, &drb->qosFlowsFailed[q]); + } + } + } + // DRB Failed List (O) + if (pdu->numDRBFailed) { + iePdu->dRB_Failed_List_NG_RAN = calloc_or_fail(1, sizeof(*iePdu->dRB_Failed_List_NG_RAN)); + E1AP_DRB_Failed_List_NG_RAN_t *ngran = iePdu->dRB_Failed_List_NG_RAN; + for (int j = 0; j < pdu->numDRBFailed; ++j) { + const DRB_nGRAN_failed_t *drb = &pdu->DRBnGRanFailedList[j]; + asn1cSequenceAdd(ngran->list, E1AP_DRB_Failed_Item_NG_RAN_t, fail); + encode_drb_failed_item(fail, drb); + } } } } diff --git a/openair2/E1AP/lib/e1ap_lib_includes.h b/openair2/E1AP/lib/e1ap_lib_includes.h index 028993e6fd..adafbe0ae5 100644 --- a/openair2/E1AP/lib/e1ap_lib_includes.h +++ b/openair2/E1AP/lib/e1ap_lib_includes.h @@ -78,6 +78,7 @@ #include "E1AP_DRB-To-Modify-Item-NG-RAN.h" #include "E1AP_PDU-Session-Resource-To-Setup-Mod-Item.h" #include "E1AP_DRB-To-Setup-Mod-Item-NG-RAN.h" +#include "E1AP_PDU-Session-Resource-To-Remove-Item.h" // E1 Bearer Context Modification Response #include "E1AP_PDU-Session-Resource-Modified-Item.h" #include "E1AP_DRB-Modified-List-NG-RAN.h" diff --git a/openair2/E1AP/tests/e1ap_lib_test.c b/openair2/E1AP/tests/e1ap_lib_test.c index b168ff9e82..50116514fb 100644 --- a/openair2/E1AP/tests/e1ap_lib_test.c +++ b/openair2/E1AP/tests/e1ap_lib_test.c @@ -538,6 +538,14 @@ static void test_bearer_context_modification_request(void) .DRBnGRanList[0] = drb_to_setup, }; + // PDU Session to Remove + pdu_session_to_remove_t pdu_session_to_remove = { + .sessionId = 2, + // Note: cause is optional extension IE, currently encoding/decoding only handles sessionId + .cause.type = 0, + .cause.value = 0, + }; + // Initialize the Bearer Context Modification Request e1ap_bearer_mod_req_t orig = { .gNB_cu_cp_ue_id = 0x1234, @@ -548,6 +556,8 @@ static void test_bearer_context_modification_request(void) .pduSession[0] = pdusession_setup_item, .numPDUSessionsMod = 1, .pduSessionMod[0] = pdusession_mod_item, + .numPDUSessionsRem = 1, + .pduSessionRem[0] = pdu_session_to_remove, }; *orig.bearerContextStatus = BEARER_SUSPEND; *orig.inactivityTimer = 1000; From 1f313db0513d96d1e85fc4eadb13105540adde74 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 13 Aug 2025 14:43:49 +0200 Subject: [PATCH 32/80] RRC: add only DRBs to add/mod in createDRBlist Do not add PDU Session with status higher than PDU_SESSION_STATUS_TOMODIFY which means, do not add "failed" or "to release" PDU Sessions. --- openair2/RRC/NR/rrc_gNB.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index dcc17ec2c0..bc4cca38f1 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -366,6 +366,10 @@ NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish, bool do LOG_D(NR_RRC, "PDU Session %d not found, skip\n", drb->pdusession_id); continue; } + if (pduSession->status > PDU_SESSION_STATUS_TOMODIFY) { + LOG_D(NR_RRC, "PDU Session %d is not to add/mod\n", drb->pdusession_id); + continue; + } pdusession_t *session = &pduSession->param; NR_DRB_ToAddMod_t *drb_ToAddMod = calloc_or_fail(1, sizeof(*drb_ToAddMod)); drb_ToAddMod->drb_Identity = drb->drb_id; From de744ddf35d3a87c90981693ccc5211d2fdb736d Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Thu, 13 Nov 2025 20:46:06 +0000 Subject: [PATCH 33/80] Enable 2 layers and increase tested UL throughput in Aerial UL heavy test --- .../gnb-vnf.sa.band78.273prb.aerial.ul-heavy.conf | 6 +++--- .../xml_files/container_sa_aerial_quectel_ul_heavy.xml | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ci-scripts/conf_files/gnb-vnf.sa.band78.273prb.aerial.ul-heavy.conf b/ci-scripts/conf_files/gnb-vnf.sa.band78.273prb.aerial.ul-heavy.conf index 90662226ed..43207d63ec 100644 --- a/ci-scripts/conf_files/gnb-vnf.sa.band78.273prb.aerial.ul-heavy.conf +++ b/ci-scripts/conf_files/gnb-vnf.sa.band78.273prb.aerial.ul-heavy.conf @@ -24,9 +24,9 @@ gNBs = pdsch_AntennaPorts_N1 = 2; pusch_AntennaPorts = 2; do_CSIRS = 1; - do_SRS = 0; + do_SRS = 1; min_rxtxtime = 2; - + force_UL256qam_off = 1; servingCellConfigCommon = ( { #spCellConfigCommon @@ -187,7 +187,7 @@ MACRLCs = ( remote_s_portd = 50010; // pnf p7 port [!] tr_s_preference = "aerial"; tr_n_preference = "local_RRC"; - pusch_TargetSNRx10 = 220; # 150; + pusch_TargetSNRx10 = 260; # 150; pucch_TargetSNRx10 = 200; #200; dl_max_mcs = 28; ul_max_mcs = 28; diff --git a/ci-scripts/xml_files/container_sa_aerial_quectel_ul_heavy.xml b/ci-scripts/xml_files/container_sa_aerial_quectel_ul_heavy.xml index ab38b72295..baf525f167 100644 --- a/ci-scripts/xml_files/container_sa_aerial_quectel_ul_heavy.xml +++ b/ci-scripts/xml_files/container_sa_aerial_quectel_ul_heavy.xml @@ -97,8 +97,8 @@ Iperf - iperf (UL/UDP/200M)(30 sec)(single-ue profile) - -u -b 200M -t 30 -l 1428 + iperf (UL/UDP/300M)(30 sec)(single-ue profile) + -u -b 300M -t 30 -l 1428 oc-cn5g-20897-aerial up2-aerial 10 @@ -107,9 +107,9 @@ Iperf - iperf (UL/UDP/220M)(30 sec)(single-ue profile) + iperf (UL/UDP/380M)(30 sec)(single-ue profile) true - -u -b 220M -t 30 -l 1428 + -u -b 380M -t 30 -l 1428 oc-cn5g-20897-aerial up2-aerial 10 From 3445d3bb12783ce94ceacd88483f41d1d93b86ba Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 3 Sep 2025 15:24:47 +0200 Subject: [PATCH 34/80] OAI UE: add reusable function to release RLC entity --- openair2/RRC/NR_UE/rrc_UE.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 15c713cb26..2e97244202 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -1651,6 +1651,22 @@ static void nr_rrc_signal_maxrtxindication(int ue_id) itti_send_msg_to_task(TASK_RRC_NRUE, ue_id, msg); } +/** @brief Release all active RLC entities for a UE and set to inactive. + * This is typically used when tearing down all DRBs at UE side, + * such as after a PDU session release or full reconfiguration. + * @param rrc Pointer to NR_UE_RRC_INST_t structure + * @param id Logical Channel ID (must be in range [0, NR_MAX_NUM_LCID-1]) */ +static void nr_rrc_release_rlc_entity(NR_UE_RRC_INST_t *rrc, int id) +{ + DevAssert(rrc); + DevAssert(id >= 0 && id < NR_MAX_NUM_LCID); + if (rrc->active_RLC_entity[id]) { + rrc->active_RLC_entity[id] = false; + nr_rlc_release_entity(rrc->ue_id, id); + LOG_I(RLC, "Released RLC entity: ue_id=%ld, lc_id=%d\n", rrc->ue_id, id); + } +} + static void nr_rrc_manage_rlc_bearers(NR_UE_RRC_INST_t *rrc, const NR_CellGroupConfig_t *cellGroupConfig) { if (cellGroupConfig->rlc_BearerToReleaseList != NULL) { @@ -1830,10 +1846,7 @@ static void nr_rrc_rrcsetup_fallback(NR_UE_RRC_INST_t *rrc) } } for (int i = 1; i < NR_MAX_NUM_LCID; i++) { - if (rrc->active_RLC_entity[i]) { - rrc->active_RLC_entity[i] = false; - nr_rlc_release_entity(rrc->ue_id, i); - } + nr_rrc_release_rlc_entity(rrc, i); } nr_sdap_delete_ue_entities(rrc->ue_id); @@ -2938,10 +2951,7 @@ void nr_rrc_going_to_IDLE(NR_UE_RRC_INST_t *rrc, } } for (int i = 0; i < NR_MAX_NUM_LCID; i++) { - if (rrc->active_RLC_entity[i]) { - rrc->active_RLC_entity[i] = false; - nr_rlc_release_entity(rrc->ue_id, i); - } + nr_rrc_release_rlc_entity(rrc, i); } for (int i = 0; i < NB_CNX_UE; i++) { From c5b21d42a4b31b2781b781ff906a08ff65cc3e04 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 3 Sep 2025 15:25:03 +0200 Subject: [PATCH 35/80] OAI UE: set RLC entity status to false when releasing entity in nr_rrc_manage_rlc_bearers The previously introduced function rrc_release_rlc_entity has been adopted to deactvate the RLC entities after release. --- openair2/RRC/NR_UE/rrc_UE.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 2e97244202..289309419b 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -1673,7 +1673,7 @@ static void nr_rrc_manage_rlc_bearers(NR_UE_RRC_INST_t *rrc, const NR_CellGroupC for (int i = 0; i < cellGroupConfig->rlc_BearerToReleaseList->list.count; i++) { NR_LogicalChannelIdentity_t *lcid = cellGroupConfig->rlc_BearerToReleaseList->list.array[i]; AssertFatal(lcid, "LogicalChannelIdentity shouldn't be null here\n"); - nr_rlc_release_entity(rrc->ue_id, *lcid); + nr_rrc_release_rlc_entity(rrc, *lcid); } } From 228ca89f3e122b57d61e57ab9a06a8eb73541bd0 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 2 Oct 2025 12:51:48 +0200 Subject: [PATCH 36/80] Fix GTP-U TEID logging: prevent negative values and use hexadecimal format Problem: - GTP-U logs showed negative TEID values (e.g., -1943516315) due to signed/unsigned conversion. Due to wrong conversion from uint32_t to int and overflow caused negative values. - TEID values were inconsistently formatted across different log statements, due to mixed use of %d, %u, %x formats for TEID logging. Made debugging and troubleshooting difficult Changes: 1. Fixed signed/unsigned conversion bug: use teid_t. Prevents overflow when TEID values exceed int range. 2. Standardized TEID logging format: all TEID values now use '0x%x' hexadecimal format. Consistent 'TEID' capitalization throughout --- openair3/ocp-gtpu/gtp_itf.cpp | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index c524129098..ab14ee6241 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -292,7 +292,7 @@ static int gtpv1uCreateAndSendMsg(gtpv1u_bearer_t *bearer, DevAssert(bearer->ip.ss_family == AF_INET); struct sockaddr_in *to = (struct sockaddr_in *)&bearer->ip; LOG_D(GTPU, - "Peer IP:" IPV4_ADDR " port:%u outgoing teid:%x\n", + "Peer IP:" IPV4_ADDR " port:%u outgoing TEID:0x%x\n", IPV4_ADDR_FORMAT(to->sin_addr.s_addr), htons(to->sin_port), bearer->teid_outgoing); @@ -332,7 +332,7 @@ static void _gtpv1uSendDirect(instance_t instance, } LOG_D(GTPU, - "[%ld] sending a packet to UE:RAB:teid %lx/%x/%x, len %lu, oldseq %d, oldnum %d\n", + "[%ld] sending a packet to UE:RAB:TEID %lx/%d/0x%x, len %lu, oldseq %d, oldnum %d\n", instance, ue_id, bearer_id, @@ -492,7 +492,7 @@ static void gtpv1uEndTunnel(instance_t instance, gtpv1u_enb_end_marker_req_t *re } LOG_D(GTPU, - "[%ld] sending a end packet packet to UE:RAB:teid %lx/%x/%x\n", + "[%ld] sending a end packet packet to UE:RAB:TEID %lx/%d/0x%x\n", instance, ue_id, bearer_id, @@ -641,7 +641,7 @@ void GtpuUpdateTunnelOutgoingAddressAndTeid(instance_t instance, struct sockaddr_in *sa4 = (struct sockaddr_in *)sockaddr; struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sockaddr; LOG_I(GTPU, - "[%ld] UE ID %ld: Update tunnel TEID incoming %x outgoing %x to remote IPv4 %s, IPv6 %s, port %d\n", + "[%ld] UE ID %ld: Update tunnel TEID incoming 0x%x outgoing 0x%x to remote IPv4 %s, IPv6 %s, port %d\n", instance, ue_id, ptr2->second.teid_incoming, @@ -676,7 +676,7 @@ teid_t newGtpuCreateTunnel(instance_t instance, teid_t incoming_teid = gtpv1uNewTeid(); while (globGtp.te2ue_mapping.find(incoming_teid) != globGtp.te2ue_mapping.end()) { - LOG_W(GTPU, "[%ld] generated a random Teid that exists, re-generating (%x)\n", instance, incoming_teid); + LOG_W(GTPU, "[%ld] generated a random TEID that exists, re-generating (0x%x)\n", instance, incoming_teid); incoming_teid = gtpv1uNewTeid(); }; @@ -721,7 +721,7 @@ teid_t newGtpuCreateTunnel(instance_t instance, char ip4[INET_ADDRSTRLEN]; char ip6[INET6_ADDRSTRLEN]; LOG_I(GTPU, - "[%ld] UE ID %ld: Create tunnel TEID incoming %x outgoing %x to remote IPv4 %s, IPv6 %s, port %d\n", + "[%ld] UE ID %ld: Create tunnel TEID incoming 0x%x outgoing 0x%x to remote IPv4 %s, IPv6 %s, port %d\n", instance, ue_id, bearer.teid_incoming, @@ -825,7 +825,7 @@ int gtpv1u_create_ngu_tunnel(const instance_t instance, gtpCallbackSDAP callBackSDAP) { LOG_D(GTPU, - "[%ld] Start create tunnels for ue id %lu, num_tunnels %d, sgw_S1u_teid %x\n", + "[%ld] Start create tunnels for ue id %lu, num_tunnels %d, TEID 0x%x\n", instance, create_tunnel_req->ue_id, create_tunnel_req->num_tunnels, @@ -909,7 +909,7 @@ int newGtpuDeleteOneTunnel(instance_t instance, ue_id_t ue_id, int rb_id) pthread_mutex_unlock(&globGtp.gtp_lock); return !GTPNOK; } - int teid = rb_it->second.teid_incoming; + teid_t teid = rb_it->second.teid_incoming; globGtp.te2ue_mapping.erase(teid); ue_it->second.bearers.erase(rb_id); pthread_mutex_unlock(&globGtp.gtp_lock); @@ -1043,7 +1043,7 @@ static int Gtpv1uHandleEchoReq(int h, uint8_t *msgBuf, uint32_t msgBufLen, const } uint16_t seq = ntohs(*(uint16_t *)(msgHdr + 1)); - LOG_D(GTPU, "[%d] Received a echo request, TEID: %d, seq: %hu\n", h, msgHdr->teid, seq); + LOG_D(GTPU, "[%d] Received a echo request, TEID: 0x%x, seq: %hu\n", h, msgHdr->teid, seq); uint8_t recovery[2] = {14, 0}; gtpv1u_bearer_t bearer = create_bearer(h, addr, ntohl(msgHdr->teid), seq); return gtpv1uCreateAndSendMsg(&bearer, @@ -1061,10 +1061,11 @@ static int Gtpv1uHandleError(int h, uint8_t *msgBuf, uint32_t msgBufLen, const s if (msgBufLen < sizeof(Gtpv1uError)) LOG_E(GTPU, "Received GTP error indication with truncated size %u (mini size: %lu)\n", msgBufLen,sizeof(Gtpv1uError)+4); Gtpv1uError *msg = ( Gtpv1uError *)msgBuf; - LOG_E(GTPU, "Received GTP error indication: \n" - " TEID %u (must be 0 from TS 29.281)\n" - " TV id for TEID %u (must be 16)\n" - " TEID in error %u (should be a TEID we sent)\n" + LOG_E(GTPU, + "Received GTP error indication: \n" + " TEID 0x%x (must be 0 from TS 29.281)\n" + " TV id for TEID 0x%x (must be 16)\n" + " TEID in error 0x%x (should be a TEID we sent)\n" " TV id for GTP addr %u (should be 133)\n" " len for addr of UPF %u (should be IPv4 or IPv6 len)" " (TS 29.281 Sec 7.3.1 Error Handling not implemented)\n", @@ -1103,7 +1104,7 @@ static int Gtpv1uHandleEndMarker(int h, uint8_t *msgBuf, uint32_t msgBufLen, con auto tunnel = globGtp.te2ue_mapping.find(ntohl(msgHdr->teid)); if (tunnel == globGtp.te2ue_mapping.end()) { - LOG_E(GTPU, "[%d] Received a incoming packet on unknown teid (%x) Dropping!\n", h, msgHdr->teid); + LOG_E(GTPU, "[%d] Received a incoming packet on unknown TEID (0x%x) Dropping!\n", h, msgHdr->teid); pthread_mutex_unlock(&globGtp.gtp_lock); return GTPNOK; } @@ -1132,7 +1133,7 @@ static int Gtpv1uHandleEndMarker(int h, uint8_t *msgBuf, uint32_t msgBufLen, con if (!tunnel->second.callBack(&ctxt, srb_flag, rb_id, mui, confirm, 0, NULL, mode, &sourceL2Id, &destinationL2Id)) LOG_E(GTPU, "[%d] down layer refused incoming packet\n", h); - LOG_D(GTPU, "[%d] Received END marker packet for: teid:%x\n", h, ntohl(msgHdr->teid)); + LOG_D(GTPU, "[%d] Received END marker packet for: TEID:0x%x\n", h, ntohl(msgHdr->teid)); return !GTPNOK; } @@ -1149,7 +1150,7 @@ static int Gtpv1uHandleGpdu(int h, uint8_t *msgBuf, uint32_t msgBufLen, const st auto tunnel = globGtp.te2ue_mapping.find(ntohl(msgHdr->teid)); if (tunnel == globGtp.te2ue_mapping.end()) { - LOG_E(GTPU, "[%d] Received a incoming packet on unknown teid (%x) Dropping!\n", h, ntohl(msgHdr->teid)); + LOG_E(GTPU, "[%d] Received a incoming packet on unknown TEID (0x%x) Dropping!\n", h, ntohl(msgHdr->teid)); pthread_mutex_unlock(&globGtp.gtp_lock); return GTPNOK; } @@ -1282,7 +1283,7 @@ static int Gtpv1uHandleGpdu(int h, uint8_t *msgBuf, uint32_t msgBufLen, const st 1); } - LOG_D(GTPU, "[%d] Received a %d bytes packet for: teid:%x\n", h, msgBufLen - offset, ntohl(msgHdr->teid)); + LOG_D(GTPU, "[%d] Received a %d bytes packet for: TEID:0x%x\n", h, msgBufLen - offset, ntohl(msgHdr->teid)); return !GTPNOK; } From bae9e0f1e81ce182a03d34924704125755e6a71f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 5 Nov 2025 17:07:10 +0100 Subject: [PATCH 37/80] Rewrite nr_generate_dci_top() without msgTx and shorter --- doc/SW_archi.md | 2 +- openair1/PHY/NR_TRANSPORT/nr_dci.c | 23 +++++------------------ openair1/PHY/NR_TRANSPORT/nr_dci.h | 6 +++++- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 9 +++++++-- 4 files changed, 18 insertions(+), 22 deletions(-) diff --git a/doc/SW_archi.md b/doc/SW_archi.md index c47a3cbc91..78004a5a74 100644 --- a/doc/SW_archi.md +++ b/doc/SW_archi.md @@ -177,7 +177,7 @@ it would be better to call **NR_UL_indication()** now instead of before (on prev * nr_common_signal_procedures() generate common signals {: .func4} -* nr_generate_dci_top() +* nr_generate_dci() generate DCI: the scheduling informtion for each UE in both DL and UL {: .func4} * nr_generate_pdsch() diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.c b/openair1/PHY/NR_TRANSPORT/nr_dci.c index d43bc04752..2df2df8eb0 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dci.c @@ -51,11 +51,11 @@ static void nr_pdcch_scrambling(uint32_t *in, uint32_t size, uint32_t Nid, uint3 out[i] = in[i] ^ seq[i]; } -static void nr_generate_dci(PHY_VARS_gNB *gNB, - const nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15, - int txdataF_offset, - NR_DL_FRAME_PARMS *frame_parms, - int slot) +void nr_generate_dci(PHY_VARS_gNB *gNB, + const nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15, + int txdataF_offset, + NR_DL_FRAME_PARMS *frame_parms, + int slot) { // fill reg list per symbol int reg_list[MAX_DCI_CORESET][NR_MAX_PDCCH_AGG_LEVEL * NR_NB_REG_PER_CCE]; @@ -237,16 +237,3 @@ static void nr_generate_dci(PHY_VARS_gNB *gNB, *(unsigned long long *)dci_pdu->Payload); } // for (int d=0;dnumDlDci;d++) } - -void nr_generate_dci_top(processingData_L1tx_t *msgTx, int slot, int txdataF_offset) -{ - PHY_VARS_gNB *gNB = msgTx->gNB; - NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; - start_meas(&gNB->dci_generation_stats); - for (int i = 0; i < msgTx->num_ul_pdcch; i++) - nr_generate_dci(msgTx->gNB, &msgTx->ul_pdcch_pdu[i].pdcch_pdu_rel15, txdataF_offset, frame_parms, slot); - for (int i = 0; i < msgTx->num_dl_pdcch; i++) - nr_generate_dci(msgTx->gNB, &msgTx->pdcch_pdu[i].pdcch_pdu_rel15, txdataF_offset, frame_parms, slot); - stop_meas(&gNB->dci_generation_stats); -} - diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.h b/openair1/PHY/NR_TRANSPORT/nr_dci.h index 2fb0f5aedd..57651f03a2 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci.h +++ b/openair1/PHY/NR_TRANSPORT/nr_dci.h @@ -26,7 +26,11 @@ #include "PHY/NR_REFSIG/nr_refsig.h" #include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h" -void nr_generate_dci_top(processingData_L1tx_t *msgTx, int slot, int txdataF_offset); +void nr_generate_dci(PHY_VARS_gNB *gNB, + const nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15, + int txdataF_offset, + NR_DL_FRAME_PARMS *frame_parms, + int slot); int16_t find_nr_pdcch(int frame,int slot, PHY_VARS_gNB *gNB,find_type_t type); diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index e515f15b02..bf743c60f6 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -255,12 +255,17 @@ void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx, int num_pdcch_pdus = msgTx->num_ul_pdcch + msgTx->num_dl_pdcch; if (num_pdcch_pdus > 0) { - LOG_D(PHY, "[gNB %d] Frame %d slot %d Calling nr_generate_dci_top (number of UL/DL PDCCH PDUs %d/%d)\n", + LOG_D(PHY, "[gNB %d] Frame %d slot %d Calling nr_generate_dci() (number of UL/DL PDCCH PDUs %d/%d)\n", gNB->Mod_id, frame, slot, msgTx->num_ul_pdcch, msgTx->num_dl_pdcch); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_gNB_PDCCH_TX,1); - nr_generate_dci_top(msgTx, slot, txdataF_offset); + start_meas(&gNB->dci_generation_stats); + for (int i = 0; i < msgTx->num_dl_pdcch; ++i) + nr_generate_dci(gNB, &msgTx->pdcch_pdu[i].pdcch_pdu_rel15, txdataF_offset, &gNB->frame_parms, slot); + for (int i = 0; i < msgTx->num_ul_pdcch; ++i) + nr_generate_dci(gNB, &msgTx->ul_pdcch_pdu[i].pdcch_pdu_rel15, txdataF_offset, &gNB->frame_parms, slot); + stop_meas(&gNB->dci_generation_stats); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_gNB_PDCCH_TX,0); } From d0f4997aa00222c86aabe3febb2ca7caf03ee320 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 5 Nov 2025 17:15:02 +0100 Subject: [PATCH 38/80] Remove msgTx->ssb and replace with normal array There is no point in tracking the "active" state: the SSB PDU will be sent from MAC to L1, encoded, and then "discarded" (by marking the number of SSB PDUs as 0). Hence, remove this intermediate type. --- executables/nr-gnb.c | 1 - openair1/PHY/defs_gNB.h | 8 ++------ openair1/SCHED_NR/fapi_nr_l1.c | 7 +------ openair1/SCHED_NR/phy_procedures_nr_gNB.c | 9 +++------ openair1/SIMULATION/NR_PHY/dlsim.c | 5 ++--- openair1/SIMULATION/NR_PHY/pbchsim.c | 12 ++++++------ 6 files changed, 14 insertions(+), 28 deletions(-) diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index b866a83222..c4ad405655 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -362,7 +362,6 @@ void init_gNB_Tpool(int inst) processingData_L1tx_t *msgDataTx = (processingData_L1tx_t *)NotifiedFifoData(msgL1Tx); memset(msgDataTx, 0, sizeof(processingData_L1tx_t)); init_DLSCH_struct(gNB, msgDataTx); - memset(msgDataTx->ssb, 0, 64 * sizeof(NR_gNB_SSB_t)); // this will be removed when the msgDataTx is not necessary anymore gNB->msgDataTx = msgDataTx; diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index ed10ff70cd..01a9bd99f2 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -129,11 +129,6 @@ typedef struct { uint32_t G; } NR_gNB_DLSCH_t; -typedef struct { - bool active; - nfapi_nr_dl_tti_ssb_pdu ssb_pdu; -} NR_gNB_SSB_t; - typedef struct { uint8_t NumPRSResources; prs_config_t prs_cfg[NR_MAX_PRS_RESOURCES_PER_SET]; @@ -604,7 +599,8 @@ typedef struct processingData_L1tx { nfapi_nr_dl_tti_pdcch_pdu ul_pdcch_pdu[NFAPI_NR_MAX_NB_CORESETS]; NR_gNB_CSIRS_t csirs_pdu[NR_SYMBOLS_PER_SLOT]; NR_gNB_DLSCH_t **dlsch; - NR_gNB_SSB_t ssb[64]; + nfapi_nr_dl_tti_ssb_pdu ssb_pdu[64]; + int n_ssb_pdu; uint16_t num_pdsch_slot; int num_dl_pdcch; int num_ul_pdcch; diff --git a/openair1/SCHED_NR/fapi_nr_l1.c b/openair1/SCHED_NR/fapi_nr_l1.c index 01955a0c18..b00cdf416d 100644 --- a/openair1/SCHED_NR/fapi_nr_l1.c +++ b/openair1/SCHED_NR/fapi_nr_l1.c @@ -47,12 +47,7 @@ static void handle_nr_nfapi_ssb_pdu(processingData_L1tx_t *msgTx, int frame, int uint8_t i_ssb = dl_tti_pdu->ssb_pdu.ssb_pdu_rel15.SsbBlockIndex; LOG_D(NR_PHY,"%d.%d : ssb index %d pbch_pdu: %x\n",frame,slot,i_ssb,dl_tti_pdu->ssb_pdu.ssb_pdu_rel15.bchPayload); - if (msgTx->ssb[i_ssb].active) - AssertFatal(1==0,"SSB PDU with index %d already active\n",i_ssb); - else { - msgTx->ssb[i_ssb].active = true; - memcpy((void*)&msgTx->ssb[i_ssb].ssb_pdu,&dl_tti_pdu->ssb_pdu,sizeof(dl_tti_pdu->ssb_pdu)); - } + msgTx->ssb_pdu[msgTx->n_ssb_pdu++] = dl_tti_pdu->ssb_pdu; } static void handle_nfapi_nr_csirs_pdu(processingData_L1tx_t *msgTx, int frame, int slot, nfapi_nr_dl_tti_csi_rs_pdu *csirs_pdu) diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index bf743c60f6..570a0785a4 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -243,12 +243,9 @@ void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx, } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_COMMON_TX,1); - for (int i = 0; i < fp->Lmax; i++) { - if (msgTx->ssb[i].active) { - nr_common_signal_procedures(gNB, frame, slot, &msgTx->ssb[i].ssb_pdu); - msgTx->ssb[i].active = false; - } - } + for (int i = 0; i < msgTx->n_ssb_pdu; i++) + nr_common_signal_procedures(gNB, frame, slot, &msgTx->ssb_pdu[i]); + msgTx->n_ssb_pdu = 0; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_COMMON_TX,0); diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index c03e3c0046..678b330513 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -979,7 +979,6 @@ int main(int argc, char **argv) init_DLSCH_struct(gNB, msgDataTx); msgDataTx->slot = slot; msgDataTx->frame = frame; - memset(msgDataTx->ssb, 0, 64*sizeof(NR_gNB_SSB_t)); gNB->msgDataTx = msgDataTx; // Buffers to store internal memory of slot process @@ -1117,8 +1116,8 @@ int main(int argc, char **argv) LOG_D(PHY,"[DLSIM] PTRS Symbols in a slot: %2u, RE per Symbol: %3u, RE in a slot %4d\n", ptrsSymbPerSlot, ptrsRePerSymb, ptrsSymbPerSlot * ptrsRePerSymb); } - msgDataTx->ssb[0].ssb_pdu.ssb_pdu_rel15.bchPayload=0x001234; - msgDataTx->ssb[0].ssb_pdu.ssb_pdu_rel15.SsbBlockIndex = 0; + msgDataTx->ssb_pdu[0].ssb_pdu_rel15.bchPayload = 0x001234; + msgDataTx->ssb_pdu[0].ssb_pdu_rel15.SsbBlockIndex = 0; msgDataTx->gNB = gNB; start_meas(&gNB->phy_proc_tx); diff --git a/openair1/SIMULATION/NR_PHY/pbchsim.c b/openair1/SIMULATION/NR_PHY/pbchsim.c index 97421130af..b40cfc8176 100644 --- a/openair1/SIMULATION/NR_PHY/pbchsim.c +++ b/openair1/SIMULATION/NR_PHY/pbchsim.c @@ -530,10 +530,10 @@ int main(int argc, char **argv) const int sc_offset = frame_parms->freq_range == FR1 ? ssb_subcarrier_offset<freq_range == FR1 ? gNB->gNB_config.ssb_table.ssb_offset_point_a.value<gNB_config.ssb_table.ssb_offset_point_a.value << (mu - 2); - msgDataTx.ssb[i].ssb_pdu.ssb_pdu_rel15.bchPayload = 0x55dd33; - msgDataTx.ssb[i].ssb_pdu.ssb_pdu_rel15.SsbBlockIndex = i; - msgDataTx.ssb[i].ssb_pdu.ssb_pdu_rel15.SsbSubcarrierOffset = sc_offset; - msgDataTx.ssb[i].ssb_pdu.ssb_pdu_rel15.ssbOffsetPointA = prb_offset; + msgDataTx.ssb_pdu[i].ssb_pdu_rel15.bchPayload = 0x55dd33; + msgDataTx.ssb_pdu[i].ssb_pdu_rel15.SsbBlockIndex = i; + msgDataTx.ssb_pdu[i].ssb_pdu_rel15.SsbSubcarrierOffset = sc_offset; + msgDataTx.ssb_pdu[i].ssb_pdu_rel15.ssbOffsetPointA = prb_offset; start_symbol = nr_get_ssb_start_symbol(frame_parms,i); int slot = start_symbol/14; @@ -541,7 +541,7 @@ int main(int argc, char **argv) for (aa=0; aaframe_parms.nb_antennas_tx; aa++) memset(gNB->common_vars.txdataF[0][aa], 0, frame_parms->samples_per_slot_wCP * sizeof(int32_t)); - nr_common_signal_procedures (gNB,frame,slot, &msgDataTx.ssb[i].ssb_pdu); + nr_common_signal_procedures (gNB,frame,slot, &msgDataTx.ssb_pdu[i]); int samp = frame_parms->get_samples_slot_timestamp(slot, frame_parms, 0); for (aa=0; aaframe_parms.nb_antennas_tx; aa++) { @@ -744,7 +744,7 @@ int main(int argc, char **argv) gNB->gNB_config.ssb_table.ssb_subcarrier_offset.value, frame_parms->Lmax); int payload_ret = (result.xtra_byte == xtra_byte); - nfapi_nr_dl_tti_ssb_pdu_rel15_t *pdu = &msgDataTx.ssb[ssb_index].ssb_pdu.ssb_pdu_rel15; + nfapi_nr_dl_tti_ssb_pdu_rel15_t *pdu = &msgDataTx.ssb_pdu[ssb_index].ssb_pdu_rel15; for (int i = 0; i < 3; i++) payload_ret += (result.decoded_output[i] == ((pdu->bchPayload >> (8 * i)) & 0xff)); // printf("ret %d\n", payload_ret); From 62333cd3cfb7af097a4e3e828263c24214c4e4fd Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 5 Nov 2025 17:27:32 +0100 Subject: [PATCH 39/80] Refactor csi-rs handling Similarly to the parent commit, simplify the array type to the FAPI PDU towards further refactoring, and encapsulate the code in a function for easier reuse in a later refactoring step. Note on ZP-CSI: after this commit, we continue treating CSI PDUs. The prior code was returning, which I think is wrong (as this information is only for the currently treated CSI-RS PDU). --- openair1/PHY/defs_gNB.h | 8 +-- openair1/SCHED_NR/fapi_nr_l1.c | 15 +--- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 86 +++++++++++------------ 3 files changed, 46 insertions(+), 63 deletions(-) diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 01a9bd99f2..cb4edddeca 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -72,11 +72,6 @@ typedef struct { uint32_t unav_res; } NR_DL_gNB_HARQ_t; -typedef struct { - uint8_t active; - nfapi_nr_dl_tti_csi_rs_pdu csirs_pdu; -} NR_gNB_CSIRS_t; - typedef struct { int dump_frame; int round_trials[8]; @@ -597,10 +592,11 @@ typedef struct processingData_L1tx { nfapi_nr_dl_tti_pdcch_pdu pdcch_pdu[NFAPI_NR_MAX_NB_CORESETS]; /// corresponds to UL_dci_req->ul_dci_pdu_list nfapi_nr_dl_tti_pdcch_pdu ul_pdcch_pdu[NFAPI_NR_MAX_NB_CORESETS]; - NR_gNB_CSIRS_t csirs_pdu[NR_SYMBOLS_PER_SLOT]; + nfapi_nr_dl_tti_csi_rs_pdu csirs_pdu[NFAPI_NR_MAX_NB_CORESETS]; NR_gNB_DLSCH_t **dlsch; nfapi_nr_dl_tti_ssb_pdu ssb_pdu[64]; int n_ssb_pdu; + int n_csirs_pdu; uint16_t num_pdsch_slot; int num_dl_pdcch; int num_ul_pdcch; diff --git a/openair1/SCHED_NR/fapi_nr_l1.c b/openair1/SCHED_NR/fapi_nr_l1.c index b00cdf416d..0d122cedf5 100644 --- a/openair1/SCHED_NR/fapi_nr_l1.c +++ b/openair1/SCHED_NR/fapi_nr_l1.c @@ -52,20 +52,7 @@ static void handle_nr_nfapi_ssb_pdu(processingData_L1tx_t *msgTx, int frame, int static void handle_nfapi_nr_csirs_pdu(processingData_L1tx_t *msgTx, int frame, int slot, nfapi_nr_dl_tti_csi_rs_pdu *csirs_pdu) { - int found = 0; - - for (int id = 0; id < NR_NUMBER_OF_SYMBOLS_PER_SLOT; id++) { - NR_gNB_CSIRS_t *csirs = &msgTx->csirs_pdu[id]; - if (csirs->active == 0) { - LOG_D(NR_PHY,"Frame %d Slot %d CSI_RS with ID %d is now active\n",frame,slot,id); - csirs->active = 1; - memcpy((void*)&csirs->csirs_pdu, (void*)csirs_pdu, sizeof(nfapi_nr_dl_tti_csi_rs_pdu)); - found = 1; - break; - } - } - if (found == 0) - LOG_E(MAC,"CSI-RS list is full\n"); + msgTx->csirs_pdu[msgTx->n_csirs_pdu++] = *csirs_pdu; } void nr_schedule_dl_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_dl_tti_request_t *DL_req) diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 570a0785a4..6c94a3005e 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -203,6 +203,46 @@ void clear_slot_beamid(PHY_VARS_gNB *gNB, int slot) } } +static void nr_generate_csi_rs_gNB(PHY_VARS_gNB *gNB, + int slot, + const nfapi_nr_config_request_scf_t *cfg, + const nfapi_nr_dl_tti_csi_rs_pdu *csi_rs_pdu) +{ + const nfapi_nr_dl_tti_csi_rs_pdu_rel15_t *csi_params = &csi_rs_pdu->csi_rs_pdu_rel15; + if (csi_params->csi_type == 2) // ZP-CSI + return; + + csi_mapping_parms_t mapping_parms = + get_csi_mapping_parms(csi_params->row, csi_params->freq_domain, csi_params->symb_l0, csi_params->symb_l1); + const nfapi_nr_tx_precoding_and_beamforming_t *pb = &csi_params->precodingAndBeamforming; + int csi_bitmap = 0; + int lprime_num = mapping_parms.lprime + 1; + for (int j = 0; j < mapping_parms.size; j++) + csi_bitmap |= ((1 << lprime_num) - 1) << mapping_parms.loverline[j]; + int beam_nb = beam_index_allocation(gNB->enable_analog_das, + pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, + &cfg->analog_beamforming_ve, + &gNB->common_vars, + slot, + gNB->frame_parms.symbols_per_slot, + csi_bitmap); + + nr_generate_csi_rs(&gNB->frame_parms, + &mapping_parms, + gNB->TX_AMP, + slot, + csi_params->freq_density, + csi_params->start_rb, + csi_params->nr_of_rbs, + csi_params->symb_l0, + csi_params->symb_l1, + csi_params->row, + csi_params->scramb_id, + csi_params->power_control_offset_ss, + csi_params->cdm_type, + gNB->common_vars.txdataF[beam_nb]); +} + void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx, int frame, int slot, @@ -277,49 +317,9 @@ void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx, } msgTx->num_pdsch_slot = 0; - for (int i = 0; i < NR_SYMBOLS_PER_SLOT; i++){ - NR_gNB_CSIRS_t *csirs = &msgTx->csirs_pdu[i]; - if (csirs->active == 1) { - LOG_D(PHY, "CSI-RS generation started in frame %d.%d\n",frame,slot); - nfapi_nr_dl_tti_csi_rs_pdu_rel15_t *csi_params = &csirs->csirs_pdu.csi_rs_pdu_rel15; - if (csi_params->csi_type == 2) { // ZP-CSI - csirs->active = 0; - return; - } - csi_mapping_parms_t mapping_parms = get_csi_mapping_parms(csi_params->row, - csi_params->freq_domain, - csi_params->symb_l0, - csi_params->symb_l1); - nfapi_nr_tx_precoding_and_beamforming_t *pb = &csi_params->precodingAndBeamforming; - int csi_bitmap = 0; - int lprime_num = mapping_parms.lprime + 1; - for (int j = 0; j < mapping_parms.size; j++) - csi_bitmap |= ((1 << lprime_num) - 1) << mapping_parms.loverline[j]; - int beam_nb = beam_index_allocation(gNB->enable_analog_das, - pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, - &cfg->analog_beamforming_ve, - &gNB->common_vars, - slot, - fp->symbols_per_slot, - csi_bitmap); - - nr_generate_csi_rs(&gNB->frame_parms, - &mapping_parms, - gNB->TX_AMP, - slot, - csi_params->freq_density, - csi_params->start_rb, - csi_params->nr_of_rbs, - csi_params->symb_l0, - csi_params->symb_l1, - csi_params->row, - csi_params->scramb_id, - csi_params->power_control_offset_ss, - csi_params->cdm_type, - gNB->common_vars.txdataF[beam_nb]); - csirs->active = 0; - } - } + for (int i = 0; i < msgTx->n_csirs_pdu; i++) + nr_generate_csi_rs_gNB(gNB, slot, cfg, &msgTx->csirs_pdu[i]); + msgTx->n_csirs_pdu = 0; //apply the OFDM symbol rotation here start_meas(&gNB->phase_comp_stats); From c06033697c29dbded5850e289a4cdeb10fe85b55 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 6 Nov 2025 09:56:35 +0100 Subject: [PATCH 40/80] Remove unused or write-only variables --- openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c | 1 - openair1/PHY/defs_gNB.h | 8 -------- 2 files changed, 9 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c index 4cbfdde2e2..79538c52cd 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c @@ -203,7 +203,6 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, // The harq_pid is not unique among the active HARQ processes in the instance so we use dlsch_id instead TB_parameters->harq_unique_pid = dlsch_id; TB_parameters->BG = rel15->maintenance_parms_v3.ldpcBaseGraph; - TB_parameters->Z = harq->Z; TB_parameters->A = A; start_meas(dlsch_segmentation_stats); TB_parameters->Kb = nr_segmentation(harq->b, diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index cb4edddeca..246d3aaa6f 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -62,12 +62,8 @@ typedef struct { uint8_t *b; /// Pointers to transport block segments uint8_t **c; - /// Frame where current HARQ round was sent - uint32_t frame; /// Interleaver outputs uint8_t *f; - /// LDPC lifting size - uint32_t Z; /// REs unavailable for DLSCH (overlapping with PTRS, CSIRS etc.) uint32_t unav_res; } NR_DL_gNB_HARQ_t; @@ -118,10 +114,6 @@ typedef struct { typedef struct { /// Pointers to variables related to DLSCH harq process NR_DL_gNB_HARQ_t harq_process; - /// Active flag for baseband transmitter processing - uint8_t active; - /// Number of soft channel bits - uint32_t G; } NR_gNB_DLSCH_t; typedef struct { From 09e0344b5ba0b63f02cd12e90406cd4f3fd71369 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 5 Nov 2025 18:23:47 +0100 Subject: [PATCH 41/80] Remove unused computation unav_res is already computed in nr_generate_pdsch(), and then used inside of nr_dlsch_encoding() right after. --- openair1/PHY/NR_TRANSPORT/nr_dlsch.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index c5b981d301..171aeec73f 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -580,7 +580,6 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC /* PTRS */ uint16_t dlPtrsSymPos = 0; int n_ptrs = 0; - uint32_t ptrsSymbPerSlot = 0; if (rel15->pduBitmap & 0x1) { set_ptrs_symb_idx(&dlPtrsSymPos, rel15->NrOfSymbols, @@ -588,9 +587,7 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC 1 << rel15->PTRSTimeDensity, rel15->dlDmrsSymbPos); n_ptrs = (rel15->rbSize + rel15->PTRSFreqDensity - 1) / rel15->PTRSFreqDensity; - ptrsSymbPerSlot = get_ptrs_symbols_in_slot(dlPtrsSymPos, rel15->StartSymbolIndex, rel15->NrOfSymbols); } - harq->unav_res = ptrsSymbPerSlot * n_ptrs; #ifdef DEBUG_DLSCH printf("PDSCH encoding:\nPayload:\n"); From 2b2b3cd3470ee344ebdeacf7bc2203452b882fd8 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 13 Nov 2025 19:26:02 +0100 Subject: [PATCH 42/80] Simplify gNB DLSCH type DLSCH encoding is not concerned with HARQ processes directly. Instead, it gets the redundancy version and encodes a specific redundancy version for a given TB. The rest is up to the MAC, the L1 is stateless in that regard. Hence, remove the HARQ type and put it into DLSCH, which also simplifies the code elsewhere. --- openair1/PHY/NR_TRANSPORT/nr_dlsch.c | 16 ++--- openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c | 71 ++++++++++----------- openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c | 10 ++- openair1/PHY/defs_gNB.h | 29 ++++----- openair1/SIMULATION/NR_PHY/dlschsim.c | 4 +- openair1/SIMULATION/NR_PHY/dlsim.c | 6 +- 6 files changed, 60 insertions(+), 76 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index 171aeec73f..55cd8fad11 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -555,8 +555,7 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC time_stats_t *dlsch_scrambling_stats = &gNB->dlsch_scrambling_stats; time_stats_t *dlsch_modulation_stats = &gNB->dlsch_modulation_stats; - NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; - const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15; + const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu.pdsch_pdu_rel15; const int layerSz = frame_parms->N_RB_DL * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB; const int symbol_sz=frame_parms->ofdm_symbol_size; const int dmrs_Type = rel15->dmrsConfigType; @@ -591,9 +590,9 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC #ifdef DEBUG_DLSCH printf("PDSCH encoding:\nPayload:\n"); - for (int i = 0; i < (harq->B >> 3); i += 16) { + for (int i = 0; i < (dlsch->B >> 3); i += 16) { for (int j = 0; j < 16; j++) - printf("0x%02x\t", harq->pdu[i + j]); + printf("0x%02x\t", dlsch->pdu[i + j]); printf("\n"); } printf("\nEncoded payload:\n"); @@ -606,7 +605,7 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC #endif if (IS_SOFTMODEM_DLSIM) - memcpy(harq->f, input_ptr, (encoded_length + 7) >> 3); + memcpy(dlsch->f, input_ptr, (encoded_length + 7) >> 3); c16_t mod_symbs[rel15->NrOfCodewords][encoded_length] __attribute__((aligned(64))); for (int codeWord = 0; codeWord < rel15->NrOfCodewords; codeWord++) { @@ -791,8 +790,7 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot) for (int dlsch_id = 0; dlsch_id < msgTx->num_pdsch_slot; dlsch_id++) { NR_gNB_DLSCH_t *dlsch = msgTx->dlsch[dlsch_id]; - NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; - const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15; + const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu.pdsch_pdu_rel15; LOG_D(PHY, "pdsch: BWPStart %d, BWPSize %d, rbStart %d, rbsize %d\n", @@ -816,10 +814,10 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot) n_ptrs = (rel15->rbSize + rel15->PTRSFreqDensity - 1) / rel15->PTRSFreqDensity; ptrsSymbPerSlot = get_ptrs_symbols_in_slot(dlPtrsSymPos, rel15->StartSymbolIndex, rel15->NrOfSymbols); } - harq->unav_res = ptrsSymbPerSlot * n_ptrs; + dlsch->unav_res = ptrsSymbPerSlot * n_ptrs; /// CRC, coding, interleaving and rate matching - AssertFatal(harq->pdu != NULL, "%4d.%2d no HARQ PDU for PDSCH generation\n", msgTx->frame, msgTx->slot); + AssertFatal(dlsch->pdu != NULL, "%4d.%2d no PDU for PDSCH generation\n", msgTx->frame, msgTx->slot); /* output and its parts for each dlsch should be aligned on 64 bytes (or 8 * 64 bits) * => size_output is a sum of parts sizes rounded up to a multiple of 8 * 64 diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c index 79538c52cd..eb70819ff4 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c @@ -52,20 +52,19 @@ void free_gNB_dlsch(NR_gNB_DLSCH_t *dlsch, uint16_t N_RB, const NR_DL_FRAME_PARM a_segments = a_segments / 273 + 1; } - NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; - if (harq->b) { - free16(harq->b, a_segments * 1056); - harq->b = NULL; + if (dlsch->b) { + free16(dlsch->b, a_segments * 1056); + dlsch->b = NULL; } - if (harq->f) { - free16(harq->f, N_RB * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * 8 * NR_MAX_NB_LAYERS); - harq->f = NULL; + if (dlsch->f) { + free16(dlsch->f, N_RB * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * 8 * NR_MAX_NB_LAYERS); + dlsch->f = NULL; } for (int r = 0; r < a_segments; r++) { - free(harq->c[r]); - harq->c[r] = NULL; + free(dlsch->c[r]); + dlsch->c[r] = NULL; } - free(harq->c); + free(dlsch->c); } NR_gNB_DLSCH_t new_gNB_dlsch(NR_DL_FRAME_PARMS *frame_parms, uint16_t N_RB) @@ -80,28 +79,26 @@ NR_gNB_DLSCH_t new_gNB_dlsch(NR_DL_FRAME_PARMS *frame_parms, uint16_t N_RB) LOG_D(PHY, "Allocating %d segments (MAX %d, N_PRB %d)\n", a_segments, MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER, N_RB); uint32_t dlsch_bytes = a_segments * 1056; // allocated bytes per segment - NR_gNB_DLSCH_t dlsch; + NR_gNB_DLSCH_t dlsch = {0}; - NR_DL_gNB_HARQ_t *harq = &dlsch.harq_process; - bzero(harq, sizeof(NR_DL_gNB_HARQ_t)); - harq->b = malloc16(dlsch_bytes); - AssertFatal(harq->b, "cannot allocate memory for harq->b\n"); - bzero(harq->b, dlsch_bytes); + dlsch.b = malloc16(dlsch_bytes); + AssertFatal(dlsch.b, "cannot allocate memory for dlsch.b\n"); + bzero(dlsch.b, dlsch_bytes); - harq->c = (uint8_t **)malloc16(a_segments * sizeof(uint8_t *)); + dlsch.c = (uint8_t **)malloc16(a_segments * sizeof(uint8_t *)); for (int r = 0; r < a_segments; r++) { // account for filler in first segment and CRCs for multiple segment case // [hna] 8448 is the maximum CB size in NR // 68*348 = 68*(maximum size of Zc) // In section 5.3.2 in 38.212, the for loop is up to N + 2*Zc (maximum size of N is 66*Zc, therefore 68*Zc) - harq->c[r] = malloc16(8448); - AssertFatal(harq->c[r], "cannot allocate harq->c[%d]\n", r); - bzero(harq->c[r], 8448); + dlsch.c[r] = malloc16(8448); + AssertFatal(dlsch.c[r], "cannot allocate dlsch.c[%d]\n", r); + bzero(dlsch.c[r], 8448); } - harq->f = malloc16(N_RB * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * 8 * NR_MAX_NB_LAYERS); - AssertFatal(harq->f, "cannot allocate harq->f\n"); - bzero(harq->f, N_RB * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * 8 * NR_MAX_NB_LAYERS); + dlsch.f = malloc16(N_RB * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * 8 * NR_MAX_NB_LAYERS); + AssertFatal(dlsch.f, "cannot allocate dlsch->f\n"); + bzero(dlsch.f, N_RB * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * 8 * NR_MAX_NB_LAYERS); return (dlsch); } @@ -139,11 +136,10 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, for (int dlsch_id = 0; dlsch_id < msgTx->num_pdsch_slot; dlsch_id++) { NR_gNB_DLSCH_t *dlsch = msgTx->dlsch[dlsch_id]; - NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; unsigned int crc = 1; - const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15; + const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu.pdsch_pdu_rel15; uint32_t A = rel15->TBSize[0] << 3; - unsigned char *a = harq->pdu; + unsigned char *a = dlsch->pdu; if (rel15->rnti != SI_RNTI) { ws_trace_t tmp = {.nr = true, .direction = DIRECTION_DOWNLINK, @@ -182,9 +178,8 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, // printf("CRC %x (A %d)\n",crc,A); // printf("a0 %d a1 %d a2 %d\n", a[A>>3], a[1+(A>>3)], a[2+(A>>3)]); B = A + 24; - // harq->b = a; AssertFatal((A / 8) + 4 <= max_bytes, "A %d is too big (A/8+4 = %d > %d)\n", A, (A / 8) + 4, max_bytes); - memcpy(harq->b, a, (A / 8) + 4); // why is this +4 if the CRC is only 3 bytes? + memcpy(dlsch->b, a, (A / 8) + 4); // why is this +4 if the CRC is only 3 bytes? } else { // Add 16-bit crc (polynomial A) to payload crc = crc16(a, A) >> 16; @@ -193,9 +188,8 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, // printf("CRC %x (A %d)\n",crc,A); // printf("a0 %d a1 %d \n", a[A>>3], a[1+(A>>3)]); B = A + 16; - // harq->b = a; AssertFatal((A / 8) + 3 <= max_bytes, "A %d is too big (A/8+3 = %d > %d)\n", A, (A / 8) + 3, max_bytes); - memcpy(harq->b, a, (A / 8) + 3); // using 3 bytes to mimic the case of 24 bit crc + memcpy(dlsch->b, a, (A / 8) + 3); // using 3 bytes to mimic the case of 24 bit crc } nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[dlsch_id]; @@ -205,8 +199,8 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, TB_parameters->BG = rel15->maintenance_parms_v3.ldpcBaseGraph; TB_parameters->A = A; start_meas(dlsch_segmentation_stats); - TB_parameters->Kb = nr_segmentation(harq->b, - harq->c, + TB_parameters->Kb = nr_segmentation(dlsch->b, + dlsch->c, B, &TB_parameters->C, &TB_parameters->K, @@ -229,18 +223,17 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, for (int dlsch_id = 0; dlsch_id < msgTx->num_pdsch_slot; dlsch_id++) { NR_gNB_DLSCH_t *dlsch = msgTx->dlsch[dlsch_id]; - NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; - const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15; + const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu.pdsch_pdu_rel15; nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[dlsch_id]; #ifdef DEBUG_DLSCH_CODING for (int r = 0; r < TB_parameters->C; r++) { - LOG_D(PHY, "Encoder: B %d F %d \n", harq->B, TB_parameters->F); + LOG_D(PHY, "Encoder: B %d F %d \n", dlsch->B, TB_parameters->F); LOG_D(PHY, "start ldpc encoder segment %d/%d\n", r, TB_parameters->C); - LOG_D(PHY, "input %d %d %d %d %d \n", harq->c[r][0], harq->c[r][1], harq->c[r][2], harq->c[r][3], harq->c[r][4]); + LOG_D(PHY, "input %d %d %d %d %d \n", dlsch->c[r][0], dlsch->c[r][1], dlsch->c[r][2], dlsch->c[r][3], dlsch->c[r][4]); for (int cnt = 0; cnt < 22 * (TB_parameters->Z) / 8; cnt++) { - LOG_D(PHY, "%d ", harq->c[r][cnt]); + LOG_D(PHY, "%d ", dlsch->c[r][cnt]); } LOG_D(PHY, "\n"); } @@ -258,7 +251,7 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, rel15->NrOfSymbols, nb_re_dmrs, get_num_dmrs(rel15->dlDmrsSymbPos), - harq->unav_res, + dlsch->unav_res, rel15->qamModOrder[0], rel15->nrOfLayers); @@ -269,7 +262,7 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, for (int r = 0; r < TB_parameters->C; r++) { nrLDPC_segment_encoding_parameters_t *segment_parameters = &TB_parameters->segments[r]; - segment_parameters->c = harq->c[r]; + segment_parameters->c = dlsch->c[r]; segment_parameters->E = nr_get_E(TB_parameters->G, TB_parameters->C, TB_parameters->Qm, rel15->nrOfLayers, r); reset_meas(&segment_parameters->ts_interleave); diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c index 3f1d988c53..45a064f571 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c @@ -37,15 +37,14 @@ void nr_fill_dlsch_dl_tti_req(processingData_L1tx_t *msgTx, nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu) { NR_gNB_DLSCH_t *dlsch = &msgTx->dlsch[msgTx->num_pdsch_slot][0]; - NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; /// DLSCH struct - memcpy((void*)&harq->pdsch_pdu, (void*)pdsch_pdu, sizeof(nfapi_nr_dl_tti_pdsch_pdu)); + memcpy((void*)&dlsch->pdsch_pdu, (void*)pdsch_pdu, sizeof(nfapi_nr_dl_tti_pdsch_pdu)); AssertFatal(msgTx->num_pdsch_slot == pdsch_pdu->pdsch_pdu_rel15.pduIndex, "PDSCH PDU index %d does not match msgTx index %d\n", pdsch_pdu->pdsch_pdu_rel15.pduIndex, msgTx->num_pdsch_slot); msgTx->num_pdsch_slot++; - harq->pdu = NULL; + dlsch->pdu = NULL; } void nr_fill_dlsch_tx_req(processingData_L1tx_t *msgTx, int idx, uint8_t *sdu) @@ -55,8 +54,7 @@ void nr_fill_dlsch_tx_req(processingData_L1tx_t *msgTx, int idx, uint8_t *sdu) /* not sure if FAPI could transmit DL_TTI_req and TX_req in different orders. * for the moment, assume they are in the same order (and check!) */ NR_gNB_DLSCH_t *dlsch = &msgTx->dlsch[idx][0]; - NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; - nfapi_nr_dl_tti_pdsch_pdu *pdsch = &harq->pdsch_pdu; + nfapi_nr_dl_tti_pdsch_pdu *pdsch = &dlsch->pdsch_pdu; AssertFatal(pdsch->pdsch_pdu_rel15.pduIndex == idx, "PDSCH PDU index %d does not match %d\n", pdsch->pdsch_pdu_rel15.pduIndex, idx); - harq->pdu = sdu; + dlsch->pdu = sdu; } diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 246d3aaa6f..fe4d3869d2 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -53,21 +53,6 @@ typedef struct { int lut[MAX_PUCCH0_NID][160][14]; } NR_gNB_PUCCH0_LUT_t; -typedef struct { - /// Nfapi DLSCH PDU - nfapi_nr_dl_tti_pdsch_pdu pdsch_pdu; - /// pointer to pdu from MAC interface (this is "a" in 36.212) - uint8_t *pdu; - /// Pointer to the payload - uint8_t *b; - /// Pointers to transport block segments - uint8_t **c; - /// Interleaver outputs - uint8_t *f; - /// REs unavailable for DLSCH (overlapping with PTRS, CSIRS etc.) - uint32_t unav_res; -} NR_DL_gNB_HARQ_t; - typedef struct { int dump_frame; int round_trials[8]; @@ -112,8 +97,18 @@ typedef struct { } NR_gNB_PHY_STATS_t; typedef struct { - /// Pointers to variables related to DLSCH harq process - NR_DL_gNB_HARQ_t harq_process; + /// Nfapi DLSCH PDU + nfapi_nr_dl_tti_pdsch_pdu pdsch_pdu; + /// pointer to pdu from MAC interface (this is "a" in 36.212) + uint8_t *pdu; + /// Pointer to the payload + uint8_t *b; + /// Pointers to transport block segments + uint8_t **c; + /// Interleaver outputs + uint8_t *f; + /// REs unavailable for DLSCH (overlapping with PTRS, CSIRS etc.) + uint32_t unav_res; } NR_gNB_DLSCH_t; typedef struct { diff --git a/openair1/SIMULATION/NR_PHY/dlschsim.c b/openair1/SIMULATION/NR_PHY/dlschsim.c index c475bfc039..7a2f120043 100644 --- a/openair1/SIMULATION/NR_PHY/dlschsim.c +++ b/openair1/SIMULATION/NR_PHY/dlschsim.c @@ -442,7 +442,7 @@ int main(int argc, char **argv) processingData_L1tx_t msgDataTx; init_DLSCH_struct(gNB, &msgDataTx); NR_gNB_DLSCH_t *dlsch = &msgDataTx.dlsch[0][0]; - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->harq_process.pdsch_pdu.pdsch_pdu_rel15; + nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu.pdsch_pdu_rel15; //time_stats_t *rm_stats, *te_stats, *i_stats; unsigned int TBS = 8424; uint8_t nb_re_dmrs = 6; // No data in dmrs symbol @@ -498,7 +498,7 @@ int main(int argc, char **argv) printf("harq process ue mcs = %d Qm = %d, symb %d\n", dlsch0_ue->dlsch_config.mcs, dlsch0_ue->dlsch_config.qamModOrder, nb_symb_sch); uint8_t test_input[TBS / 8 + 4]; // + 3 for CRC + 1 additional byte, see nr_dlsch_encoding() - dlsch->harq_process.pdu = test_input; + dlsch->pdu = test_input; //unsigned char test_input[TBS / 8] __attribute__ ((aligned(16))); for (i = 0; i < TBS / 8; i++) test_input[i] = (unsigned char) rand(); diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 678b330513..cd8fef35ff 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -1059,7 +1059,7 @@ int main(int argc, char **argv) if (n_trials== 1) num_rounds = 1; NR_gNB_DLSCH_t *gNB_dlsch = &msgDataTx->dlsch[0][0]; - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &gNB_dlsch->harq_process.pdsch_pdu.pdsch_pdu_rel15; + nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &gNB_dlsch->pdsch_pdu.pdsch_pdu_rel15; for (trial = 0; trial < n_trials && !stop; trial++) { @@ -1255,7 +1255,7 @@ int main(int argc, char **argv) } for (i = 0; i < available_bits; i++) { - const uint8_t current_bit = (gNB_dlsch->harq_process.f[i / 8] & (1 << (i & 7))) >> (i & 7); + const uint8_t current_bit = (gNB_dlsch->f[i / 8] & (1 << (i & 7))) >> (i & 7); if (((current_bit == 0) && (UE_llr[i] <= 0)) || ((current_bit == 1) && (UE_llr[i] >= 0))) { if (errors_scrambling[round] == 0) { LOG_D(PHY,"First bit in error in unscrambling = %d\n",i); @@ -1275,7 +1275,7 @@ int main(int argc, char **argv) for (i = 0; i < TBS; i++) { estimated_output_bit[i] = (UE->phy_sim_dlsch_b[i/8] & (1 << (i & 7))) >> (i & 7); - test_input_bit[i] = (gNB_dlsch->harq_process.b[i / 8] & (1 << (i & 7))) >> (i & 7); // Further correct for multiple segments + test_input_bit[i] = (gNB_dlsch->b[i / 8] & (1 << (i & 7))) >> (i & 7); // Further correct for multiple segments if (estimated_output_bit[i] != test_input_bit[i]) { if(errors_bit == 0) From 751cab3d89fab95b963296ab3f18688db86d5483 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 13 Nov 2025 19:28:00 +0100 Subject: [PATCH 43/80] Simplify DLSCH: only one codeword supported --- openair1/PHY/INIT/nr_init.c | 14 +++----------- openair1/PHY/NR_TRANSPORT/nr_dlsch.c | 4 ++-- openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c | 4 ++-- openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c | 4 ++-- openair1/PHY/defs_gNB.h | 2 +- openair1/SIMULATION/NR_PHY/dlschsim.c | 2 +- openair1/SIMULATION/NR_PHY/dlsim.c | 2 +- 7 files changed, 12 insertions(+), 20 deletions(-) diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 7a360e30ff..e87a1d13db 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -408,14 +408,10 @@ void init_DLSCH_struct(PHY_VARS_gNB *gNB, processingData_L1tx_t *msg) uint16_t grid_size = cfg->carrier_config.dl_grid_size[fp->numerology_index].value; msg->num_pdsch_slot = 0; - msg->dlsch = malloc16(gNB->max_nb_pdsch * sizeof(NR_gNB_DLSCH_t *)); - int num_cw = NR_MAX_NB_LAYERS > 4? 2:1; + msg->dlsch = calloc(gNB->max_nb_pdsch, sizeof(*msg->dlsch)); for (int i = 0; i < gNB->max_nb_pdsch; i++) { LOG_D(PHY, "Allocating Transport Channel Buffers for DLSCH %d/%d\n", i, gNB->max_nb_pdsch); - msg->dlsch[i] = (NR_gNB_DLSCH_t *)malloc16(num_cw * sizeof(NR_gNB_DLSCH_t)); - for (int j = 0; j < num_cw; j++) { - msg->dlsch[i][j] = new_gNB_dlsch(fp, grid_size); - } + msg->dlsch[i] = new_gNB_dlsch(fp, grid_size); } } @@ -424,12 +420,8 @@ void reset_DLSCH_struct(const PHY_VARS_gNB *gNB, processingData_L1tx_t *msg) const NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; const nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config; const uint16_t grid_size = cfg->carrier_config.dl_grid_size[fp->numerology_index].value; - int num_cw = NR_MAX_NB_LAYERS > 4? 2:1; for (int i = 0; i < gNB->max_nb_pdsch; i++) { - for (int j = 0; j < num_cw; j++) { - free_gNB_dlsch(&msg->dlsch[i][j], grid_size, fp); - } - free(msg->dlsch[i]); + free_gNB_dlsch(&msg->dlsch[i], grid_size, fp); } free(msg->dlsch); } diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index 55cd8fad11..30137d8e35 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -789,7 +789,7 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot) size_t size_output = 0; for (int dlsch_id = 0; dlsch_id < msgTx->num_pdsch_slot; dlsch_id++) { - NR_gNB_DLSCH_t *dlsch = msgTx->dlsch[dlsch_id]; + NR_gNB_DLSCH_t *dlsch = &msgTx->dlsch[dlsch_id]; const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu.pdsch_pdu_rel15; LOG_D(PHY, @@ -850,7 +850,7 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot) unsigned char *output_ptr = output; for (int dlsch_id = 0; dlsch_id < msgTx->num_pdsch_slot; dlsch_id++) { - output_ptr += do_one_dlsch(output_ptr, gNB, msgTx->dlsch[dlsch_id], slot); + output_ptr += do_one_dlsch(output_ptr, gNB, &msgTx->dlsch[dlsch_id], slot); } } diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c index eb70819ff4..c26b56da3a 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c @@ -134,7 +134,7 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, int num_segments = 0; for (int dlsch_id = 0; dlsch_id < msgTx->num_pdsch_slot; dlsch_id++) { - NR_gNB_DLSCH_t *dlsch = msgTx->dlsch[dlsch_id]; + NR_gNB_DLSCH_t *dlsch = &msgTx->dlsch[dlsch_id]; unsigned int crc = 1; const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu.pdsch_pdu_rel15; @@ -222,7 +222,7 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, size_t dlsch_offset = 0; for (int dlsch_id = 0; dlsch_id < msgTx->num_pdsch_slot; dlsch_id++) { - NR_gNB_DLSCH_t *dlsch = msgTx->dlsch[dlsch_id]; + NR_gNB_DLSCH_t *dlsch = &msgTx->dlsch[dlsch_id]; const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu.pdsch_pdu_rel15; nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[dlsch_id]; diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c index 45a064f571..244ab5363b 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c @@ -36,7 +36,7 @@ void nr_fill_dlsch_dl_tti_req(processingData_L1tx_t *msgTx, nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu) { - NR_gNB_DLSCH_t *dlsch = &msgTx->dlsch[msgTx->num_pdsch_slot][0]; + NR_gNB_DLSCH_t *dlsch = &msgTx->dlsch[msgTx->num_pdsch_slot]; /// DLSCH struct memcpy((void*)&dlsch->pdsch_pdu, (void*)pdsch_pdu, sizeof(nfapi_nr_dl_tti_pdsch_pdu)); AssertFatal(msgTx->num_pdsch_slot == pdsch_pdu->pdsch_pdu_rel15.pduIndex, @@ -53,7 +53,7 @@ void nr_fill_dlsch_tx_req(processingData_L1tx_t *msgTx, int idx, uint8_t *sdu) /* not sure if FAPI could transmit DL_TTI_req and TX_req in different orders. * for the moment, assume they are in the same order (and check!) */ - NR_gNB_DLSCH_t *dlsch = &msgTx->dlsch[idx][0]; + NR_gNB_DLSCH_t *dlsch = &msgTx->dlsch[idx]; nfapi_nr_dl_tti_pdsch_pdu *pdsch = &dlsch->pdsch_pdu; AssertFatal(pdsch->pdsch_pdu_rel15.pduIndex == idx, "PDSCH PDU index %d does not match %d\n", pdsch->pdsch_pdu_rel15.pduIndex, idx); dlsch->pdu = sdu; diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index fe4d3869d2..af4f0d5707 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -580,7 +580,7 @@ typedef struct processingData_L1tx { /// corresponds to UL_dci_req->ul_dci_pdu_list nfapi_nr_dl_tti_pdcch_pdu ul_pdcch_pdu[NFAPI_NR_MAX_NB_CORESETS]; nfapi_nr_dl_tti_csi_rs_pdu csirs_pdu[NFAPI_NR_MAX_NB_CORESETS]; - NR_gNB_DLSCH_t **dlsch; + NR_gNB_DLSCH_t *dlsch; nfapi_nr_dl_tti_ssb_pdu ssb_pdu[64]; int n_ssb_pdu; int n_csirs_pdu; diff --git a/openair1/SIMULATION/NR_PHY/dlschsim.c b/openair1/SIMULATION/NR_PHY/dlschsim.c index 7a2f120043..ad0120cb52 100644 --- a/openair1/SIMULATION/NR_PHY/dlschsim.c +++ b/openair1/SIMULATION/NR_PHY/dlschsim.c @@ -441,7 +441,7 @@ int main(int argc, char **argv) unsigned char harq_pid = 0; //dlsch->harq_ids[subframe]; processingData_L1tx_t msgDataTx; init_DLSCH_struct(gNB, &msgDataTx); - NR_gNB_DLSCH_t *dlsch = &msgDataTx.dlsch[0][0]; + NR_gNB_DLSCH_t *dlsch = &msgDataTx.dlsch[0]; nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu.pdsch_pdu_rel15; //time_stats_t *rm_stats, *te_stats, *i_stats; unsigned int TBS = 8424; diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index cd8fef35ff..a4c4351764 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -1058,7 +1058,7 @@ int main(int argc, char **argv) n_false_positive = 0; if (n_trials== 1) num_rounds = 1; - NR_gNB_DLSCH_t *gNB_dlsch = &msgDataTx->dlsch[0][0]; + NR_gNB_DLSCH_t *gNB_dlsch = &msgDataTx->dlsch[0]; nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &gNB_dlsch->pdsch_pdu.pdsch_pdu_rel15; for (trial = 0; trial < n_trials && !stop; trial++) { From 2be5ff361f58b24e65277032d8ec53055b28aed7 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 13 Nov 2025 19:29:10 +0100 Subject: [PATCH 44/80] Don't use msgTx inside nr_dlsch_encoding() and nr_generate_pdsch() A later commit will remove "msgTx" altogether. Push it out from L1 functions. --- openair1/PHY/NR_TRANSPORT/nr_dlsch.c | 16 ++++++------ openair1/PHY/NR_TRANSPORT/nr_dlsch.h | 7 +++--- openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c | 27 +++++++++++---------- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 2 +- openair1/SIMULATION/NR_PHY/dlschsim.c | 3 +-- 5 files changed, 27 insertions(+), 28 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index 30137d8e35..7afbed41b4 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -773,9 +773,8 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC return ((size_output_tb + 511) >> 9) << 6; } -void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot) +void nr_generate_pdsch(PHY_VARS_gNB *gNB, int n_dlsch, NR_gNB_DLSCH_t *dlsch_array, int frame, int slot) { - PHY_VARS_gNB *gNB = msgTx->gNB; NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; time_stats_t *dlsch_encoding_stats = &gNB->dlsch_encoding_stats; time_stats_t *tinput = &gNB->tinput; @@ -788,8 +787,8 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot) size_t size_output = 0; - for (int dlsch_id = 0; dlsch_id < msgTx->num_pdsch_slot; dlsch_id++) { - NR_gNB_DLSCH_t *dlsch = &msgTx->dlsch[dlsch_id]; + for (int i = 0; i < n_dlsch; i++) { + NR_gNB_DLSCH_t *dlsch = &dlsch_array[i]; const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu.pdsch_pdu_rel15; LOG_D(PHY, @@ -817,7 +816,7 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot) dlsch->unav_res = ptrsSymbPerSlot * n_ptrs; /// CRC, coding, interleaving and rate matching - AssertFatal(dlsch->pdu != NULL, "%4d.%2d no PDU for PDSCH generation\n", msgTx->frame, msgTx->slot); + AssertFatal(dlsch->pdu != NULL, "%4d.%2d no PDU for PDSCH generation\n", frame, slot); /* output and its parts for each dlsch should be aligned on 64 bytes (or 8 * 64 bits) * => size_output is a sum of parts sizes rounded up to a multiple of 8 * 64 @@ -831,7 +830,8 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot) start_meas(dlsch_encoding_stats); if (nr_dlsch_encoding(gNB, - msgTx, + n_dlsch, + dlsch_array, frame, slot, frame_parms, @@ -849,8 +849,8 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot) stop_meas(dlsch_encoding_stats); unsigned char *output_ptr = output; - for (int dlsch_id = 0; dlsch_id < msgTx->num_pdsch_slot; dlsch_id++) { - output_ptr += do_one_dlsch(output_ptr, gNB, &msgTx->dlsch[dlsch_id], slot); + for (int i = 0; i < n_dlsch; i++) { + output_ptr += do_one_dlsch(output_ptr, gNB, &dlsch_array[i], slot); } } diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.h b/openair1/PHY/NR_TRANSPORT/nr_dlsch.h index 15f48825f5..443035274b 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.h +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.h @@ -38,12 +38,11 @@ void nr_fill_dlsch_dl_tti_req(processingData_L1tx_t *msgTx, nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu); void nr_fill_dlsch_tx_req(processingData_L1tx_t *msgTx, int idx, uint8_t *sdu); -void nr_generate_pdsch(processingData_L1tx_t *msgTx, - int frame, - int slot); +void nr_generate_pdsch(PHY_VARS_gNB *gNB, int n_dlsch, NR_gNB_DLSCH_t *dlsch_array, int frame, int slot); int nr_dlsch_encoding(PHY_VARS_gNB *gNB, - processingData_L1tx_t *msgTx, + int n_dlsch, + NR_gNB_DLSCH_t *dlsch_array, int frame, uint8_t slot, NR_DL_FRAME_PARMS *frame_parms, diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c index c26b56da3a..67f3dd4363 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c @@ -104,7 +104,8 @@ NR_gNB_DLSCH_t new_gNB_dlsch(NR_DL_FRAME_PARMS *frame_parms, uint16_t N_RB) } int nr_dlsch_encoding(PHY_VARS_gNB *gNB, - processingData_L1tx_t *msgTx, + int n_dlsch, + NR_gNB_DLSCH_t *dlsch_array, int frame, uint8_t slot, NR_DL_FRAME_PARMS *frame_parms, @@ -119,11 +120,11 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_DLSCH_ENCODING, VCD_FUNCTION_IN); - nrLDPC_TB_encoding_parameters_t TBs[msgTx->num_pdsch_slot]; + nrLDPC_TB_encoding_parameters_t TBs[n_dlsch]; memset(TBs, 0, sizeof(TBs)); nrLDPC_slot_encoding_parameters_t slot_parameters = {.frame = frame, .slot = slot, - .nb_TBs = msgTx->num_pdsch_slot, + .nb_TBs = n_dlsch, .threadPool = &gNB->threadPool, .tinput = tinput, .tprep = tprep, @@ -133,8 +134,8 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, int num_segments = 0; - for (int dlsch_id = 0; dlsch_id < msgTx->num_pdsch_slot; dlsch_id++) { - NR_gNB_DLSCH_t *dlsch = &msgTx->dlsch[dlsch_id]; + for (int i = 0; i < n_dlsch; i++) { + NR_gNB_DLSCH_t *dlsch = &dlsch_array[i]; unsigned int crc = 1; const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu.pdsch_pdu_rel15; @@ -192,10 +193,10 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, memcpy(dlsch->b, a, (A / 8) + 3); // using 3 bytes to mimic the case of 24 bit crc } - nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[dlsch_id]; + nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[i]; - // The harq_pid is not unique among the active HARQ processes in the instance so we use dlsch_id instead - TB_parameters->harq_unique_pid = dlsch_id; + // The harq_pid is not unique among the active HARQ processes in the instance so we use i instead + TB_parameters->harq_unique_pid = i; TB_parameters->BG = rel15->maintenance_parms_v3.ldpcBaseGraph; TB_parameters->A = A; start_meas(dlsch_segmentation_stats); @@ -221,11 +222,11 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, size_t segments_offset = 0; size_t dlsch_offset = 0; - for (int dlsch_id = 0; dlsch_id < msgTx->num_pdsch_slot; dlsch_id++) { - NR_gNB_DLSCH_t *dlsch = &msgTx->dlsch[dlsch_id]; + for (int i = 0; i < n_dlsch; i++) { + NR_gNB_DLSCH_t *dlsch = &dlsch_array[i]; const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu.pdsch_pdu_rel15; - nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[dlsch_id]; + nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[i]; #ifdef DEBUG_DLSCH_CODING for (int r = 0; r < TB_parameters->C; r++) { @@ -281,8 +282,8 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, gNB->nrLDPC_coding_interface.nrLDPC_coding_encoder(&slot_parameters); - for (int dlsch_id = 0; dlsch_id < msgTx->num_pdsch_slot; dlsch_id++) { - nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[dlsch_id]; + for (int i = 0; i < n_dlsch; i++) { + nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[i]; for (int r = 0; r < TB_parameters->C; r++) { nrLDPC_segment_encoding_parameters_t *segment_parameters = &TB_parameters->segments[r]; merge_meas(dlsch_interleaving_stats, &segment_parameters->ts_interleave); diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 6c94a3005e..f3f80e2ae4 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -312,7 +312,7 @@ void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx, if (msgTx->num_pdsch_slot > 0) { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DLSCH,1); LOG_D(PHY, "PDSCH generation started (%d) in frame %d.%d\n", msgTx->num_pdsch_slot,frame,slot); - nr_generate_pdsch(msgTx, frame, slot); + nr_generate_pdsch(gNB, msgTx->num_pdsch_slot, msgTx->dlsch, frame, slot); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DLSCH,0); } msgTx->num_pdsch_slot = 0; diff --git a/openair1/SIMULATION/NR_PHY/dlschsim.c b/openair1/SIMULATION/NR_PHY/dlschsim.c index ad0120cb52..0dbc230f09 100644 --- a/openair1/SIMULATION/NR_PHY/dlschsim.c +++ b/openair1/SIMULATION/NR_PHY/dlschsim.c @@ -515,8 +515,7 @@ int main(int argc, char **argv) unsigned char output[rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * NR_MAX_NB_LAYERS] __attribute__((aligned(64))); bzero(output, sizeof(output)); if (input_fd == NULL) { - msgDataTx.num_pdsch_slot = 1; - nr_dlsch_encoding(gNB, &msgDataTx, frame, slot, frame_parms, output, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + nr_dlsch_encoding(gNB, 1, dlsch, frame, slot, frame_parms, output, NULL, NULL, NULL, NULL, NULL, NULL, NULL); } for (SNR = snr0; SNR < snr1 && !stop; SNR += snr_step) { From 8d2a5c6fd607ee6c4d6b7133e78e4edf6c04e856 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 6 Nov 2025 12:26:06 +0100 Subject: [PATCH 45/80] First slot indication makes no sense: tx thread should trigger --- nfapi/oai_integration/nfapi_pnf.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/nfapi/oai_integration/nfapi_pnf.c b/nfapi/oai_integration/nfapi_pnf.c index 3de11d8003..bad2d036c9 100644 --- a/nfapi/oai_integration/nfapi_pnf.c +++ b/nfapi/oai_integration/nfapi_pnf.c @@ -1825,13 +1825,6 @@ int nr_start_request(nfapi_pnf_config_t *config, nfapi_pnf_phy_config_t *phy, nf nfapi_nr_send_pnf_start_resp(config, p7_config->phy_id); printf("[PNF] Sending first P7 slot indication\n"); #endif -#if 1 - nfapi_pnf_p7_slot_ind(p7_config, p7_config->phy_id, 0, 0); - printf("[PNF] Sent first P7 slot ind\n"); -#else - nfapi_pnf_p7_subframe_ind(p7_config, p7_config->phy_id, 0); // SFN_SF set to zero - correct??? - printf("[PNF] Sent first P7 subframe ind\n"); -#endif return 0; } From 247e908b6eb97c82800d4602ff45506c6a13a693 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 10 Nov 2025 14:31:23 +0100 Subject: [PATCH 46/80] Simplify UndeployObject() and GetDeployedObjects() GetRunningServices() was returning all services, running or stopped. Hence, rename to reflect what this function does, and rewrite slightly to better capture what is actually happening. Also, don't return the container ID, as we don't use it. Call stop on all services, as we will down the deployment right after. The list of services is still used to retrieve logs. Remove a stray "return False", which would sometimes prevent us from seeing all error messages. --- ci-scripts/cls_containerize.py | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index 32ce498be0..ee295b1f79 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -165,25 +165,26 @@ def CopyinServiceLog(ssh, lSourcePath, svcName, wd_yaml, ctx): ssh.run(f'docker compose -f {wd_yaml} logs {svcName} --no-log-prefix &> {remote_filename}') return archiveArtifact(ssh, ctx, remote_filename) -def GetRunningServices(ssh, file): +def GetDeployedServices(ssh, file): ret = ssh.run(f'docker compose -f {file} config --services') if ret.returncode != 0: + logging.error("could not get services") return None allServices = ret.stdout.splitlines() - running_services = [] + deployed_services = [] for s in allServices: - # outputs the hash if the container is running - ret = ssh.run(f'docker compose -f {file} ps --all --quiet -- {s}') + # outputs the hash if the container has been deployed (but might be stopped) + ret = ssh.run(f'docker compose -f {file} ps --all --quiet -- {s}', silent=True) if ret.returncode != 0: - logging.info(f"service {s}: {ret.stdout}") + # error: should not happen as we iterate over docker-provided service list + logging.error(f"service {s}: {ret.stdout}") elif ret.stdout == "": - logging.warning(f"could not retrieve information for service {s}") + logging.info(f"service {s} not deployed") else: c = ret.stdout - logging.debug(f'running service {s} with container id {c}') - running_services.append((s, c)) - logging.info(f'stopping services: {running_services}') - return running_services + logging.info(f'service {s} with container id {c}') + deployed_services.append(s) + return deployed_services def CheckLogs(self, filename, HTML, RAN): success = True @@ -763,19 +764,19 @@ class Containerize(): wd_yaml = f'{wd}/docker-compose.y*ml' with cls_cmd.getConnection(node) as ssh: ExistEnvFilePrint(ssh, wd) - services = GetRunningServices(ssh, wd_yaml) + services = GetDeployedServices(ssh, wd_yaml) copyin_res = None + ssh.run(f'docker compose -f {wd_yaml} stop') if services is not None: - all_serv = " ".join([s for s, _ in services]) - ssh.run(f'docker compose -f {wd_yaml} stop -- {all_serv}') - copyin_res = [CopyinServiceLog(ssh, lSourcePath, s, wd_yaml, ctx) for s, _ in services] + copyin_res = [CopyinServiceLog(ssh, lSourcePath, s, wd_yaml, ctx) for s in services] else: logging.warning('could not identify services to stop => no log file') ssh.run(f'docker compose -f {wd_yaml} down -v') ssh.run(f'rm {wd}/.env') if not copyin_res: HTML.CreateHtmlTestRowQueue('N/A', 'KO', ['Could not copy logfile(s)']) - return False + logging.error(f"could not copy all files: {copyin_res=} {services=}") + success = False else: log_results = [CheckLogs(self, f, HTML, RAN) for f in copyin_res] success = all(log_results) From ddcb216a3543d96a1c86f4b3a8c5bcb19d342f4f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 13 Nov 2025 15:04:14 +0100 Subject: [PATCH 47/80] Improve logging in CI Undeploy/DeployObject() Consistently print requested services (if applicable) and outcome of the step. --- ci-scripts/cls_containerize.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index ee295b1f79..367bb47eb5 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -716,7 +716,6 @@ class Containerize(): def DeployObject(self, ctx, node, HTML): num_attempts = self.num_attempts lSourcePath = self.eNBSourceCodePath - logging.debug(f'Deploying OAI Object on server: {node}') yaml = self.yamlPath.strip('/') wd = f'{lSourcePath}/{yaml}' wd_yaml = f'{wd}/docker-compose.y*ml' @@ -727,6 +726,7 @@ class Containerize(): logging.error(msg) HTML.CreateHtmlTestRowQueue('N/A', 'KO', [msg]) return False + logging.info(f'\u001B[1mDeploying object(s) "{services}" on server {node}\u001B[0m') ExistEnvFilePrint(ssh, wd) WriteEnvFile(ssh, services, wd, self.deploymentTag, self.flexricTag) if num_attempts <= 0: @@ -751,14 +751,16 @@ class Containerize(): imagesInfo = info.stdout.splitlines()[1:] logging.debug(f'{info.stdout.splitlines()[1:]}') if deployed: - HTML.CreateHtmlTestRowQueue('N/A', 'OK', ['\n'.join(imagesInfo)]) + HTML.CreateHtmlTestRowQueue(self.services, 'OK', ['\n'.join(imagesInfo)]) + logging.info('\u001B[1m Deploying objects Pass\u001B[0m') else: - HTML.CreateHtmlTestRowQueue('N/A', 'KO', ['\n'.join(imagesInfo)]) + HTML.CreateHtmlTestRowQueue(self.services, 'KO', ['\n'.join(imagesInfo)]) + logging.error('\u001B[1m Deploying objects Failed\u001B[0m') return deployed def UndeployObject(self, ctx, node, HTML, RAN): lSourcePath = self.eNBSourceCodePath - logging.debug(f'\u001B[1m Undeploying OAI Object from server: {node}\u001B[0m') + logging.info(f'\u001B[1m Undeploying all objects from server {node}\u001B[0m') yaml = self.yamlPath.strip('/') wd = f'{lSourcePath}/{yaml}' wd_yaml = f'{wd}/docker-compose.y*ml' @@ -781,7 +783,7 @@ class Containerize(): log_results = [CheckLogs(self, f, HTML, RAN) for f in copyin_res] success = all(log_results) if success: - logging.info('\u001B[1m Undeploying OAI Object Pass\u001B[0m') + logging.info('\u001B[1m Undeploying objects Pass\u001B[0m') else: - logging.error('\u001B[1m Undeploying OAI Object Failed\u001B[0m') + logging.error('\u001B[1m Undeploying objects Failed\u001B[0m') return success From de8d0991ec290b537b1d515808d62edaa48c837b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 13 Nov 2025 11:34:30 +0100 Subject: [PATCH 48/80] Remove services to be undeployed from XML files In all these cases, the intention is to undeploy all services. Correspondingly, remove the services from the XML to avoid any ambiguity. --- ci-scripts/xml_files/container_5g_rfsim_u0_25prb.xml | 1 - ci-scripts/xml_files/container_sa_n310_2X2_100MHz_quectel.xml | 1 - ci-scripts/xml_files/container_sa_n310_2X2_60MHz_quectel.xml | 1 - ci-scripts/xml_files/container_sa_n310_4X4_60MHz_quectel.xml | 1 - 4 files changed, 4 deletions(-) diff --git a/ci-scripts/xml_files/container_5g_rfsim_u0_25prb.xml b/ci-scripts/xml_files/container_5g_rfsim_u0_25prb.xml index d563b3aab4..86b9040b63 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_u0_25prb.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_u0_25prb.xml @@ -144,7 +144,6 @@ true Undeploy all OAI 5G stack localhost - oai-vnf oai-pnf ci-scripts/yaml_files/5g_rfsimulator_u0_25prb 1,0,0,0 1,0,0,0 diff --git a/ci-scripts/xml_files/container_sa_n310_2X2_100MHz_quectel.xml b/ci-scripts/xml_files/container_sa_n310_2X2_100MHz_quectel.xml index a4d72398e1..ad98afcd32 100644 --- a/ci-scripts/xml_files/container_sa_n310_2X2_100MHz_quectel.xml +++ b/ci-scripts/xml_files/container_sa_n310_2X2_100MHz_quectel.xml @@ -146,7 +146,6 @@ Undeploy gNB matix ci-scripts/yaml_files/5g_sa_n310_2x2_100MHz - oai-gnb 10,100,100,100 10,100,100,100 diff --git a/ci-scripts/xml_files/container_sa_n310_2X2_60MHz_quectel.xml b/ci-scripts/xml_files/container_sa_n310_2X2_60MHz_quectel.xml index ab7188c023..a809fafa2c 100644 --- a/ci-scripts/xml_files/container_sa_n310_2X2_60MHz_quectel.xml +++ b/ci-scripts/xml_files/container_sa_n310_2X2_60MHz_quectel.xml @@ -146,7 +146,6 @@ Undeploy gNB matix ci-scripts/yaml_files/5g_sa_n310_2x2_60MHz - oai-gnb 15,100,100,100 20,100,100,100 diff --git a/ci-scripts/xml_files/container_sa_n310_4X4_60MHz_quectel.xml b/ci-scripts/xml_files/container_sa_n310_4X4_60MHz_quectel.xml index d7cf992aa4..d4d0d51258 100644 --- a/ci-scripts/xml_files/container_sa_n310_4X4_60MHz_quectel.xml +++ b/ci-scripts/xml_files/container_sa_n310_4X4_60MHz_quectel.xml @@ -146,7 +146,6 @@ Undeploy VNF-PNF matix ci-scripts/yaml_files/5g_sa_n310_4x4_60MHz - oai-vnf oai-pnf 10,100,100,100 10,100,100,100 From 81680e29a9f7d91c2fe6bf46971a4566af7655d8 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 13 Nov 2025 15:04:10 +0100 Subject: [PATCH 49/80] Implement StopObject() For some test cases, we might want to stop a service earlier. This functionality is done by StopObject(). Test log collection is still done by UndeployObject(), which will collect the logs of all services (at that point, stopped or not). --- ci-scripts/cls_containerize.py | 29 +++++++++++++++++++ ci-scripts/main.py | 4 ++- ci-scripts/tests/deployment.py | 27 +++++++++++++++++ .../tests/simple-undep/docker-compose.yml | 23 +++++++++++++++ ci-scripts/xml_class_list.yml | 1 + 5 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 ci-scripts/tests/simple-undep/docker-compose.yml diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index 367bb47eb5..c94b0c8dfb 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -758,6 +758,35 @@ class Containerize(): logging.error('\u001B[1m Deploying objects Failed\u001B[0m') return deployed + def StopObject(self, ctx, node, HTML): + lSourcePath = self.eNBSourceCodePath + if not self.services: + raise ValueError(f'no services provided') + logging.info(f'\u001B[1m Stopping objects "{self.services}" from server: {node}\u001B[0m') + reqServices = self.services.split() + yaml = self.yamlPath.strip('/') + wd = f'{lSourcePath}/{yaml}' + wd_yaml = f'{wd}/docker-compose.y*ml' + with cls_cmd.getConnection(node) as ssh: + ExistEnvFilePrint(ssh, wd) + services = GetDeployedServices(ssh, wd_yaml) + success = [] + fail = [] + for s in reqServices: + if s in services: + ssh.run(f'docker compose -f {wd_yaml} stop -- {s}') + success.append(s) + else: + logging.error(f"no such service {s}") + fail.append(s) + if success == reqServices: + logging.info('\u001B[1m Stopping object Pass\u001B[0m') + HTML.CreateHtmlTestRowQueue(self.services, 'OK', [f'Stopped {self.services}']) + else: + logging.error('\u001B[1m Stopping object Failed\u001B[0m') + HTML.CreateHtmlTestRowQueue(self.services, 'KO', [f'Failed stopping {" ".join(fail)}, succeeded {" ".join(success)}']) + return success + def UndeployObject(self, ctx, node, HTML, RAN): lSourcePath = self.eNBSourceCodePath logging.info(f'\u001B[1m Undeploying all objects from server {node}\u001B[0m') diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 2428df83af..8aadad76bb 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -214,7 +214,7 @@ def ExecuteActionWithParam(action, ctx, node): core_op = getattr(cls_oaicitest.OaiCiTest, action) success = core_op(cn_id, ctx, HTML) - elif action == 'Deploy_Object' or action == 'Undeploy_Object' or action == "Create_Workspace": + elif action == 'Deploy_Object' or action == 'Undeploy_Object' or action == "Create_Workspace" or action == "Stop_Object": CONTAINERS.yamlPath = test.findtext('yaml_path') string_field=test.findtext('d_retx_th') if (string_field is not None): @@ -227,6 +227,8 @@ def ExecuteActionWithParam(action, ctx, node): CONTAINERS.deploymentTag = cls_containerize.CreateTag(CONTAINERS.ranCommitID, CONTAINERS.ranBranch, CONTAINERS.ranAllowMerge) if action == 'Deploy_Object': success = CONTAINERS.DeployObject(ctx, node, HTML) + elif action == 'Stop_Object': + success = CONTAINERS.StopObject(ctx, node, HTML) elif action == 'Undeploy_Object': success = CONTAINERS.UndeployObject(ctx, node, HTML, RAN) elif action == 'Create_Workspace': diff --git a/ci-scripts/tests/deployment.py b/ci-scripts/tests/deployment.py index e7efc707bf..10bd2c843f 100644 --- a/ci-scripts/tests/deployment.py +++ b/ci-scripts/tests/deployment.py @@ -60,6 +60,33 @@ class TestDeploymentMethods(unittest.TestCase): self.assertTrue(deploy) self.assertTrue(undeploy) + def test_stop_services(self): + self.cont.yamlPath = 'tests/simple-undep/' + self.cont.deploymentTag = "noble" + # should deploy both testA and testB + deploy = self.cont.DeployObject(self.ctx, self.node, self.html) + # should fail (no such service) + self.cont.services = "testC" + stopC = self.cont.StopObject(self.ctx, self.node, self.html) + # should stop testA + self.cont.services = "testA" + stopA = self.cont.StopObject(self.ctx, self.node, self.html) + # should (re-)stop testA (no-op) + self.cont.services = "testA" + stopA2 = self.cont.StopObject(self.ctx, self.node, self.html) + # should deploy testB + self.cont.services = "testB" + stopB = self.cont.StopObject(self.ctx, self.node, self.html) + # should not undeploy anything (everything already stopped) + self.cont.services = None + undeployAll = self.cont.UndeployObject(self.ctx, self.node, self.html, self.ran) + self.assertTrue(deploy) + self.assertFalse(stopC) + self.assertTrue(stopA) + self.assertTrue(stopA2) + self.assertTrue(stopB) + self.assertTrue(undeployAll) + def test_deployfails(self): # fails reliably old = self.cont.yamlPath diff --git a/ci-scripts/tests/simple-undep/docker-compose.yml b/ci-scripts/tests/simple-undep/docker-compose.yml new file mode 100644 index 0000000000..6f88826a9a --- /dev/null +++ b/ci-scripts/tests/simple-undep/docker-compose.yml @@ -0,0 +1,23 @@ +services: + testA: + image: ubuntu:${TAG:-jammy} + container_name: test_container_A + cap_drop: + - ALL + entrypoint: /bin/bash -c "sleep infinity" + healthcheck: + test: /bin/bash -c "true" + interval: 1s + timeout: 1s + retries: 1 + testB: + image: ubuntu:${TAG:-jammy} + container_name: test_container_B + cap_drop: + - ALL + entrypoint: /bin/bash -c "sleep infinity" + healthcheck: + test: /bin/bash -c "true" + interval: 1s + timeout: 1s + retries: 1 diff --git a/ci-scripts/xml_class_list.yml b/ci-scripts/xml_class_list.yml index 615454bbea..a20b78fc99 100755 --- a/ci-scripts/xml_class_list.yml +++ b/ci-scripts/xml_class_list.yml @@ -20,6 +20,7 @@ - Build_Image - Build_Run_Tests - Deploy_Object + - Stop_Object - Undeploy_Object - Cppcheck_Analysis - Deploy_Run_OC_PhySim From 6a6588e9cbb13ffdaa01c88537293d431be9f96b Mon Sep 17 00:00:00 2001 From: Teodora Date: Thu, 13 Nov 2025 12:11:03 +0100 Subject: [PATCH 50/80] OAI-FLEXRIC-RAN-Integration-Test CI pipeline 1. Rename oai-flexric to nearRT-RIC. FlexRIC is a project combining nearRT-RIC, xApps, and E2 agent emulators. 2. Instead of undeploying all the containers at the same time, and not checking the logs for xApps and nearRT-RIC, do the following: - Stop containers (docker compose stop) - one or subgroup of running containers in the following order: a) xapp-kpm-moni b) xapp-kpm-rc c) xapp-gtp-mac-rlc-pdcp-moni d) oai-nr-ue oai-nr-ue2 e) oai-gnb f) nearRT-RIC - Undeploy containers (docker compose down), collect and analyze all the logs. --- ci-scripts/cls_containerize.py | 19 +++++ .../xml_files/container_5g_flexric_rfsim.xml | 79 +++++++++++++++++-- .../5g_rfsimulator_flexric/docker-compose.yml | 14 ++-- 3 files changed, 97 insertions(+), 15 deletions(-) diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index c94b0c8dfb..cd07851319 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -47,6 +47,7 @@ import helpreadme as HELP import constants as CONST import cls_oaicitest from cls_ci_helper import archiveArtifact +from collections import deque #----------------------------------------------------------- # Helper functions used here and in other classes @@ -216,6 +217,24 @@ def CheckLogs(self, filename, HTML, RAN): else: HTML.CreateHtmlTestRowQueue(opt, 'OK', [HTML.htmleNBFailureMsg]) HTML.htmleNBFailureMsg = "" + elif 'xapp' in name: + opt = f"Undeploy {name}" + with open(f'{filename}', "r") as f: + last_line = deque(f, maxlen=1).pop() + if ('Test xApp run SUCCESSFULLY' in last_line): + HTML.CreateHtmlTestRowQueue(opt, 'OK', ["xApp run successfully"]) + else: + HTML.CreateHtmlTestRowQueue(opt, 'KO', ["xApp didn't run successfully"]) + success = False + elif 'RIC' in name: + opt = f"Undeploy {name}" + with open(f'{filename}', 'r') as f: + last_line = deque(f, maxlen=1).pop() + if ('Removing E2 Node' in last_line): + HTML.CreateHtmlTestRowQueue(opt, 'OK', ["nearRT-RIC run successfully"]) + else: + HTML.CreateHtmlTestRowQueue(opt, 'KO', ["nearRT-RIC didn't run successfully"]) + success = False else: logging.info(f"Skipping analysis of log '{filename}': no submatch for xNB/UE") logging.debug(f"log check: file {filename} passed analysis {success}") diff --git a/ci-scripts/xml_files/container_5g_flexric_rfsim.xml b/ci-scripts/xml_files/container_5g_flexric_rfsim.xml index 536952a2bc..135eab6b68 100644 --- a/ci-scripts/xml_files/container_5g_flexric_rfsim.xml +++ b/ci-scripts/xml_files/container_5g_flexric_rfsim.xml @@ -42,6 +42,13 @@ 002006 444444 100002 + 100003 + 100004 + 100005 + 100006 + 100007 + 100008 + 100009 100001 222221 222222 @@ -95,10 +102,10 @@ Deploy_Object - Deploy OAI FlexRIC + Deploy OAI nearRT-RIC localhost ci-scripts/yaml_files/5g_rfsimulator_flexric - oai-flexric + nearRT-RIC @@ -151,16 +158,72 @@ + Stop_Object + Stop RC monitoring xApp + localhost + ci-scripts/yaml_files/5g_rfsimulator_flexric + xapp-rc-moni + + + + Stop_Object + Stop KPM monitoring xApp + localhost + ci-scripts/yaml_files/5g_rfsimulator_flexric + xapp-kpm-moni + + + + Stop_Object + Stop KPM monitoring and RC control xApp + localhost + ci-scripts/yaml_files/5g_rfsimulator_flexric + xapp-kpm-rc + + + + Stop_Object + Stop custom SMs monitoring xApp + localhost + ci-scripts/yaml_files/5g_rfsimulator_flexric + xapp-gtp-mac-rlc-pdcp-moni + + + + Stop_Object + Stop OAI UEs + localhost + ci-scripts/yaml_files/5g_rfsimulator_flexric + oai-nr-ue oai-nr-ue2 + + + + Stop_Object + Stop OAI gNB + localhost + ci-scripts/yaml_files/5g_rfsimulator_flexric + oai-gnb + + + + Stop_Object + Stop nearRT-RIC + localhost + ci-scripts/yaml_files/5g_rfsimulator_flexric + nearRT-RIC + + + Undeploy_Object - Undeploy RAN and Flexric + Undeploy RAN and FlexRIC localhost ci-scripts/yaml_files/5g_rfsimulator_flexric true - + Deploy_Object - RC monitoring + Deploy RC monitoring localhost ci-scripts/yaml_files/5g_rfsimulator_flexric xapp-rc-moni @@ -168,7 +231,7 @@ Deploy_Object - KPM monitoring + Deploy KPM monitoring localhost ci-scripts/yaml_files/5g_rfsimulator_flexric xapp-kpm-moni @@ -176,7 +239,7 @@ Deploy_Object - KPM monitoring and RC control + Deploy KPM monitoring and RC control localhost ci-scripts/yaml_files/5g_rfsimulator_flexric xapp-kpm-rc @@ -184,7 +247,7 @@ Deploy_Object - Custom SMs monitoring + Deploy custom SMs monitoring localhost ci-scripts/yaml_files/5g_rfsimulator_flexric xapp-gtp-mac-rlc-pdcp-moni diff --git a/ci-scripts/yaml_files/5g_rfsimulator_flexric/docker-compose.yml b/ci-scripts/yaml_files/5g_rfsimulator_flexric/docker-compose.yml index 8e1688dff3..5bb8d0246d 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator_flexric/docker-compose.yml +++ b/ci-scripts/yaml_files/5g_rfsimulator_flexric/docker-compose.yml @@ -1,7 +1,7 @@ services: - oai-flexric: + nearRT-RIC: image: ${REGISTRY-oaisoftwarealliance/}oai-flexric:${FLEXRIC_TAG:-develop} - container_name: oai-flexric + container_name: nearRT-RIC networks: public_net: ipv4_address: 192.168.70.150 @@ -17,7 +17,7 @@ services: command: "stdbuf -o0 /usr/local/flexric/xApp/c/monitor/xapp_rc_moni" container_name: xapp-rc-moni depends_on: - - oai-flexric + - nearRT-RIC - oai-gnb networks: public_net: @@ -34,7 +34,7 @@ services: command: "stdbuf -o0 /usr/local/flexric/xApp/c/monitor/xapp_kpm_moni" container_name: xapp-kpm-moni depends_on: - - oai-flexric + - nearRT-RIC - oai-gnb networks: public_net: @@ -51,7 +51,7 @@ services: command: "stdbuf -o0 /usr/local/flexric/xApp/c/kpm_rc/xapp_kpm_rc" container_name: xapp-kpm-rc depends_on: - - oai-flexric + - nearRT-RIC - oai-gnb networks: public_net: @@ -68,7 +68,7 @@ services: command: "stdbuf -o0 /usr/local/flexric/xApp/c/monitor/xapp_gtp_mac_rlc_pdcp_moni" container_name: xapp-gtp-mac-rlc-pdcp-moni depends_on: - - oai-flexric + - nearRT-RIC - oai-gnb networks: public_net: @@ -88,7 +88,7 @@ services: USE_ADDITIONAL_OPTIONS: -E --rfsim --log_config.global_log_options level,nocolor,time ASAN_OPTIONS: detect_leaks=0 depends_on: - - oai-flexric + - nearRT-RIC networks: public_net: ipv4_address: 192.168.70.151 From 090cf00c76b3d9cdf16ca2987044593f425c95ba Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 12 Nov 2025 16:14:11 +0100 Subject: [PATCH 51/80] Simplify logging UTC option to only show time We probably almost never care about the date, but it takes a lot of space. Remove it; if somebody needs the full time stamp including the date, we could still add it with a new option. --- common/utils/LOG/log.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/common/utils/LOG/log.c b/common/utils/LOG/log.c index 91c97ac1ac..8e332b7797 100644 --- a/common/utils/LOG/log.c +++ b/common/utils/LOG/log.c @@ -575,8 +575,7 @@ static inline int log_header(log_component_t *c, struct tm utc_time; if (gmtime_r(&t.tv_sec, &utc_time) == NULL) abort(); - snprintf(timeString, sizeof(timeString), "%04d-%02d-%02d %02d:%02d:%02d.%06lu UTC ", - utc_time.tm_year + 1900, utc_time.tm_mon + 1, utc_time.tm_mday, + snprintf(timeString, sizeof(timeString), "[%02d:%02d:%02d.%06lu] ", utc_time.tm_hour, utc_time.tm_min, utc_time.tm_sec, t.tv_nsec / 1000); } else { snprintf(timeString, sizeof(timeString), "%lu.%06lu ", From 7f57019128b5d4500fd6bec80ae4e9d93a478ef3 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 14 Nov 2025 16:01:07 +0100 Subject: [PATCH 52/80] log: Only print one space if no level selected Prior to this change, when no "level" option is given to the logging module, we see [PHY] RU 0 RF started cpu_meas_enabled 0 [HW] No connected device, generating void samples... with three spaces, which is too much. This change reduces the amount of spaces to 1 without log level. Co-authored-by: Robert Schmidt --- common/utils/LOG/log.c | 29 +++++++++++++++++------------ common/utils/LOG/log.h | 2 +- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/common/utils/LOG/log.c b/common/utils/LOG/log.c index 8e332b7797..bb7d0482cf 100644 --- a/common/utils/LOG/log.c +++ b/common/utils/LOG/log.c @@ -509,12 +509,15 @@ int logInit (void) for (int i = 0; i < MAX_LOG_PREDEF_COMPONENTS; i++) register_log_component(comp_name[i], comp_extension[i], i); - for (int i=0 ; log_level_names[i].name != NULL ; i++) - g_log->level2string[i] = toupper(log_level_names[i].name[0]); // uppercased first letter of level name - g_log->filelog_name = "/tmp/openair.log"; log_getconfig(g_log); + for (int i = 0; log_level_names[i].name != NULL; i++) + if (g_log->flag & FLAG_LEVEL) + snprintf(g_log->level2string[i], sizeof g_log->level2string[i], " %c ", toupper(log_level_names[i].name[0])); + else + snprintf(g_log->level2string[i], sizeof g_log->level2string[i], " "); + // set all unused component items to 0, they are for non predefined components for (int i=MAX_LOG_PREDEF_COMPONENTS; i < MAX_LOG_COMPONENTS; i++) { memset(&(g_log->log_component[i]),0,sizeof(log_component_t)); @@ -592,15 +595,17 @@ static inline int log_header(log_component_t *c, } else { threadIdString[0] = 0; } - return snprintf(log_buffer, buffsize, "%s%s%s[%s] %c %s%s", - flag & FLAG_NOCOLOR ? "" : log_level_highlight_start[level], - timeString, - threadIdString, - c->name, - flag & FLAG_LEVEL ? g_log->level2string[level] : ' ', - l, - threadname - ); + + return snprintf(log_buffer, + buffsize, + "%s%s%s[%s]%s%s%s", + flag & FLAG_NOCOLOR ? "" : log_level_highlight_start[level], + timeString, + threadIdString, + c->name, + g_log->level2string[level], // will print space if no level selected + l, + threadname); } void logRecord_mt(const char *file, diff --git a/common/utils/LOG/log.h b/common/utils/LOG/log.h index c873b0d418..37f903c597 100644 --- a/common/utils/LOG/log.h +++ b/common/utils/LOG/log.h @@ -217,7 +217,7 @@ typedef struct { typedef struct { log_component_t log_component[MAX_LOG_COMPONENTS]; log_component_back_t log_rarely_used[MAX_LOG_COMPONENTS]; - char level2string[NUM_LOG_LEVEL]; + char level2string[NUM_LOG_LEVEL][4]; int flag; char *filelog_name; debug_flags_t debug_mask; From ea1aa382c3932606b388a599bfc7e374d1581e6d Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 14 Nov 2025 17:05:49 +0100 Subject: [PATCH 53/80] Update log header format to improve visual alignment The new format left-aligns the component name and enforces a minimum width of 7 (log component) characters, padding shorter names with spaces after the closing "]". Example output: [14:05:43.395376] [E1AP] I releasing UE 1 [14:05:43.395400] [GTPU] I [91] UE ID 1: Delete all tunnels (1 tunnels) [14:05:43.395414] [NR_RRC] A [DL] (cellID bc614e, UE ID 1 RNTI 8e27) Send RRC Release [14:05:43.395431] [RRC] I UE 1: received bearer release complete [14:05:43.424551] [RLC] W Remove UE 36391 [14:05:43.424597] [NR_RRC] I removed UE CU UE ID 1/RNTI 8e27 [14:05:43.424773] [NR_RRC] A [--] (cellID bc614e, UE ID 1 RNTI 8e27) Remove UE context [14:05:43.425205] [NR_MAC] I Remove NR rnti 0x8e27 [14:05:43.582158] [HW] W Lost socket ^C ** Caught SIGTERM, shutting down Returned from ITTI signal handler [14:05:43.948721] [GNB_APP] I stopping nr-softmodem [14:05:43.948746] [PHY] I Killing gNB 0 processing threads [14:05:44.574818] [PHY] I Stopping RU 0 processing threads [14:05:44.575000] [PHY] I RU 0 RF device stopped [14:05:44.575006] [GNB_APP] I turned off RU rfdevice --- common/utils/LOG/log.c | 16 +++++++++++----- common/utils/LOG/log.h | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/common/utils/LOG/log.c b/common/utils/LOG/log.c index bb7d0482cf..354fae2fb1 100644 --- a/common/utils/LOG/log.c +++ b/common/utils/LOG/log.c @@ -461,9 +461,15 @@ int register_log_component(const char *name, const char *fext, int compidx) } if (computed_compidx >= 0 && computed_compidx log_component[computed_compidx].name = strdup(name); - g_log->log_component[computed_compidx].stream = stdout; - g_log->log_component[computed_compidx].filelog = 0; + log_component_t *c = &g_log->log_component[computed_compidx]; + c->name = strdup(name); + int n = snprintf(c->headerName, sizeof(c->headerName), "[%s", c->name); + if (n >= sizeof(c->headerName) - 1) // snprintf() truncated + n = sizeof(c->headerName) - 2; + c->headerName[n] = ']'; + c->headerName[n + 1] = 0; + c->stream = stdout; + c->filelog = 0; g_log->log_rarely_used[computed_compidx].filelog_name = calloc(1, strlen(name) + 16); /* /tmp/.%s */ sprintf(g_log->log_rarely_used[computed_compidx].filelog_name, "/tmp/%s.", name); strncat(g_log->log_rarely_used[computed_compidx].filelog_name, fext, 3); @@ -598,11 +604,11 @@ static inline int log_header(log_component_t *c, return snprintf(log_buffer, buffsize, - "%s%s%s[%s]%s%s%s", + "%s%s%s%-8s%s%s%s", flag & FLAG_NOCOLOR ? "" : log_level_highlight_start[level], timeString, threadIdString, - c->name, + c->headerName, g_log->level2string[level], // will print space if no level selected l, threadname); diff --git a/common/utils/LOG/log.h b/common/utils/LOG/log.h index 37f903c597..312f2c9510 100644 --- a/common/utils/LOG/log.h +++ b/common/utils/LOG/log.h @@ -206,6 +206,7 @@ typedef struct { typedef struct { const char *name; + char headerName[19]; int level; int filelog; FILE *stream; From 875ec96fce0b3ac0f15dde5abdab8ad34c4a90cf Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 14 Nov 2025 17:07:13 +0100 Subject: [PATCH 54/80] When logging function names, align to 32 characters --- common/utils/LOG/log.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/utils/LOG/log.c b/common/utils/LOG/log.c index 354fae2fb1..23aa075ca1 100644 --- a/common/utils/LOG/log.c +++ b/common/utils/LOG/log.c @@ -604,12 +604,13 @@ static inline int log_header(log_component_t *c, return snprintf(log_buffer, buffsize, - "%s%s%s%-8s%s%s%s", + "%s%s%s%-8s%s%-*s%s", flag & FLAG_NOCOLOR ? "" : log_level_highlight_start[level], timeString, threadIdString, c->headerName, g_log->level2string[level], // will print space if no level selected + l[0] == 0 ? 0 : 32, l, threadname); } From f4ff6c756c392d202d86b06897d689b73245d9a7 Mon Sep 17 00:00:00 2001 From: francescomani Date: Sat, 8 Nov 2025 14:41:42 +0100 Subject: [PATCH 55/80] add a check for rlc-Config presence (even if it should be mandatory at setup) --- openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 2 +- openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c | 5 ++--- openair2/RRC/NR_UE/rrc_UE.c | 9 +++++++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 064857a8e3..ce59a31226 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -329,7 +329,7 @@ static int handle_ue_context_drbs_setup(NR_UE_info_t *UE, *rlc_BearerConfig->rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = NR_SN_FieldLengthAM_size12; *rlc_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = NR_SN_FieldLengthAM_size12; } - + AssertFatal(rlc_BearerConfig->rlc_Config, "We expect rlc-Config to be always present when we configure a DRB\n"); nr_rlc_add_drb(UE->rnti, drb->id, rlc_BearerConfig); nr_lc_config_t c = {.lcid = rlc_BearerConfig->logicalChannelIdentity, .nssai = drb->nr.nssai}; diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c index e187541fd5..126f9fb51c 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c @@ -672,7 +672,7 @@ void nr_rlc_reconfigure_entity(int ue_id, int lc_id, NR_RLC_Config_t *rlc_Config void nr_rlc_add_srb(int ue_id, int srb_id, const NR_RLC_BearerConfig_t *rlc_BearerConfig) { - struct NR_RLC_Config *r = rlc_BearerConfig->rlc_Config; + NR_RLC_Config_t *r = rlc_BearerConfig->rlc_Config; int t_status_prohibit; int t_poll_retransmit; int poll_pdu; @@ -682,8 +682,7 @@ void nr_rlc_add_srb(int ue_id, int srb_id, const NR_RLC_BearerConfig_t *rlc_Bear int sn_field_length; LOG_D(RLC, "Trying to add SRB %d\n", srb_id); - AssertFatal(srb_id > 0 && srb_id < 4, - "Invalid srb id %d\n", srb_id); + AssertFatal(srb_id > 0 && srb_id < 4, "Invalid srb id %d\n", srb_id); if (r && r->present == NR_RLC_Config_PR_am) { struct NR_RLC_Config__am *am; diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 9086ad25eb..4bb0e8bdb3 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -1684,8 +1684,13 @@ static void nr_rrc_manage_rlc_bearers(NR_UE_RRC_INST_t *rrc, const NR_CellGroupC nr_rlc_set_rlf_handler(rrc->ue_id, nr_rrc_signal_maxrtxindication); } else { // DRB NR_DRB_Identity_t drb_id = rlc_bearer->servedRadioBearer->choice.drb_Identity; - nr_rlc_add_drb(rrc->ue_id, drb_id, rlc_bearer); - nr_rlc_set_rlf_handler(rrc->ue_id, nr_rrc_signal_maxrtxindication); + if (!rlc_bearer->rlc_Config) { + LOG_E(RLC, "RLC-Config not present but is mandatory for setup\n"); + rrc->active_RLC_entity[lcid] = false; + } else { + nr_rlc_add_drb(rrc->ue_id, drb_id, rlc_bearer); + nr_rlc_set_rlf_handler(rrc->ue_id, nr_rrc_signal_maxrtxindication); + } } } } From 566da5317fad6d2c2c3d9877f87ae07ffa084cf4 Mon Sep 17 00:00:00 2001 From: francescomani Date: Sat, 8 Nov 2025 14:48:31 +0100 Subject: [PATCH 56/80] add a check for cell ID presence in handling reconfigurationWithSync --- openair2/RRC/NR_UE/rrc_UE.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 4bb0e8bdb3..818bb26be3 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -1718,7 +1718,10 @@ static void nr_rrc_process_reconfigurationWithSync(NR_UE_RRC_INST_t *rrc, rrc->arfcn_ssb = *dcc->frequencyInfoDL->absoluteFrequencySSB; // consider the target SpCell to be one with a physical cell identity indicated by the physCellId - rrc->phyCellID = *reconfigurationWithSync->spCellConfigCommon->physCellId; + if (!reconfigurationWithSync->spCellConfigCommon->physCellId) + LOG_E(NR_RRC, "physCellId absent but should be mandatory present upon cell change and cell addition\n"); + else + rrc->phyCellID = *reconfigurationWithSync->spCellConfigCommon->physCellId; } NR_UE_Timers_Constants_t *tac = &rrc->timers_and_constants; From 88baba8948cc2b9b7f3c8ccc8d9f93c3d7922013 Mon Sep 17 00:00:00 2001 From: francescomani Date: Sat, 8 Nov 2025 14:52:53 +0100 Subject: [PATCH 57/80] do not handle not decoded cellGroupConfig (issue #1031) --- openair2/RRC/NR_UE/rrc_UE.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 818bb26be3..a1b8616c60 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -1161,20 +1161,19 @@ static void nr_rrc_ue_process_rrcReconfiguration(NR_UE_RRC_INST_t *rrc, int gNB_ LOG_E(NR_RRC, "\n"); // free the memory SEQUENCE_free(&asn_DEF_NR_CellGroupConfig, (void *)cellGroupConfig, 1); + } else { + if (LOG_DEBUGFLAG(DEBUG_ASN1)) + xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *) cellGroupConfig); + + nr_rrc_cellgroup_configuration(rrc, cellGroupConfig, gNB_index); + AssertFatal(!IS_SA_MODE(get_softmodem_params()), "secondaryCellGroup only used in NSA for now\n"); + nr_mac_rrc_message_t rrc_msg = {0}; + rrc_msg.payload_type = NR_MAC_RRC_CONFIG_CG; + nr_mac_rrc_config_cg_t *config_cg = &rrc_msg.payload.config_cg; + config_cg->cellGroupConfig = cellGroupConfig; + config_cg->UE_NR_Capability = rrc->UECap.UE_NR_Capability; + nr_rrc_send_msg_to_mac(rrc, &rrc_msg); } - - if (LOG_DEBUGFLAG(DEBUG_ASN1)) - xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *) cellGroupConfig); - - nr_rrc_cellgroup_configuration(rrc, cellGroupConfig, gNB_index); - - AssertFatal(!IS_SA_MODE(get_softmodem_params()), "secondaryCellGroup only used in NSA for now\n"); - nr_mac_rrc_message_t rrc_msg = {0}; - rrc_msg.payload_type = NR_MAC_RRC_CONFIG_CG; - nr_mac_rrc_config_cg_t *config_cg = &rrc_msg.payload.config_cg; - config_cg->cellGroupConfig = cellGroupConfig; - config_cg->UE_NR_Capability = rrc->UECap.UE_NR_Capability; - nr_rrc_send_msg_to_mac(rrc, &rrc_msg); } if (ie->measConfig) { LOG_I(NR_RRC, "RRCReconfiguration includes Measurement Configuration\n"); From 9c3c65f5c943575ada45e3b4809912678854e00b Mon Sep 17 00:00:00 2001 From: francescomani Date: Sat, 8 Nov 2025 15:00:38 +0100 Subject: [PATCH 58/80] check presence of optional nonCriticalExtension before handling (issue #1026) --- openair2/RRC/NR_UE/rrc_UE.c | 46 +++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index a1b8616c60..177ef621b3 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -826,28 +826,30 @@ static void nr_rrc_process_reconfiguration_v1530(NR_UE_RRC_INST_t *rrc, NR_RRCRe NR_RRCReconfiguration_v1540_IEs_t *rec_1540 = rec_1530->nonCriticalExtension; if (rec_1540) { NR_RRCReconfiguration_v1560_IEs_t *rec_1560 = rec_1540->nonCriticalExtension; - if (rec_1560->sk_Counter) { - // TODO perform AS security key update procedure as specified in 5.3.5.7 - LOG_E(NR_RRC, "RRCReconfiguration includes sk-Counter but this is not implemented yet\n"); - } - if (rec_1560->mrdc_SecondaryCellGroupConfig) { - // TODO perform handling of mrdc-SecondaryCellGroupConfig as specified in 5.3.5.3 - LOG_E(NR_RRC, "RRCReconfiguration includes mrdc-SecondaryCellGroupConfig but this is not handled yet\n"); - } - if (rec_1560->radioBearerConfig2) { - NR_RadioBearerConfig_t *RadioBearerConfig = NULL; - asn_dec_rval_t dec_rval = uper_decode(NULL, - &asn_DEF_NR_RadioBearerConfig, - (void **)&RadioBearerConfig, - (uint8_t *)rec_1560->radioBearerConfig2->buf, - rec_1560->radioBearerConfig2->size, - 0, - 0); - if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) { - LOG_E(NR_RRC, "radioBearerConfig2 decode error\n"); - SEQUENCE_free(&asn_DEF_NR_RadioBearerConfig, RadioBearerConfig, 1); - } else - nr_rrc_ue_process_RadioBearerConfig(rrc, RadioBearerConfig); + if (rec_1560) { + if (rec_1560->sk_Counter) { + // TODO perform AS security key update procedure as specified in 5.3.5.7 + LOG_E(NR_RRC, "RRCReconfiguration includes sk-Counter but this is not implemented yet\n"); + } + if (rec_1560->mrdc_SecondaryCellGroupConfig) { + // TODO perform handling of mrdc-SecondaryCellGroupConfig as specified in 5.3.5.3 + LOG_E(NR_RRC, "RRCReconfiguration includes mrdc-SecondaryCellGroupConfig but this is not handled yet\n"); + } + if (rec_1560->radioBearerConfig2) { + NR_RadioBearerConfig_t *RadioBearerConfig = NULL; + asn_dec_rval_t dec_rval = uper_decode(NULL, + &asn_DEF_NR_RadioBearerConfig, + (void **)&RadioBearerConfig, + (uint8_t *)rec_1560->radioBearerConfig2->buf, + rec_1560->radioBearerConfig2->size, + 0, + 0); + if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) { + LOG_E(NR_RRC, "radioBearerConfig2 decode error\n"); + SEQUENCE_free(&asn_DEF_NR_RadioBearerConfig, RadioBearerConfig, 1); + } else + nr_rrc_ue_process_RadioBearerConfig(rrc, RadioBearerConfig); + } } } } From 789564fa8eddc5da61abc3d3781938b56abf636e Mon Sep 17 00:00:00 2001 From: francescomani Date: Sat, 8 Nov 2025 15:09:58 +0100 Subject: [PATCH 59/80] add UE capability container for each element of request list (issue #1025) --- openair2/RRC/NR_UE/rrc_UE.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 177ef621b3..6b7688c19c 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -2247,13 +2247,7 @@ static void nr_rrc_ue_process_ueCapabilityEnquiry(NR_UE_RRC_INST_t *rrc, NR_UECa AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name, enc_rval.encoded); rrc->UECap.sdu_size = (enc_rval.encoded + 7) / 8; LOG_I(PHY, "[RRC]UE NR Capability encoded, %d bytes (%zd bits)\n", rrc->UECap.sdu_size, enc_rval.encoded + 7); - /* RAT Container */ - NR_UE_CapabilityRAT_Container_t *ue_CapabilityRAT_Container = CALLOC(1, sizeof(NR_UE_CapabilityRAT_Container_t)); - ue_CapabilityRAT_Container->rat_Type = NR_RAT_Type_nr; - OCTET_STRING_fromBuf(&ue_CapabilityRAT_Container->ue_CapabilityRAT_Container, (const char *)rrc->UECap.sdu, rrc->UECap.sdu_size); NR_UECapabilityEnquiry_IEs_t *ueCapabilityEnquiry_ie = UECapabilityEnquiry->criticalExtensions.choice.ueCapabilityEnquiry; - // ue_CapabilityRAT_Container.ueCapabilityRAT_Container.buf = UE_rrc_inst[ue_mod_idP].UECapability; - // ue_CapabilityRAT_Container.ueCapabilityRAT_Container.size = UE_rrc_inst[ue_mod_idP].UECapability_size; AssertFatal(UECapabilityEnquiry->criticalExtensions.present == NR_UECapabilityEnquiry__criticalExtensions_PR_ueCapabilityEnquiry, "UECapabilityEnquiry->criticalExtensions.present (%d) != UECapabilityEnquiry__criticalExtensions_PR_c1 (%d)\n", UECapabilityEnquiry->criticalExtensions.present,NR_UECapabilityEnquiry__criticalExtensions_PR_ueCapabilityEnquiry); @@ -2266,6 +2260,10 @@ static void nr_rrc_ue_process_ueCapabilityEnquiry(NR_UE_RRC_INST_t *rrc, NR_UECa for (int i = 0; i < ueCapabilityEnquiry_ie->ue_CapabilityRAT_RequestList.list.count; i++) { if (ueCapabilityEnquiry_ie->ue_CapabilityRAT_RequestList.list.array[i]->rat_Type == NR_RAT_Type_nr) { + /* RAT Container */ + NR_UE_CapabilityRAT_Container_t *ue_CapabilityRAT_Container = CALLOC(1, sizeof(NR_UE_CapabilityRAT_Container_t)); + ue_CapabilityRAT_Container->rat_Type = NR_RAT_Type_nr; + OCTET_STRING_fromBuf(&ue_CapabilityRAT_Container->ue_CapabilityRAT_Container, (const char *)rrc->UECap.sdu, rrc->UECap.sdu_size); asn1cSeqAdd(&UEcapList->list, ue_CapabilityRAT_Container); uint8_t buffer[500]; asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_UL_DCCH_Message, NULL, (void *)&ul_dcch_msg, buffer, 500); @@ -2279,8 +2277,7 @@ static void nr_rrc_ue_process_ueCapabilityEnquiry(NR_UE_RRC_INST_t *rrc, NR_UECa nr_pdcp_data_req_srb(rrc->ue_id, srb_id, 0, (enc_rval.encoded + 7) / 8, buffer, deliver_pdu_srb_rlc, NULL); } } - /* Free struct members after it's done - including locally allocated ue_CapabilityRAT_Container */ + /* Free struct members after it's done including locally allocated ue_CapabilityRAT_Container */ ASN_STRUCT_RESET(asn_DEF_NR_UL_DCCH_Message, &ul_dcch_msg); } From 8620f33a58a9883b5159c81d7a0141988328213f Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 14 Nov 2025 12:33:14 +0100 Subject: [PATCH 60/80] Provide public helper functions to create NR_RLC_Config from nr_rlc_configuration_t --- openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c | 43 +++++++++++--------- openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h | 3 ++ 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c index 99bf846d4d..dff2f2b663 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c +++ b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c @@ -3538,6 +3538,24 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, return SpCellConfig; } +struct NR_RLC_Config *nr_srb_config(const nr_rlc_configuration_t *default_rlc_config) +{ + NR_RLC_Config_t *rlc_Config = calloc(1, sizeof(NR_RLC_Config_t)); + rlc_Config->present = NR_RLC_Config_PR_am; + rlc_Config->choice.am = calloc(1, sizeof(*rlc_Config->choice.am)); + rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t)); + *(rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength) = encode_sn_field_length_am(default_rlc_config->srb.sn_field_length); + rlc_Config->choice.am->dl_AM_RLC.t_Reassembly = encode_t_reassembly(default_rlc_config->srb.t_reassembly); + rlc_Config->choice.am->dl_AM_RLC.t_StatusProhibit = encode_t_status_prohibit(default_rlc_config->srb.t_status_prohibit); + rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t)); + *(rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength) = encode_sn_field_length_am(default_rlc_config->srb.sn_field_length); + rlc_Config->choice.am->ul_AM_RLC.t_PollRetransmit = encode_t_poll_retransmit(default_rlc_config->srb.t_poll_retransmit); + rlc_Config->choice.am->ul_AM_RLC.pollPDU = encode_poll_pdu(default_rlc_config->srb.poll_pdu); + rlc_Config->choice.am->ul_AM_RLC.pollByte = encode_poll_byte(default_rlc_config->srb.poll_byte); + rlc_Config->choice.am->ul_AM_RLC.maxRetxThreshold = encode_max_retx_threshold(default_rlc_config->srb.max_retx_threshold); + return rlc_Config; +} + NR_RLC_BearerConfig_t *get_SRB_RLC_BearerConfig(long channelId, long priority, long bucketSizeDuration, @@ -3551,20 +3569,7 @@ NR_RLC_BearerConfig_t *get_SRB_RLC_BearerConfig(long channelId, rlc_BearerConfig->servedRadioBearer->choice.srb_Identity = channelId; rlc_BearerConfig->reestablishRLC = NULL; - NR_RLC_Config_t *rlc_Config = calloc(1, sizeof(NR_RLC_Config_t)); - rlc_Config->present = NR_RLC_Config_PR_am; - rlc_Config->choice.am = calloc(1, sizeof(*rlc_Config->choice.am)); - rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t)); - *(rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength) = encode_sn_field_length_am(default_rlc_config->srb.sn_field_length); - rlc_Config->choice.am->dl_AM_RLC.t_Reassembly = encode_t_reassembly(default_rlc_config->srb.t_reassembly); - rlc_Config->choice.am->dl_AM_RLC.t_StatusProhibit = encode_t_status_prohibit(default_rlc_config->srb.t_status_prohibit); - rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t)); - *(rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength) = encode_sn_field_length_am(default_rlc_config->srb.sn_field_length); - rlc_Config->choice.am->ul_AM_RLC.t_PollRetransmit = encode_t_poll_retransmit(default_rlc_config->srb.t_poll_retransmit); - rlc_Config->choice.am->ul_AM_RLC.pollPDU = encode_poll_pdu(default_rlc_config->srb.poll_pdu); - rlc_Config->choice.am->ul_AM_RLC.pollByte = encode_poll_byte(default_rlc_config->srb.poll_byte); - rlc_Config->choice.am->ul_AM_RLC.maxRetxThreshold = encode_max_retx_threshold(default_rlc_config->srb.max_retx_threshold); - rlc_BearerConfig->rlc_Config = rlc_Config; + rlc_BearerConfig->rlc_Config = nr_srb_config(default_rlc_config); NR_LogicalChannelConfig_t *logicalChannelConfig = calloc(1, sizeof(NR_LogicalChannelConfig_t)); logicalChannelConfig->ul_SpecificParameters = calloc(1, sizeof(*logicalChannelConfig->ul_SpecificParameters)); @@ -3584,10 +3589,9 @@ NR_RLC_BearerConfig_t *get_SRB_RLC_BearerConfig(long channelId, return rlc_BearerConfig; } -static void nr_drb_config(struct NR_RLC_Config *rlc_Config, - NR_RLC_Config_PR rlc_config_pr, - const nr_rlc_configuration_t *default_rlc_config) +struct NR_RLC_Config *nr_drb_config(NR_RLC_Config_PR rlc_config_pr, const nr_rlc_configuration_t *default_rlc_config) { + NR_RLC_Config_t *rlc_Config = calloc(1, sizeof(NR_RLC_Config_t)); switch (rlc_config_pr) { case NR_RLC_Config_PR_um_Bi_Directional: // RLC UM Bi-directional Bearer configuration @@ -3620,6 +3624,7 @@ static void nr_drb_config(struct NR_RLC_Config *rlc_Config, break; } rlc_Config->present = rlc_config_pr; + return rlc_Config; } NR_RLC_BearerConfig_t *get_DRB_RLC_BearerConfig(long lcChannelId, @@ -3635,9 +3640,7 @@ NR_RLC_BearerConfig_t *get_DRB_RLC_BearerConfig(long lcChannelId, rlc_BearerConfig->servedRadioBearer->choice.drb_Identity = drbId; rlc_BearerConfig->reestablishRLC = NULL; - NR_RLC_Config_t *rlc_Config = calloc(1, sizeof(NR_RLC_Config_t)); - nr_drb_config(rlc_Config, rlc_conf, default_rlc_config); - rlc_BearerConfig->rlc_Config = rlc_Config; + rlc_BearerConfig->rlc_Config = nr_drb_config(rlc_conf, default_rlc_config); NR_LogicalChannelConfig_t *logicalChannelConfig = calloc(1, sizeof(NR_LogicalChannelConfig_t)); logicalChannelConfig->ul_SpecificParameters = calloc(1, sizeof(*logicalChannelConfig->ul_SpecificParameters)); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h index 89ce03e7f5..466f18c0de 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h @@ -112,6 +112,9 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC NR_ReconfigurationWithSync_t *get_reconfiguration_with_sync(rnti_t rnti, uid_t uid, const NR_ServingCellConfigCommon_t *scc, int frame); +struct NR_RLC_Config *nr_srb_config(const nr_rlc_configuration_t *default_rlc_config); +struct NR_RLC_Config *nr_drb_config(NR_RLC_Config_PR rlc_config_pr, const nr_rlc_configuration_t *default_rlc_config); + NR_RLC_BearerConfig_t *get_SRB_RLC_BearerConfig(long channelId, long priority, long bucketSizeDuration, From eb7ca9663cd87a7e68bfcdcf8a032fae244ec9d9 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 14 Nov 2025 12:45:37 +0100 Subject: [PATCH 61/80] gNB: modify RLC configuration applied for SRB1 during RRCReestablishment TS 38.331 clause 5.3.7.4 specifies to apply the configuration defined in 9.2.1 for SRB1 at UE side. This implies that the gNB also has to apply sn_field_length = 12, but there are no implications on the other RLC parameters. As wrong timer values break SRB1 e.g. for long RTT NTN scenarios, this commit switches to using the RLC timer values provided in the configuration file. Currently we still set poll_pdu, poll_byte and max_retx_threshold to the values defined in 9.2.1, but this can be changed. --- openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 064857a8e3..d353ab9e3f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -980,8 +980,15 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc) pthread_mutex_unlock(&mac->sched_lock); nr_rlc_remove_ue(dl_rrc->gNB_DU_ue_id); nr_rlc_update_id(*dl_rrc->old_gNB_DU_ue_id, dl_rrc->gNB_DU_ue_id); - /* 38.331 clause 5.3.7.4: apply the specified configuration defined in 9.2.1 for SRB1 */ - nr_rlc_reconfigure_entity(dl_rrc->gNB_DU_ue_id, 1, NULL); + /* 38.331 clause 5.3.7.4: apply gNB RLC configuration for SRB1 to match the UE RLC configuration defined in 9.2.1 */ + nr_rlc_configuration_t rlc_configuration = mac->rlc_config; // use configuration file values for timers t_poll_retransmit, t_reassembly and t_status_prohibit + rlc_configuration.srb.poll_pdu = -1; + rlc_configuration.srb.poll_byte = -1; + rlc_configuration.srb.max_retx_threshold = 8; + rlc_configuration.srb.sn_field_length = 12; + NR_RLC_Config_t *rlc_Config = nr_srb_config(&rlc_configuration); + nr_rlc_reconfigure_entity(dl_rrc->gNB_DU_ue_id, 1, rlc_Config); + ASN_STRUCT_FREE(asn_DEF_NR_RLC_Config, rlc_Config); instance_t f1inst = get_f1_gtp_instance(); if (f1inst >= 0) // we actually use F1-U gtpv1u_update_ue_id(f1inst, *dl_rrc->old_gNB_DU_ue_id, dl_rrc->gNB_DU_ue_id); From e17c165c9d17dd4c9a2d82b1e0a998b8df51566d Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 5 Nov 2025 22:44:48 +0100 Subject: [PATCH 62/80] Move DLSCH/PDSCH variables to gNB The next commit will remove msgDataTx. We can therefore not use msgDataTx to retain the PDSCH/DLSCH variables, and move them to the gNB. Note that the only reason for NR_gNB_DLSCH_t after this commit is to hold various large buffers (c, b, f). Future work could be done to remove this, in which case the array inside PHY_VARS_gNB could be deleted. On this occasion, clean up the use of init_DLSCH_struct() and reset_DLSCH_struct() (renamed destroy_DLSCH_struct()) and centralize their call in phy_init_nr_gNB()/phy_free_nr_gNB(), and correct simulators accordingly. --- executables/nr-gnb.c | 1 - openair1/PHY/INIT/nr_init.c | 21 +++++++++++++-------- openair1/PHY/INIT/nr_phy_init.h | 3 --- openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c | 4 ++-- openair1/PHY/defs_gNB.h | 3 ++- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 2 +- openair1/SIMULATION/NR_PHY/dlschsim.c | 8 +++----- openair1/SIMULATION/NR_PHY/dlsim.c | 4 ++-- 8 files changed, 23 insertions(+), 23 deletions(-) diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index c4ad405655..7c52d67c97 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -361,7 +361,6 @@ void init_gNB_Tpool(int inst) notifiedFIFO_elt_t *msgL1Tx = newNotifiedFIFO_elt(sizeof(processingData_L1tx_t), 0, &gNB->L1_tx_out, NULL); processingData_L1tx_t *msgDataTx = (processingData_L1tx_t *)NotifiedFifoData(msgL1Tx); memset(msgDataTx, 0, sizeof(processingData_L1tx_t)); - init_DLSCH_struct(gNB, msgDataTx); // this will be removed when the msgDataTx is not necessary anymore gNB->msgDataTx = msgDataTx; diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index e87a1d13db..f744b441ab 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -44,6 +44,9 @@ #include #include "nfapi/open-nFAPI/fapi/inc/nr_fapi_p5_utils.h" +static void init_DLSCH_struct(PHY_VARS_gNB *gNB); +static void destroy_DLSCH_struct(const PHY_VARS_gNB *gNB); + int l1_north_init_gNB() { AssertFatal(RC.nb_nr_L1_inst > 0, "Failed to init PHY callbacks: nb_nr_L1_inst = %d\n", RC.nb_nr_L1_inst); @@ -155,6 +158,8 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB) /// Transport init necessary for NR synchro init_nr_transport(gNB); + init_DLSCH_struct(gNB); + gNB->nr_srs_info = (nr_srs_info_t **)malloc16_clear(gNB->max_nb_srs * sizeof(nr_srs_info_t*)); for (int id = 0; id < gNB->max_nb_srs; id++) { gNB->nr_srs_info[id] = (nr_srs_info_t *)malloc16_clear(sizeof(nr_srs_info_t)); @@ -241,6 +246,8 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB) reset_nr_transport(gNB); + destroy_DLSCH_struct(gNB); + NR_gNB_COMMON * common_vars = &gNB->common_vars; for (int j = 0; j < common_vars->num_beams_period; j++) { if (common_vars->beam_id) @@ -401,29 +408,27 @@ void nr_phy_config_request(NR_PHY_Config_t *phy_config) init_timeshift_rotation(fp); } -void init_DLSCH_struct(PHY_VARS_gNB *gNB, processingData_L1tx_t *msg) +static void init_DLSCH_struct(PHY_VARS_gNB *gNB) { NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config; uint16_t grid_size = cfg->carrier_config.dl_grid_size[fp->numerology_index].value; - msg->num_pdsch_slot = 0; - - msg->dlsch = calloc(gNB->max_nb_pdsch, sizeof(*msg->dlsch)); + gNB->dlsch = calloc(gNB->max_nb_pdsch, sizeof(*gNB->dlsch)); for (int i = 0; i < gNB->max_nb_pdsch; i++) { LOG_D(PHY, "Allocating Transport Channel Buffers for DLSCH %d/%d\n", i, gNB->max_nb_pdsch); - msg->dlsch[i] = new_gNB_dlsch(fp, grid_size); + gNB->dlsch[i] = new_gNB_dlsch(fp, grid_size); } } -void reset_DLSCH_struct(const PHY_VARS_gNB *gNB, processingData_L1tx_t *msg) +static void destroy_DLSCH_struct(const PHY_VARS_gNB *gNB) { const NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; const nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config; const uint16_t grid_size = cfg->carrier_config.dl_grid_size[fp->numerology_index].value; for (int i = 0; i < gNB->max_nb_pdsch; i++) { - free_gNB_dlsch(&msg->dlsch[i], grid_size, fp); + free_gNB_dlsch(&gNB->dlsch[i], grid_size, fp); } - free(msg->dlsch); + free(gNB->dlsch); } void init_nr_transport(PHY_VARS_gNB *gNB) diff --git a/openair1/PHY/INIT/nr_phy_init.h b/openair1/PHY/INIT/nr_phy_init.h index 1b1a0fa1b0..f556498f0f 100644 --- a/openair1/PHY/INIT/nr_phy_init.h +++ b/openair1/PHY/INIT/nr_phy_init.h @@ -46,9 +46,6 @@ int l1_north_init_gNB(void); void init_nr_transport(PHY_VARS_gNB *gNB); void reset_nr_transport(PHY_VARS_gNB *gNB); -void init_DLSCH_struct(PHY_VARS_gNB *gNB, processingData_L1tx_t *msg); -void reset_DLSCH_struct(const PHY_VARS_gNB *gNB, processingData_L1tx_t *msg); - void RCconfig_nrUE_prs(void *cfg); void init_nr_prs_ue_vars(PHY_VARS_NR_UE *ue); void nr_init_dl_harq_processes(NR_DL_UE_HARQ_t harq_list[2][NR_MAX_DLSCH_HARQ_PROCESSES], int number_of_processes, int num_rb); diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c index 244ab5363b..bde85329e7 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c @@ -36,7 +36,7 @@ void nr_fill_dlsch_dl_tti_req(processingData_L1tx_t *msgTx, nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu) { - NR_gNB_DLSCH_t *dlsch = &msgTx->dlsch[msgTx->num_pdsch_slot]; + NR_gNB_DLSCH_t *dlsch = &msgTx->gNB->dlsch[msgTx->num_pdsch_slot]; /// DLSCH struct memcpy((void*)&dlsch->pdsch_pdu, (void*)pdsch_pdu, sizeof(nfapi_nr_dl_tti_pdsch_pdu)); AssertFatal(msgTx->num_pdsch_slot == pdsch_pdu->pdsch_pdu_rel15.pduIndex, @@ -53,7 +53,7 @@ void nr_fill_dlsch_tx_req(processingData_L1tx_t *msgTx, int idx, uint8_t *sdu) /* not sure if FAPI could transmit DL_TTI_req and TX_req in different orders. * for the moment, assume they are in the same order (and check!) */ - NR_gNB_DLSCH_t *dlsch = &msgTx->dlsch[idx]; + NR_gNB_DLSCH_t *dlsch = &msgTx->gNB->dlsch[idx]; nfapi_nr_dl_tti_pdsch_pdu *pdsch = &dlsch->pdsch_pdu; AssertFatal(pdsch->pdsch_pdu_rel15.pduIndex == idx, "PDSCH PDU index %d does not match %d\n", pdsch->pdsch_pdu_rel15.pduIndex, idx); dlsch->pdu = sdu; diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index af4f0d5707..0563d7580e 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -386,6 +386,8 @@ typedef struct PHY_VARS_gNB_s { NR_gNB_COMMON common_vars; prach_list_t prach_list; + // TODO: can we remove c from NR_gNB_DLSCH_t and put it on the stack? + NR_gNB_DLSCH_t *dlsch; NR_gNB_PRS prs_vars; NR_gNB_PUSCH *pusch_vars; NR_gNB_PUCCH_t *pucch; @@ -580,7 +582,6 @@ typedef struct processingData_L1tx { /// corresponds to UL_dci_req->ul_dci_pdu_list nfapi_nr_dl_tti_pdcch_pdu ul_pdcch_pdu[NFAPI_NR_MAX_NB_CORESETS]; nfapi_nr_dl_tti_csi_rs_pdu csirs_pdu[NFAPI_NR_MAX_NB_CORESETS]; - NR_gNB_DLSCH_t *dlsch; nfapi_nr_dl_tti_ssb_pdu ssb_pdu[64]; int n_ssb_pdu; int n_csirs_pdu; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index f3f80e2ae4..3579da8642 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -312,7 +312,7 @@ void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx, if (msgTx->num_pdsch_slot > 0) { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DLSCH,1); LOG_D(PHY, "PDSCH generation started (%d) in frame %d.%d\n", msgTx->num_pdsch_slot,frame,slot); - nr_generate_pdsch(gNB, msgTx->num_pdsch_slot, msgTx->dlsch, frame, slot); + nr_generate_pdsch(gNB, msgTx->num_pdsch_slot, gNB->dlsch, frame, slot); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DLSCH,0); } msgTx->num_pdsch_slot = 0; diff --git a/openair1/SIMULATION/NR_PHY/dlschsim.c b/openair1/SIMULATION/NR_PHY/dlschsim.c index 0dbc230f09..46cda67a6f 100644 --- a/openair1/SIMULATION/NR_PHY/dlschsim.c +++ b/openair1/SIMULATION/NR_PHY/dlschsim.c @@ -439,9 +439,9 @@ int main(int argc, char **argv) nr_init_dl_harq_processes(UE->dl_harq_processes, 8, nb_rb); unsigned char harq_pid = 0; //dlsch->harq_ids[subframe]; - processingData_L1tx_t msgDataTx; - init_DLSCH_struct(gNB, &msgDataTx); - NR_gNB_DLSCH_t *dlsch = &msgDataTx.dlsch[0]; + processingData_L1tx_t msgDataTx = {0}; + msgDataTx.gNB = gNB; + NR_gNB_DLSCH_t *dlsch = &msgDataTx.gNB->dlsch[0]; nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu.pdsch_pdu_rel15; //time_stats_t *rm_stats, *te_stats, *i_stats; unsigned int TBS = 8424; @@ -621,8 +621,6 @@ int main(int argc, char **argv) free_channel_desc_scm(gNB2UE); - reset_DLSCH_struct(gNB, &msgDataTx); - int nb_slots_to_set = (1 << mu) * NR_NUMBER_OF_SUBFRAMES_PER_FRAME; for (int i = 0; i < nb_slots_to_set; ++i) free(gNB->gNB_config.tdd_table.max_tdd_periodicity_list[i].max_num_of_symbol_per_slot_list); diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index a4c4351764..33ff1b7587 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -976,9 +976,9 @@ int main(int argc, char **argv) initNotifiedFIFO(&gNB->L1_tx_out); // we create 2 threads for L1 tx processing processingData_L1tx_t *msgDataTx = malloc(sizeof(processingData_L1tx_t)); - init_DLSCH_struct(gNB, msgDataTx); msgDataTx->slot = slot; msgDataTx->frame = frame; + msgDataTx->gNB = gNB; gNB->msgDataTx = msgDataTx; // Buffers to store internal memory of slot process @@ -1058,7 +1058,7 @@ int main(int argc, char **argv) n_false_positive = 0; if (n_trials== 1) num_rounds = 1; - NR_gNB_DLSCH_t *gNB_dlsch = &msgDataTx->dlsch[0]; + NR_gNB_DLSCH_t *gNB_dlsch = &msgDataTx->gNB->dlsch[0]; nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &gNB_dlsch->pdsch_pdu.pdsch_pdu_rel15; for (trial = 0; trial < n_trials && !stop; trial++) { From 2bea71a80aa6128a0b75e008e279c5881c0bb3d6 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 14 Nov 2025 10:31:55 +0100 Subject: [PATCH 63/80] Avoid use of FAPI message buffers in msgDataTx Note: after this commit, monolithic works but nFAPI operation is broken and fixed in the next commit, to keep the changes small(er). All simulators work. This commit removes the use of msgDataTx's intermediate buffers for FAPI messages and the call of the "Schedule response". The latter incurs an additional copy of FAPI messages for the TX chain (for the RX chain, it is and will remain there) which we can avoid. Instead, it uses an NR_Sched_Rsp_t-typed variable sched_response to store the results of the scheduler when called from tx_func(). Thus, the scheduler remains unchanged (it gets a pointer to where to put FAPI messages), but we don't call nr_schedule_response() to then copy FAPI messages into the L1, but have them in a local variable sched_response. sched_response on on the data segment, as it is big and would overflow the stack; at the same time, this is ok because only one tx_func() runs at a time. Since we don't use allocate_sched_response() anymore, we don't need deref_sched_response(). clear_slot_beamid() is moved to tx_func(), as it was called in nr_schedule_response(). Since the "intermediate" NR_gNB_DLSCH_t structure groups both the DL_tti_pdsch and TX_data.req structures, a pointer has been created to point to pdsch_pdu. This affects a number of simulators, as they have to put some messages on the stack: - nr_dlschsim: put the corresponding variable on the stack - nr_pbchsim: a new array for the SSB PDUs has been introduced Further, these changes are now necessary: - nr_dlsim: there were variables "rel15" and "pdsch_pdu_rel15" that point to the same PDSCH PDU. At least "rel15" would not exist, as the corresponding pointer is now populated in phy_procedures_gNB_TX(), and we therefore refer to the single PDSCH PDU variable with "pdsch_pdu_rel15", but at the place where "rel15" used to be initialized. - nr_ulsim: use nr_save_ul_tti_req() to load PDUs into the RX chain instead of nr_schedule_response(), which does not exist anymore. --- executables/nr-gnb.c | 31 +++--- openair1/PHY/NR_TRANSPORT/nr_dlsch.c | 4 +- openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c | 4 +- openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c | 2 +- openair1/PHY/defs_gNB.h | 2 +- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 104 +++++++++++++------- openair1/SCHED_NR/sched_nr.h | 9 +- openair1/SIMULATION/NR_PHY/dlschsim.c | 38 +++---- openair1/SIMULATION/NR_PHY/dlsim.c | 70 ++++++------- openair1/SIMULATION/NR_PHY/pbchsim.c | 14 +-- openair1/SIMULATION/NR_PHY/ulsim.c | 12 +-- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c | 20 +--- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 8 +- openair2/NR_PHY_INTERFACE/NR_IF_Module.c | 80 ++++++++------- openair2/NR_PHY_INTERFACE/NR_IF_Module.h | 3 +- 15 files changed, 206 insertions(+), 195 deletions(-) diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 7c52d67c97..1485b6de1d 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -82,8 +82,6 @@ static void tx_func(processingData_L1tx_t *info) int slot_rx = info->slot_rx; LOG_D(NR_PHY, "%d.%d running tx_func\n", frame_tx, slot_tx); PHY_VARS_gNB *gNB = info->gNB; - module_id_t module_id = gNB->Mod_id; - uint8_t CC_id = gNB->CC_id; NR_IF_Module_t *ifi = gNB->if_inst; nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config; @@ -94,15 +92,22 @@ static void tx_func(processingData_L1tx_t *info) reset_active_ulsch(gNB, frame_rx); } + clear_slot_beamid(gNB, slot_tx); + + nfapi_nr_slot_indication_scf_t ind = {.sfn = frame_tx, .slot = slot_tx}; start_meas(&gNB->slot_indication_stats); - ifi->NR_slot_indication(module_id, CC_id, frame_tx, slot_tx); + // this variable is very big (multiple MB), so we put it into static storage + // to not overflow the stack while still having it in local (function) scope + // also, tx_func() is only executed by one thread, serially + static NR_Sched_Rsp_t sched_response; + ifi->NR_slot_indication(&ind, &sched_response); stop_meas(&gNB->slot_indication_stats); - gNB->msgDataTx->timestamp_tx = info->timestamp_tx; - info = gNB->msgDataTx; + info->gNB = gNB; // At this point, MAC scheduler just ran, including scheduling // PRACH/PUCCH/PUSCH, so trigger RX chain processing + nr_save_ul_tti_req(gNB, &sched_response.UL_tti_req); LOG_D(NR_PHY, "Trigger RX for %d.%d\n", frame_rx, slot_rx); notifiedFIFO_elt_t *res = newNotifiedFIFO_elt(sizeof(processingData_L1_t), 0, &gNB->resp_L1, NULL); processingData_L1_t *syncMsg = NotifiedFifoData(res); @@ -119,7 +124,13 @@ static void tx_func(processingData_L1tx_t *info) if (tx_slot_type == NR_DOWNLINK_SLOT || tx_slot_type == NR_MIXED_SLOT || get_softmodem_params()->continuous_tx || IS_SOFTMODEM_RFSIM || cfg->analog_beamforming_ve.analog_beam_list) { start_meas(&info->gNB->phy_proc_tx); - phy_procedures_gNB_TX(info, frame_tx, slot_tx, 1); + phy_procedures_gNB_TX(info->gNB, + &sched_response.DL_req, + &sched_response.TX_req, + &sched_response.UL_dci_req, + frame_tx, + slot_tx, + 1); PHY_VARS_gNB *gNB = info->gNB; processingData_RU_t syncMsgRU; @@ -131,14 +142,6 @@ static void tx_func(processingData_L1tx_t *info) ru_tx_func((void *)&syncMsgRU); stop_meas(&info->gNB->phy_proc_tx); } - - if (NFAPI_MODE == NFAPI_MONOLITHIC) { - /* this thread is done with the sched_info, decrease the reference counter. - * This only applies for monolithic; in the PNF, the memory is allocated in - * a ring buffer that should never be overwritten (one frame duration). */ - LOG_D(NR_PHY, "Calling deref_sched_response for id %d (tx_func) in %d.%d\n", info->sched_response_id, frame_tx, slot_tx); - deref_sched_response(info->sched_response_id); - } } void *L1_rx_thread(void *arg) diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index 7afbed41b4..8df7b4814c 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -555,7 +555,7 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC time_stats_t *dlsch_scrambling_stats = &gNB->dlsch_scrambling_stats; time_stats_t *dlsch_modulation_stats = &gNB->dlsch_modulation_stats; - const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu.pdsch_pdu_rel15; + const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu->pdsch_pdu_rel15; const int layerSz = frame_parms->N_RB_DL * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB; const int symbol_sz=frame_parms->ofdm_symbol_size; const int dmrs_Type = rel15->dmrsConfigType; @@ -789,7 +789,7 @@ void nr_generate_pdsch(PHY_VARS_gNB *gNB, int n_dlsch, NR_gNB_DLSCH_t *dlsch_arr for (int i = 0; i < n_dlsch; i++) { NR_gNB_DLSCH_t *dlsch = &dlsch_array[i]; - const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu.pdsch_pdu_rel15; + const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu->pdsch_pdu_rel15; LOG_D(PHY, "pdsch: BWPStart %d, BWPSize %d, rbStart %d, rbsize %d\n", diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c index 67f3dd4363..c1a4dd152d 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c @@ -138,7 +138,7 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, NR_gNB_DLSCH_t *dlsch = &dlsch_array[i]; unsigned int crc = 1; - const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu.pdsch_pdu_rel15; + const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu->pdsch_pdu_rel15; uint32_t A = rel15->TBSize[0] << 3; unsigned char *a = dlsch->pdu; if (rel15->rnti != SI_RNTI) { @@ -224,7 +224,7 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, for (int i = 0; i < n_dlsch; i++) { NR_gNB_DLSCH_t *dlsch = &dlsch_array[i]; - const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu.pdsch_pdu_rel15; + const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu->pdsch_pdu_rel15; nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[i]; diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c index bde85329e7..17766da629 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c @@ -54,7 +54,7 @@ void nr_fill_dlsch_tx_req(processingData_L1tx_t *msgTx, int idx, uint8_t *sdu) /* not sure if FAPI could transmit DL_TTI_req and TX_req in different orders. * for the moment, assume they are in the same order (and check!) */ NR_gNB_DLSCH_t *dlsch = &msgTx->gNB->dlsch[idx]; - nfapi_nr_dl_tti_pdsch_pdu *pdsch = &dlsch->pdsch_pdu; + const nfapi_nr_dl_tti_pdsch_pdu *pdsch = dlsch->pdsch_pdu; AssertFatal(pdsch->pdsch_pdu_rel15.pduIndex == idx, "PDSCH PDU index %d does not match %d\n", pdsch->pdsch_pdu_rel15.pduIndex, idx); dlsch->pdu = sdu; } diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 0563d7580e..fdaae94b49 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -98,7 +98,7 @@ typedef struct { typedef struct { /// Nfapi DLSCH PDU - nfapi_nr_dl_tti_pdsch_pdu pdsch_pdu; + const nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu; /// pointer to pdu from MAC interface (this is "a" in 36.212) uint8_t *pdu; /// Pointer to the payload diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 3579da8642..eb4f1c8e84 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -243,12 +243,14 @@ static void nr_generate_csi_rs_gNB(PHY_VARS_gNB *gNB, gNB->common_vars.txdataF[beam_nb]); } -void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx, +void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB, + const nfapi_nr_dl_tti_request_t *DL_req, + const nfapi_nr_tx_data_request_t *TX_req, + const nfapi_nr_ul_dci_request_t *UL_dci_req, int frame, int slot, int do_meas) { - PHY_VARS_gNB *gNB = msgTx->gNB; NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config; int slot_prs = 0; @@ -282,44 +284,41 @@ void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx, } } - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_COMMON_TX,1); - for (int i = 0; i < msgTx->n_ssb_pdu; i++) - nr_common_signal_procedures(gNB, frame, slot, &msgTx->ssb_pdu[i]); - msgTx->n_ssb_pdu = 0; + for (int i = 0; i < UL_dci_req->numPdus; ++i) + nr_generate_dci(gNB, &UL_dci_req->ul_dci_pdu_list[i].pdcch_pdu.pdcch_pdu_rel15, txdataF_offset, &gNB->frame_parms, slot); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_COMMON_TX,0); - - int num_pdcch_pdus = msgTx->num_ul_pdcch + msgTx->num_dl_pdcch; - - if (num_pdcch_pdus > 0) { - LOG_D(PHY, "[gNB %d] Frame %d slot %d Calling nr_generate_dci() (number of UL/DL PDCCH PDUs %d/%d)\n", - gNB->Mod_id, frame, slot, msgTx->num_ul_pdcch, msgTx->num_dl_pdcch); - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_gNB_PDCCH_TX,1); - - start_meas(&gNB->dci_generation_stats); - for (int i = 0; i < msgTx->num_dl_pdcch; ++i) - nr_generate_dci(gNB, &msgTx->pdcch_pdu[i].pdcch_pdu_rel15, txdataF_offset, &gNB->frame_parms, slot); - for (int i = 0; i < msgTx->num_ul_pdcch; ++i) - nr_generate_dci(gNB, &msgTx->ul_pdcch_pdu[i].pdcch_pdu_rel15, txdataF_offset, &gNB->frame_parms, slot); - stop_meas(&gNB->dci_generation_stats); - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_gNB_PDCCH_TX,0); + int num_pdsch = 0; + for (int i = 0; i < DL_req->dl_tti_request_body.nPDUs; ++i) { + const nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdu = &DL_req->dl_tti_request_body.dl_tti_pdu_list[i]; + switch (dl_tti_pdu->PDUType) { + case NFAPI_NR_DL_TTI_SSB_PDU_TYPE: + nr_common_signal_procedures(gNB, frame, slot, &dl_tti_pdu->ssb_pdu); + break; + case NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE: + nr_generate_dci(gNB, &dl_tti_pdu->pdcch_pdu.pdcch_pdu_rel15, txdataF_offset, &gNB->frame_parms, slot); + break; + case NFAPI_NR_DL_TTI_CSI_RS_PDU_TYPE: + nr_generate_csi_rs_gNB(gNB, slot, cfg, &dl_tti_pdu->csi_rs_pdu); + break; + case NFAPI_NR_DL_TTI_PDSCH_PDU_TYPE: { + int tx_data_idx = dl_tti_pdu->pdsch_pdu.pdsch_pdu_rel15.pduIndex; + DevAssert(tx_data_idx < TX_req->Number_of_PDUs); + // reuse dlsch variables, as there are multiple very large memory + // buffers + gNB->dlsch[num_pdsch].pdsch_pdu = &dl_tti_pdu->pdsch_pdu; + gNB->dlsch[num_pdsch].pdu = (uint8_t *)TX_req->pdu_list[tx_data_idx].TLVs[0].value.direct; + DevAssert(num_pdsch < gNB->max_nb_pdsch); + num_pdsch++; + } break; + } } - msgTx->num_dl_pdcch = 0; - msgTx->num_ul_pdcch = 0; - if (msgTx->num_pdsch_slot > 0) { + if (num_pdsch > 0) { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DLSCH,1); - LOG_D(PHY, "PDSCH generation started (%d) in frame %d.%d\n", msgTx->num_pdsch_slot,frame,slot); - nr_generate_pdsch(gNB, msgTx->num_pdsch_slot, gNB->dlsch, frame, slot); + LOG_D(PHY, "PDSCH generation started (%d) in frame %d.%d\n", num_pdsch, frame, slot); + nr_generate_pdsch(gNB, num_pdsch, gNB->dlsch, frame, slot); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DLSCH,0); } - msgTx->num_pdsch_slot = 0; - - for (int i = 0; i < msgTx->n_csirs_pdu; i++) - nr_generate_csi_rs_gNB(gNB, slot, cfg, &msgTx->csirs_pdu[i]); - msgTx->n_csirs_pdu = 0; //apply the OFDM symbol rotation here start_meas(&gNB->phase_comp_stats); @@ -1293,3 +1292,40 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_UESPEC_RX,0); return pusch_DTX; } + +void nr_save_ul_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_tti_request_t *UL_tti_req) +{ + DevAssert(gNB != NULL); + DevAssert(UL_tti_req != NULL); + + int frame = UL_tti_req->SFN; + int slot = UL_tti_req->Slot; + + for (int i = 0; i < UL_tti_req->n_pdus; i++) { + int type = UL_tti_req->pdus_list[i].pdu_type; + LOG_D(NR_PHY, + "frame %d, slot %d got %s for %d.%d\n", + frame, + slot, + txt_nfapi_nr_ul_config_pdu_type[type], + UL_tti_req->SFN, + UL_tti_req->Slot); + switch (type) { + case NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE: + nr_fill_ulsch(gNB, UL_tti_req->SFN, UL_tti_req->Slot, &UL_tti_req->pdus_list[i].pusch_pdu); + break; + case NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE: + nr_fill_pucch(gNB, UL_tti_req->SFN, UL_tti_req->Slot, &UL_tti_req->pdus_list[i].pucch_pdu); + break; + case NFAPI_NR_UL_CONFIG_PRACH_PDU_TYPE: { + nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[i].prach_pdu; + prach_item_t *prach = nr_schedule_rx_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu); + if (!prach) + LOG_W(NR_PHY_RACH, "Error in scheduling rach\n"); + } break; + case NFAPI_NR_UL_CONFIG_SRS_PDU_TYPE: + nr_fill_srs(gNB, UL_tti_req->SFN, UL_tti_req->Slot, &UL_tti_req->pdus_list[i].srs_pdu); + break; + } + } +} diff --git a/openair1/SCHED_NR/sched_nr.h b/openair1/SCHED_NR/sched_nr.h index aade6e766c..da71809589 100644 --- a/openair1/SCHED_NR/sched_nr.h +++ b/openair1/SCHED_NR/sched_nr.h @@ -33,7 +33,14 @@ #include "phy_frame_config_nr.h" void nr_set_ssb_first_subcarrier(nfapi_nr_config_request_scf_t *cfg, NR_DL_FRAME_PARMS *fp); -void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx, int frame_tx, int slot_tx, int do_meas); +void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB, + const nfapi_nr_dl_tti_request_t *DL_req, + const nfapi_nr_tx_data_request_t *TX_req, + const nfapi_nr_ul_dci_request_t *UL_dci_req, + int frame, + int slot, + int do_meas); +void nr_save_ul_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_tti_request_t *UL_tti_req); int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, NR_UL_IND_t *UL_INFO); void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rach_indication_t *rach_ind); void nr_common_signal_procedures (PHY_VARS_gNB *gNB,int frame,int slot, const nfapi_nr_dl_tti_ssb_pdu *ssb_pdu); diff --git a/openair1/SIMULATION/NR_PHY/dlschsim.c b/openair1/SIMULATION/NR_PHY/dlschsim.c index 46cda67a6f..ea4a068b6e 100644 --- a/openair1/SIMULATION/NR_PHY/dlschsim.c +++ b/openair1/SIMULATION/NR_PHY/dlschsim.c @@ -439,10 +439,7 @@ int main(int argc, char **argv) nr_init_dl_harq_processes(UE->dl_harq_processes, 8, nb_rb); unsigned char harq_pid = 0; //dlsch->harq_ids[subframe]; - processingData_L1tx_t msgDataTx = {0}; - msgDataTx.gNB = gNB; - NR_gNB_DLSCH_t *dlsch = &msgDataTx.gNB->dlsch[0]; - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu.pdsch_pdu_rel15; + NR_gNB_DLSCH_t *dlsch = &gNB->dlsch[0]; //time_stats_t *rm_stats, *te_stats, *i_stats; unsigned int TBS = 8424; uint8_t nb_re_dmrs = 6; // No data in dmrs symbol @@ -459,19 +456,24 @@ int main(int argc, char **argv) TBS = nr_compute_tbs(mod_order,rate, nb_rb, nb_symb_sch, nb_re_dmrs*length_dmrs, 0, 0, Nl); printf("available bits %u TBS %u mod_order %d\n", available_bits, TBS, mod_order); //dlsch->harq_ids[subframe]= 0; - rel15->rbSize = nb_rb; - rel15->NrOfSymbols = nb_symb_sch; - rel15->qamModOrder[0] = mod_order; - rel15->nrOfLayers = Nl; - rel15->TBSize[0] = TBS>>3; - rel15->targetCodeRate[0] = rate; - rel15->NrOfCodewords = 1; - rel15->dmrsConfigType = NFAPI_NR_DMRS_TYPE1; - rel15->dlDmrsSymbPos = 4; - rel15->mcsIndex[0] = Imcs; - rel15->numDmrsCdmGrpsNoData = 1; - rel15->maintenance_parms_v3.tbSizeLbrmBytes = Tbslbrm; - rel15->maintenance_parms_v3.ldpcBaseGraph = get_BG(TBS, rate); + nfapi_nr_dl_tti_pdsch_pdu pdsch_pdu = { + .pdsch_pdu_rel15 = { + .rbSize = nb_rb, + .NrOfSymbols = nb_symb_sch, + .qamModOrder[0] = mod_order, + .nrOfLayers = Nl, + .TBSize[0] = TBS >> 3, + .targetCodeRate[0] = rate, + .NrOfCodewords = 1, + .dmrsConfigType = NFAPI_NR_DMRS_TYPE1, + .dlDmrsSymbPos = 4, + .mcsIndex[0] = Imcs, + .numDmrsCdmGrpsNoData = 1, + .maintenance_parms_v3.tbSizeLbrmBytes = Tbslbrm, + .maintenance_parms_v3.ldpcBaseGraph = get_BG(TBS, rate), + }, + }; + dlsch->pdsch_pdu = &pdsch_pdu; double modulated_input[16 * 68 * 384]; // [hna] 16 segments, 68*Zc short channel_output_fixed[16 * 68 * 384]; //unsigned char *estimated_output; @@ -512,7 +514,7 @@ int main(int argc, char **argv) //printf("crc32: [0]->0x%08x\n",crc24c(test_input, 32)); // generate signal - unsigned char output[rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * NR_MAX_NB_LAYERS] __attribute__((aligned(64))); + unsigned char output[nb_rb * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * NR_MAX_NB_LAYERS] __attribute__((aligned(64))); bzero(output, sizeof(output)); if (input_fd == NULL) { nr_dlsch_encoding(gNB, 1, dlsch, frame, slot, frame_parms, output, NULL, NULL, NULL, NULL, NULL, NULL, NULL); diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 33ff1b7587..82984657d3 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -62,7 +62,6 @@ #include "PHY/defs_nr_common.h" #include "PHY/impl_defs_nr.h" #include "PHY/phy_vars_nr_ue.h" -#include "SCHED_NR/fapi_nr_l1.h" #include "SCHED_NR/sched_nr.h" #include "SCHED_NR_UE/defs.h" #include "SCHED_NR_UE/fapi_nr_ue_l1.h" @@ -286,7 +285,6 @@ nrUE_params_t *get_nrUE_params(void) { return &nrUE_params; } - void validate_input_pmi(nfapi_nr_config_request_scf_t *gNB_config, nr_pdsch_AntennaPorts_t pdsch_AntennaPorts, int nrOfLayers, @@ -974,12 +972,6 @@ int main(int argc, char **argv) int ret = 1; initNamedTpool(gNBthreads, &gNB->threadPool, true, "gNB-tpool"); initNotifiedFIFO(&gNB->L1_tx_out); - // we create 2 threads for L1 tx processing - processingData_L1tx_t *msgDataTx = malloc(sizeof(processingData_L1tx_t)); - msgDataTx->slot = slot; - msgDataTx->frame = frame; - msgDataTx->gNB = gNB; - gNB->msgDataTx = msgDataTx; // Buffers to store internal memory of slot process int rx_size = (((14 * UE->frame_parms.N_RB_DL * 12 * sizeof(int32_t)) + 15) >> 4) << 4; @@ -1058,8 +1050,13 @@ int main(int argc, char **argv) n_false_positive = 0; if (n_trials== 1) num_rounds = 1; - NR_gNB_DLSCH_t *gNB_dlsch = &msgDataTx->gNB->dlsch[0]; - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &gNB_dlsch->pdsch_pdu.pdsch_pdu_rel15; + NR_gNB_DLSCH_t *gNB_dlsch = &gNB->dlsch[0]; + memset(Sched_INFO, 0, sizeof(*Sched_INFO)); + Sched_INFO->sched_response_id = -1; + nfapi_nr_dl_tti_request_body_t *dl_req = &Sched_INFO->DL_req.dl_tti_request_body; + // scheduler will place PDSCH second (after PDCCH), verification below + nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu = &dl_req->dl_tti_pdu_list[1]; + nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu_rel15 = &dl_tti_pdsch_pdu->pdsch_pdu.pdsch_pdu_rel15; for (trial = 0; trial < n_trials && !stop; trial++) { @@ -1081,11 +1078,9 @@ int main(int argc, char **argv) UE_harq_process->DLround = round; UE_harq_process->first_rx = 1; - memset(Sched_INFO, 0, sizeof(*Sched_INFO)); - Sched_INFO->sched_response_id = -1; - while (round < num_rounds && !UE_harq_process->decodeResult && !stop) { - clear_nr_nfapi_information(RC.nrmac[0], 0, frame, slot, &Sched_INFO->DL_req, &Sched_INFO->TX_req, &Sched_INFO->UL_dci_req); + reset_sched_response(Sched_INFO, frame, slot, 0, 0); + clear_nr_nfapi_information(RC.nrmac[0], 0, frame, slot); UE_info->UE_sched_ctrl.harq_processes[harq_pid].ndi = !(trial&1); UE_info->UE_sched_ctrl.harq_processes[harq_pid].round = round; @@ -1093,18 +1088,13 @@ int main(int argc, char **argv) NR_SCHED_LOCK(&gNB_mac->sched_lock); nr_schedule_ue_spec(0, frame, slot, &Sched_INFO->DL_req, &Sched_INFO->TX_req); NR_SCHED_UNLOCK(&gNB_mac->sched_lock); - Sched_INFO->module_id = 0; - Sched_INFO->CC_id = 0; - Sched_INFO->frame = frame; - Sched_INFO->slot = slot; - Sched_INFO->UL_dci_req.numPdus = 0; - nr_schedule_response(Sched_INFO); + + /* check that second message is indeed PDSCH */ + DevAssert(dl_tti_pdsch_pdu->PDUType == NFAPI_NR_DL_TTI_PDSCH_PDU_TYPE); /* PTRS values for DLSIM calculations */ - nfapi_nr_dl_tti_request_body_t *dl_req = &Sched_INFO->DL_req.dl_tti_request_body; - nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu = &dl_req->dl_tti_pdu_list[1]; - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu_rel15 = &dl_tti_pdsch_pdu->pdsch_pdu.pdsch_pdu_rel15; pdu_bit_map = pdsch_pdu_rel15->pduBitmap; + // This is already in DL procedures?? if(pdu_bit_map & 0x1) { set_ptrs_symb_idx(&dlPtrsSymPos, pdsch_pdu_rel15->NrOfSymbols, @@ -1112,16 +1102,12 @@ int main(int argc, char **argv) 1<PTRSTimeDensity, pdsch_pdu_rel15->dlDmrsSymbPos); ptrsSymbPerSlot = get_ptrs_symbols_in_slot(dlPtrsSymPos, pdsch_pdu_rel15->StartSymbolIndex, pdsch_pdu_rel15->NrOfSymbols); - ptrsRePerSymb = ((rel15->rbSize + rel15->PTRSFreqDensity - 1) / rel15->PTRSFreqDensity); + ptrsRePerSymb = ((pdsch_pdu_rel15->rbSize + pdsch_pdu_rel15->PTRSFreqDensity - 1) / pdsch_pdu_rel15->PTRSFreqDensity); LOG_D(PHY,"[DLSIM] PTRS Symbols in a slot: %2u, RE per Symbol: %3u, RE in a slot %4d\n", ptrsSymbPerSlot, ptrsRePerSymb, ptrsSymbPerSlot * ptrsRePerSymb); } - msgDataTx->ssb_pdu[0].ssb_pdu_rel15.bchPayload = 0x001234; - msgDataTx->ssb_pdu[0].ssb_pdu_rel15.SsbBlockIndex = 0; - msgDataTx->gNB = gNB; - start_meas(&gNB->phy_proc_tx); - phy_procedures_gNB_TX(msgDataTx,frame,slot,1); + phy_procedures_gNB_TX(gNB, &Sched_INFO->DL_req, &Sched_INFO->TX_req, &Sched_INFO->UL_dci_req, frame, slot, 1); stop_meas(&gNB->phy_proc_tx); int txdataF_offset = slot * frame_parms->samples_per_slot_wCP; @@ -1196,9 +1182,9 @@ int main(int argc, char **argv) double ts = 1.0/(frame_parms->subcarrier_spacing * frame_parms->ofdm_symbol_size); //Compute AWGN variance - sigma2_dB = 10 * log10((double)txlev_sum * ((double)UE->frame_parms.ofdm_symbol_size/(12*rel15->rbSize))) - SNR; + sigma2_dB = 10 * log10((double)txlev_sum * ((double)UE->frame_parms.ofdm_symbol_size/(12*pdsch_pdu_rel15->rbSize))) - SNR; sigma2 = pow(10, sigma2_dB/10); - if (n_trials==1) printf("sigma2 %f (%f dB), txlev_sum %f (factor %f)\n",sigma2,sigma2_dB,10*log10((double)txlev_sum),(double)(double)UE->frame_parms.ofdm_symbol_size/(12*rel15->rbSize)); + if (n_trials==1) printf("sigma2 %f (%f dB), txlev_sum %f (factor %f)\n",sigma2,sigma2_dB,10*log10((double)txlev_sum),(double)(double)UE->frame_parms.ofdm_symbol_size/(12*pdsch_pdu_rel15->rbSize)); for (aa = 0; aa < n_rx; aa++) { bzero(r_re[aa], slot_length * sizeof(double)); @@ -1240,17 +1226,17 @@ int main(int argc, char **argv) int16_t *UE_llr = (int16_t*)UE->phy_sim_pdsch_llr; - TBS = dlsch0->dlsch_config.TBS;//rel15->TBSize[0]; + TBS = dlsch0->dlsch_config.TBS; uint16_t length_dmrs = get_num_dmrs(dlsch0->dlsch_config.dlDmrsSymbPos); uint16_t nb_rb = dlsch0->dlsch_config.number_rbs; uint8_t nb_re_dmrs = dlsch0->dlsch_config.dmrsConfigType == NFAPI_NR_DMRS_TYPE1 ? 6*dlsch0->dlsch_config.n_dmrs_cdm_groups : 4*dlsch0->dlsch_config.n_dmrs_cdm_groups; uint8_t mod_order = dlsch0->dlsch_config.qamModOrder; uint8_t nb_symb_sch = dlsch0->dlsch_config.number_symbols; uint32_t unav_res = ptrsSymbPerSlot * ptrsRePerSymb; - available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs, unav_res, mod_order, rel15->nrOfLayers); + available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs, unav_res, mod_order, pdsch_pdu_rel15->nrOfLayers); if (pdu_bit_map & 0x1) { if (trial == 0 && round == 0) { - printf("[DLSIM][PTRS] Available bits are: %5u, removed PTRS bits are: %5u \n", available_bits, (ptrsSymbPerSlot * ptrsRePerSymb * rel15->nrOfLayers * mod_order)); + printf("[DLSIM][PTRS] Available bits are: %5u, removed PTRS bits are: %5u \n", available_bits, (ptrsSymbPerSlot * ptrsRePerSymb * pdsch_pdu_rel15->nrOfLayers * mod_order)); } } @@ -1269,8 +1255,8 @@ int main(int argc, char **argv) } // round if (test_input_bit == NULL) { - test_input_bit = (unsigned char *)malloc16(8 * rel15->TBSize[0]); - estimated_output_bit = (unsigned char *)malloc16(8 * rel15->TBSize[0]); + test_input_bit = (unsigned char *)malloc16(8 * pdsch_pdu_rel15->TBSize[0]); + estimated_output_bit = (unsigned char *)malloc16(8 * pdsch_pdu_rel15->TBSize[0]); } for (i = 0; i < TBS; i++) { @@ -1319,7 +1305,7 @@ int main(int argc, char **argv) printf("), Channel BER (%e", berStats[0]); for (int r = 1; r < num_rounds; r++) printf(",%e", berStats[r]); - printf(") Avg round %.2f, Eff Rate %.4f bits/slot, Eff Throughput %.2f, TBS %u bits/slot\n", roundStats, effRate, effRate / (8 * rel15->TBSize[0]) * 100, 8 * rel15->TBSize[0]); + printf(") Avg round %.2f, Eff Rate %.4f bits/slot, Eff Throughput %.2f, TBS %u bits/slot\n", roundStats, effRate, effRate / (8 * pdsch_pdu_rel15->TBSize[0]) * 100, 8 * pdsch_pdu_rel15->TBSize[0]); printf("*****************************************\n"); printf("\n"); // writing to csv file @@ -1327,7 +1313,7 @@ int main(int argc, char **argv) fprintf(csv_file,"%f,%d/%d,",SNR,n_false_positive,n_trials); for (int r = 0; r < num_rounds; r++) fprintf(csv_file,"%d/%d,%u/%u,%f,%e,",n_errors[r], round_trials[r], errors_scrambling[r], available_bits * round_trials[r],blerStats[r],berStats[r]); - fprintf(csv_file,"%.2f,%.4f,%.2f,%u\n", roundStats, effRate, effRate / (8 * rel15->TBSize[0]) * 100, 8 * rel15->TBSize[0]); + fprintf(csv_file,"%.2f,%.4f,%.2f,%u\n", roundStats, effRate, effRate / (8 * pdsch_pdu_rel15->TBSize[0]) * 100, 8 * pdsch_pdu_rel15->TBSize[0]); } if (print_perf==1) { printf("\ngNB TX function statistics (per %d us slot, NPRB %d, mcs %d, C %d, block %d)\n", @@ -1335,7 +1321,7 @@ int main(int argc, char **argv) g_rbSize, g_mcsIndex, UE->dl_harq_processes[0][slot].C, - 8 * rel15->TBSize[0]); + 8 * pdsch_pdu_rel15->TBSize[0]); printDistribution(&gNB->phy_proc_tx,table_tx,"PHY proc tx"); printStatIndent2(&gNB->dci_generation_stats, "DCI encoding time"); printStatIndent2(&gNB->dlsch_encoding_stats,"DLSCH encoding time"); @@ -1377,8 +1363,8 @@ int main(int argc, char **argv) const uint32_t numReSym = (g_rbSize * 12 + 15) & (~15); for (int l = 0; l < g_nrOfLayers; l++) { for (int r = 0; r < n_rx; r++) { - const int s = rel15->StartSymbolIndex; - const int n = rel15->NrOfSymbols; + const int s = pdsch_pdu_rel15->StartSymbolIndex; + const int n = pdsch_pdu_rel15->NrOfSymbols; for (int i = s; i < s + n; i++) { const uint32_t dmrsBitMap = phy_data.dlsch[0].dlsch_config.dlDmrsSymbPos; const uint32_t dmrsCfg = phy_data.dlsch[0].dlsch_config.dmrsConfigType; @@ -1414,7 +1400,7 @@ int main(int argc, char **argv) break; } - if (effRate >= (eff_tp_check * 8 * rel15->TBSize[0])) { + if (effRate >= (eff_tp_check * 8 * pdsch_pdu_rel15->TBSize[0])) { printf("PDSCH test OK\n"); ret = 0; break; diff --git a/openair1/SIMULATION/NR_PHY/pbchsim.c b/openair1/SIMULATION/NR_PHY/pbchsim.c index b40cfc8176..c86744afaa 100644 --- a/openair1/SIMULATION/NR_PHY/pbchsim.c +++ b/openair1/SIMULATION/NR_PHY/pbchsim.c @@ -519,10 +519,10 @@ int main(int argc, char **argv) exit(-1); } - processingData_L1tx_t msgDataTx; // generate signal const uint32_t rxdataF_sz = UE->frame_parms.samples_per_slot_wCP; __attribute__ ((aligned(32))) c16_t rxdataF[UE->frame_parms.nb_antennas_rx][rxdataF_sz]; + nfapi_nr_dl_tti_ssb_pdu ssb_pdu[64] = {0}; if (input_fd==NULL) { for (i=0; iLmax; i++) { @@ -530,10 +530,10 @@ int main(int argc, char **argv) const int sc_offset = frame_parms->freq_range == FR1 ? ssb_subcarrier_offset<freq_range == FR1 ? gNB->gNB_config.ssb_table.ssb_offset_point_a.value<gNB_config.ssb_table.ssb_offset_point_a.value << (mu - 2); - msgDataTx.ssb_pdu[i].ssb_pdu_rel15.bchPayload = 0x55dd33; - msgDataTx.ssb_pdu[i].ssb_pdu_rel15.SsbBlockIndex = i; - msgDataTx.ssb_pdu[i].ssb_pdu_rel15.SsbSubcarrierOffset = sc_offset; - msgDataTx.ssb_pdu[i].ssb_pdu_rel15.ssbOffsetPointA = prb_offset; + ssb_pdu[i].ssb_pdu_rel15.bchPayload = 0x55dd33; + ssb_pdu[i].ssb_pdu_rel15.SsbBlockIndex = i; + ssb_pdu[i].ssb_pdu_rel15.SsbSubcarrierOffset = sc_offset; + ssb_pdu[i].ssb_pdu_rel15.ssbOffsetPointA = prb_offset; start_symbol = nr_get_ssb_start_symbol(frame_parms,i); int slot = start_symbol/14; @@ -541,7 +541,7 @@ int main(int argc, char **argv) for (aa=0; aaframe_parms.nb_antennas_tx; aa++) memset(gNB->common_vars.txdataF[0][aa], 0, frame_parms->samples_per_slot_wCP * sizeof(int32_t)); - nr_common_signal_procedures (gNB,frame,slot, &msgDataTx.ssb_pdu[i]); + nr_common_signal_procedures (gNB,frame,slot, &ssb_pdu[i]); int samp = frame_parms->get_samples_slot_timestamp(slot, frame_parms, 0); for (aa=0; aaframe_parms.nb_antennas_tx; aa++) { @@ -744,7 +744,7 @@ int main(int argc, char **argv) gNB->gNB_config.ssb_table.ssb_subcarrier_offset.value, frame_parms->Lmax); int payload_ret = (result.xtra_byte == xtra_byte); - nfapi_nr_dl_tti_ssb_pdu_rel15_t *pdu = &msgDataTx.ssb_pdu[ssb_index].ssb_pdu_rel15; + nfapi_nr_dl_tti_ssb_pdu_rel15_t *pdu = &ssb_pdu[ssb_index].ssb_pdu_rel15; for (int i = 0; i < 3; i++) payload_ret += (result.decoded_output[i] == ((pdu->bchPayload >> (8 * i)) & 0xff)); // printf("ret %d\n", payload_ret); diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index b7f93cdf3a..85c165b00d 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -60,7 +60,6 @@ #include "PHY/defs_nr_common.h" #include "PHY/impl_defs_nr.h" #include "PHY/phy_vars_nr_ue.h" -#include "SCHED_NR/fapi_nr_l1.h" #include "SCHED_NR/sched_nr.h" #include "SCHED_NR_UE/defs.h" #include "SCHED_NR_UE/fapi_nr_ue_l1.h" @@ -727,11 +726,6 @@ int main(int argc, char *argv[]) else initNamedTpool(gNBthreads, &gNB->threadPool, true, "gNB-tpool"); - processingData_L1tx_t *msgDataTx = malloc(sizeof(processingData_L1tx_t)); - msgDataTx->slot = -1; - gNB->msgDataTx = msgDataTx; - //gNB_config = &gNB->gNB_config; - NR_UL_IND_t UL_INFO = {0}; UL_INFO.crc_ind.crc_list = UL_INFO.crc_pdu_list; UL_INFO.rx_ind.pdu_list = UL_INFO.rx_pdu_list; @@ -1284,6 +1278,9 @@ int main(int argc, char *argv[]) srs_pdu->beamforming.prg_size = 1; } + /* load FAPI into RX of L1 */ + nr_save_ul_tti_req(gNB, &Sched_INFO->UL_tti_req); + /// UE UL PDUs UE->ul_harq_processes[harq_pid].round = round; @@ -1291,9 +1288,6 @@ int main(int argc, char *argv[]) UE_proc.frame_tx = frame; UE_proc.gNB_id = 0; - // prepare ULSCH/PUSCH reception - nr_schedule_response(Sched_INFO); - // --------- setting parameters for UE -------- nr_scheduled_response_t scheduled_response = {.ul_config = &ul_config, .phy_data = (void *)&phy_data}; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index a102411721..6a9cce656a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -59,13 +59,7 @@ uint8_t nr_get_rv(int rel_round) return nr_rv_round_map[rel_round]; } -void clear_nr_nfapi_information(gNB_MAC_INST *gNB, - int CC_idP, - frame_t frameP, - slot_t slotP, - nfapi_nr_dl_tti_request_t *DL_req, - nfapi_nr_tx_data_request_t *TX_req, - nfapi_nr_ul_dci_request_t *UL_dci_req) +void clear_nr_nfapi_information(gNB_MAC_INST *gNB, int CC_idP, frame_t frameP, slot_t slotP) { /* called below and in simulators, so we assume a lock but don't require it */ const int num_slots = gNB->frame_structure.numb_slots_frame; @@ -75,16 +69,8 @@ void clear_nr_nfapi_information(gNB_MAC_INST *gNB, gNB->pdu_index[CC_idP] = 0; - DL_req[CC_idP].SFN = frameP; - DL_req[CC_idP].Slot = slotP; - DL_req[CC_idP].dl_tti_request_body.nPDUs = 0; - DL_req[CC_idP].dl_tti_request_body.nGroup = 0; memset(pdcch, 0, sizeof(*pdcch) * MAX_NUM_CORESET); - UL_dci_req[CC_idP].SFN = frameP; - UL_dci_req[CC_idP].Slot = slotP; - UL_dci_req[CC_idP].numPdus = 0; - /* advance last round's future UL_tti_req to be ahead of current frame/slot */ const int size = gNB->UL_tti_req_ahead_size; const int prev_slot = frameP * num_slots + slotP + size - 1; @@ -100,8 +86,6 @@ void clear_nr_nfapi_information(gNB_MAC_INST *gNB, future_ul_tti_req->n_ulsch = 0; future_ul_tti_req->n_ulcch = 0; future_ul_tti_req->n_group = 0; - - TX_req[CC_idP].Number_of_PDUs = 0; } static void clear_beam_information(NR_beam_info_t *beam_info, int frame, int slot, int slots_per_frame) @@ -191,7 +175,7 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame, slot_t slo uint16_t *vrb_map_UL = cc[CC_id].vrb_map_UL[i]; memcpy(&vrb_map_UL[prev_slot % size * MAX_BWP_SIZE], &gNB->ulprbbl, sizeof(uint16_t) * MAX_BWP_SIZE); } - clear_nr_nfapi_information(gNB, CC_id, frame, slot, &sched_info->DL_req, &sched_info->TX_req, &sched_info->UL_dci_req); + clear_nr_nfapi_information(gNB, CC_id, frame, slot); } bool wait_prach_completed = gNB->num_scheduled_prach_rx >= NUM_PRACH_RX_FOR_NOISE_ESTIMATE; diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index cfe02755b2..fb5e64efa8 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -68,13 +68,7 @@ int nr_mac_get_reconfig_delay_slots(NR_SubcarrierSpacing_t scs); int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, int slots); int nr_transmission_action_indicator_stop(gNB_MAC_INST *mac, NR_UE_info_t *UE_info); -void clear_nr_nfapi_information(gNB_MAC_INST *gNB, - int CC_idP, - frame_t frameP, - slot_t slotP, - nfapi_nr_dl_tti_request_t *DL_req, - nfapi_nr_tx_data_request_t *TX_req, - nfapi_nr_ul_dci_request_t *UL_dci_req); +void clear_nr_nfapi_information(gNB_MAC_INST *gNB, int CC_idP, frame_t frameP, slot_t slotP); void nr_mac_update_timers(module_id_t module_id, frame_t frame, slot_t slot); diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c index 2352870ace..faf07154ee 100644 --- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c @@ -380,48 +380,22 @@ static void match_crc_rx_pdu(nfapi_nr_rx_data_indication_t *rx_ind, nfapi_nr_crc } extern void handle_nr_slot_ind(uint16_t sfn, uint16_t slot); -static void pnf_send_slot_ind(module_id_t module_id, int CC_id, int frame, int slot) +static void pnf_send_slot_ind(const nfapi_nr_slot_indication_scf_t *ind, NR_Sched_Rsp_t *rsp) { - (void)module_id; - (void)CC_id; - handle_nr_slot_ind(frame, slot); + module_id_t module_id = 0; + int CC_id = 0; + reset_sched_response(rsp, ind->sfn, ind->slot, module_id, CC_id); + handle_nr_slot_ind(ind->sfn, ind->slot); + + // TODO copy messages from FAPI buffers } -static void run_scheduler_monolithic(module_id_t module_id, int CC_id, int frame, int slot) +static void run_scheduler_monolithic(const nfapi_nr_slot_indication_scf_t *ind, NR_Sched_Rsp_t *rsp) { - NR_IF_Module_t *ifi = nr_if_inst[module_id]; - - LOG_D(NR_MAC, "Calling scheduler for %d.%d\n", frame, slot); - NR_Sched_Rsp_t *sched_info = allocate_sched_response(); - - // clear UL DCI prior to handling ULSCH - sched_info->UL_dci_req.numPdus = 0; - gNB_dlsch_ulsch_scheduler(module_id, frame, slot, sched_info); - ifi->CC_mask = 0; - sched_info->module_id = module_id; - sched_info->CC_id = CC_id; - sched_info->frame = frame; - sched_info->slot = slot; - /* - sched_info->DL_req = &mac->DL_req[CC_id]; - sched_info->UL_dci_req = &mac->UL_dci_req[CC_id]; - - sched_info->UL_tti_req = mac->UL_tti_req[CC_id]; - - sched_info->TX_req = &mac->TX_req[CC_id]; - */ -#ifdef DUMP_FAPI - dump_dl(sched_info); -#endif - - AssertFatal(ifi->NR_Schedule_response != NULL, "nr_schedule_response is null (mod %d, cc %d)\n", module_id, CC_id); - ifi->NR_Schedule_response(sched_info); - - LOG_D(NR_PHY, - "NR_Schedule_response: SFN SLOT:%d %d dl_pdus:%d\n", - sched_info->frame, - sched_info->slot, - sched_info->DL_req.dl_tti_request_body.nPDUs); + module_id_t module_id = 0; + int CC_id = 0; + reset_sched_response(rsp, ind->sfn, ind->slot, module_id, CC_id); + gNB_dlsch_ulsch_scheduler(rsp->module_id, ind->sfn, ind->slot, rsp); } void NR_UL_indication(NR_UL_IND_t *UL_info) { @@ -515,3 +489,33 @@ NR_IF_Module_t *NR_IF_Module_init(int Mod_id) { return nr_if_inst[Mod_id]; } + +void reset_sched_response(NR_Sched_Rsp_t *sched_response, int frame, int slot, int module_id, int CC_id) +{ + sched_response->module_id = module_id; + sched_response->CC_id = CC_id; + sched_response->frame = frame; + sched_response->slot = slot; + + + nfapi_nr_dl_tti_request_t *DL_req = &sched_response->DL_req; + DL_req->SFN = frame; + DL_req->Slot = slot; + DL_req->dl_tti_request_body.nPDUs = 0; + DL_req->dl_tti_request_body.nGroup = 0; + + nfapi_nr_ul_dci_request_t *UL_dci_req = &sched_response->UL_dci_req; + UL_dci_req->SFN = frame; + UL_dci_req->Slot = slot; + UL_dci_req->numPdus = 0; + + nfapi_nr_ul_tti_request_t *UL_tti_req = &sched_response->UL_tti_req; + UL_tti_req->SFN = frame; + UL_tti_req->Slot = slot; + UL_tti_req->n_pdus = 0; + + nfapi_nr_tx_data_request_t *TX_req = &sched_response->TX_req; + TX_req->SFN = frame; + TX_req->Slot = slot; + TX_req->Number_of_PDUs = 0; +} diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.h b/openair2/NR_PHY_INTERFACE/NR_IF_Module.h index 52a0f28871..fe5c0738c4 100644 --- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.h +++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.h @@ -111,6 +111,7 @@ typedef struct { /// Pointers to DL SDUs nfapi_nr_tx_data_request_t TX_req; } NR_Sched_Rsp_t; +void reset_sched_response(NR_Sched_Rsp_t *sched_response, int frame, int slot, int module_id, int CC_id); typedef struct { uint8_t Mod_id; @@ -122,7 +123,7 @@ typedef struct NR_IF_Module_s { //define the function pointer void (*NR_UL_indication)(NR_UL_IND_t *UL_INFO); void (*NR_Schedule_response)(NR_Sched_Rsp_t *Sched_INFO); - void (*NR_slot_indication)(module_id_t module_idP, int CC_id, int frame, int slot); + void (*NR_slot_indication)(const nfapi_nr_slot_indication_scf_t *ind, NR_Sched_Rsp_t *rsp); void (*NR_PHY_config_req)(NR_PHY_Config_t *config_INFO); uint32_t CC_mask; uint16_t current_frame; From eefb9da69a48ce8ca85e7647fea39bf8d8dcf5dc Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 12 Nov 2025 19:07:51 +0100 Subject: [PATCH 64/80] Reimplement nFAPI message exchange after msgDataTx removal Reimplement nFAPI message exchange between L1 and L2 following the changes in parent commit removing msgDataTx. Avoid direct calls and use NR_IF_module fptrs to avoid linking problems. allowing to remove some function definitions that are not needed. --- doc/nfapi.md | 4 +- executables/lte-softmodem.c | 2 - nfapi/oai_integration/nfapi_pnf.c | 11 +- nfapi/oai_integration/nfapi_pnf.h | 3 +- nfapi/oai_integration/nfapi_vnf.c | 98 ++++---- nfapi/open-nFAPI/pnf/inc/pnf_p7.h | 10 +- .../pnf/public_inc/nfapi_pnf_interface.h | 12 +- nfapi/open-nFAPI/pnf/src/pnf_p7.c | 214 +++++++++--------- nfapi/open-nFAPI/pnf/src/pnf_p7_interface.c | 21 +- nfapi/open-nFAPI/pnf/tests/pnf_cunit_main.c | 6 - openair2/NR_PHY_INTERFACE/NR_IF_Module.c | 19 +- openair2/NR_PHY_INTERFACE/NR_IF_Module.h | 4 +- 12 files changed, 216 insertions(+), 188 deletions(-) diff --git a/doc/nfapi.md b/doc/nfapi.md index 214aa2799f..8b9197b056 100644 --- a/doc/nfapi.md +++ b/doc/nfapi.md @@ -242,10 +242,10 @@ To see the (any) periodical output at the PNF, define `NFAPI_TRACE_LEVEL=info`. This output shows: ``` -41056.739654 [I] 3556767424: pnf_p7_slot_ind: [P7:1] msgs ontime 489 thr DL 0.06 UL 0.01 msg late 0 (vtime) +41056.739654 [I] 3556767424: nr_pnf_p7_get_msgs: [P7:1] msgs ontime 489 thr DL 0.06 UL 0.01 msg late 0 (vtime) ``` -The first numbers are timestamps. `pnf_p7_slot_ind` is the name of the +The first numbers are timestamps. `nr_pnf_p7_get_msgs` is the name of the functions that prints the output. `[P7:1]` refers to the fact that these are information on P7, of PHY ID 1. Finally, `msgs ontime 489` means that in the last window (since the last print), 489 messages arrived at the PNF in total. diff --git a/executables/lte-softmodem.c b/executables/lte-softmodem.c index 80b532607e..0932702910 100644 --- a/executables/lte-softmodem.c +++ b/executables/lte-softmodem.c @@ -199,8 +199,6 @@ void nr_schedule_ul_dci_req() {}; void nr_schedule_tx_req() {}; void nr_schedule_ul_tti_req() {}; void nr_slot_select() {}; -void NR_UL_indication(NR_UL_IND_t *UL_INFO) {}; -void gNB_dlsch_ulsch_scheduler() {}; /*------------------------------------------------------------------------*/ diff --git a/nfapi/oai_integration/nfapi_pnf.c b/nfapi/oai_integration/nfapi_pnf.c index bad2d036c9..79c0d689c7 100644 --- a/nfapi/oai_integration/nfapi_pnf.c +++ b/nfapi/oai_integration/nfapi_pnf.c @@ -2314,7 +2314,7 @@ static void maybe_slow_down_pnf(int mu) last_execution = current_execution; } -void handle_nr_slot_ind(uint16_t sfn, uint16_t slot) +void handle_nr_slot_ind(uint16_t sfn, uint16_t slot, NR_Sched_Rsp_t *sched_resp) { nfapi_pnf_p7_config_t *config = p7_config_g; pnf_p7_t *_this = (pnf_p7_t *)(config); @@ -2345,7 +2345,14 @@ void handle_nr_slot_ind(uint16_t sfn, uint16_t slot) oai_nfapi_nr_slot_indication(&ind); // copy data from appropriate p7 slot buffers into channel structures for PHY processing - nfapi_pnf_p7_slot_ind(config, config->phy_id, sfn, slot); + nfapi_pnf_p7_get_msgs(config, + config->phy_id, + sfn, + slot, + &sched_resp->DL_req, + &sched_resp->UL_tti_req, + &sched_resp->UL_dci_req, + &sched_resp->TX_req); return; } diff --git a/nfapi/oai_integration/nfapi_pnf.h b/nfapi/oai_integration/nfapi_pnf.h index 0ba0676f10..ad2df72ad3 100644 --- a/nfapi/oai_integration/nfapi_pnf.h +++ b/nfapi/oai_integration/nfapi_pnf.h @@ -28,7 +28,8 @@ void configure_nfapi_pnf(char *vnf_ip_addr, int vnf_p5_port, char *pnf_ip_addr, void configure_nr_nfapi_pnf(char *vnf_ip_addr, int vnf_p5_port, char *pnf_ip_addr, int pnf_p7_port, int vnf_p7_port); void oai_subframe_ind(uint16_t sfn, uint16_t sf); -void handle_nr_slot_ind(uint16_t sfn, uint16_t slot); +struct NR_Sched_Rsp; +void handle_nr_slot_ind(uint16_t sfn, uint16_t slot, struct NR_Sched_Rsp *resp); void sfnslot_add_slot(int mu, uint16_t *sfn, uint16_t *slot, int offset); int oai_nfapi_nr_slot_indication(nfapi_nr_slot_indication_scf_t *ind); diff --git a/nfapi/oai_integration/nfapi_vnf.c b/nfapi/oai_integration/nfapi_vnf.c index 5ea99de7ea..6f73121c68 100644 --- a/nfapi/oai_integration/nfapi_vnf.c +++ b/nfapi/oai_integration/nfapi_vnf.c @@ -971,65 +971,63 @@ int phy_cqi_indication(struct nfapi_vnf_p7_config *config, nfapi_cqi_indication_ //NR phy indication -NR_Sched_Rsp_t g_sched_resp; -void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame, slot_t slot, NR_Sched_Rsp_t* sched_info); int oai_nfapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req); int oai_nfapi_ul_tti_req(nfapi_nr_ul_tti_request_t *ul_tti_req); int oai_nfapi_tx_data_req(nfapi_nr_tx_data_request_t* tx_data_req); int oai_nfapi_ul_dci_req(nfapi_nr_ul_dci_request_t* ul_dci_req); -int trigger_scheduler(nfapi_nr_slot_indication_scf_t *slot_ind) -{ - // Call into the scheduler (this is hardcoded and should be init properly!) - // memset(sched_resp, 0, sizeof(*sched_resp)); - gNB_dlsch_ulsch_scheduler(0, slot_ind->sfn, slot_ind->slot, &g_sched_resp); - -#ifdef ENABLE_AERIAL - bool send_slt_resp = false; - if (g_sched_resp.DL_req.dl_tti_request_body.nPDUs> 0) { - oai_fapi_dl_tti_req(&g_sched_resp.DL_req); - send_slt_resp = true; - } - if (g_sched_resp.UL_tti_req.n_pdus > 0) { - oai_fapi_ul_tti_req(&g_sched_resp.UL_tti_req); - send_slt_resp = true; - } - if (g_sched_resp.TX_req.Number_of_PDUs > 0) { - oai_fapi_tx_data_req(&g_sched_resp.TX_req); - send_slt_resp = true; - } - if (g_sched_resp.UL_dci_req.numPdus > 0) { - oai_fapi_ul_dci_req(&g_sched_resp.UL_dci_req); - send_slt_resp = true; - } - if (send_slt_resp) { - oai_fapi_send_end_request(0,slot_ind->sfn, slot_ind->slot); - } -#else - if (g_sched_resp.DL_req.dl_tti_request_body.nPDUs > 0) - oai_nfapi_dl_tti_req(&g_sched_resp.DL_req); - - if (g_sched_resp.UL_tti_req.n_pdus > 0) - oai_nfapi_ul_tti_req(&g_sched_resp.UL_tti_req); - - if (g_sched_resp.TX_req.Number_of_PDUs > 0) - oai_nfapi_tx_data_req(&g_sched_resp.TX_req); - - if (g_sched_resp.UL_dci_req.numPdus > 0) - oai_nfapi_ul_dci_req(&g_sched_resp.UL_dci_req); -#endif - - NR_UL_IND_t ind = {.frame = slot_ind->sfn, .slot = slot_ind->slot, }; - NR_UL_indication(&ind); - - return 1; -} - int phy_nr_slot_indication(nfapi_nr_slot_indication_scf_t *ind) { LOG_D(MAC, "VNF SFN/Slot %d.%d \n", ind->sfn, ind->slot); - trigger_scheduler(ind); + // this variable is very big (multiple MB), so we put it into static storage + // to not overflow the stack while still having it in local (function) scope + // also, phy_nr_slot_indication() is only executed by one thread, serially + static NR_Sched_Rsp_t sched_response; + NR_IF_Module_t *ifi = RC.nrmac[0]->if_inst; + ifi->NR_slot_indication(ind, &sched_response); + +#ifdef ENABLE_AERIAL + bool send_slt_resp = false; + if (sched_response.DL_req.dl_tti_request_body.nPDUs> 0) { + oai_fapi_dl_tti_req(&sched_response.DL_req); + send_slt_resp = true; + } + if (sched_response.UL_tti_req.n_pdus > 0) { + oai_fapi_ul_tti_req(&sched_response.UL_tti_req); + send_slt_resp = true; + } + if (sched_response.TX_req.Number_of_PDUs > 0) { + oai_fapi_tx_data_req(&sched_response.TX_req); + send_slt_resp = true; + } + if (sched_response.UL_dci_req.numPdus > 0) { + oai_fapi_ul_dci_req(&sched_response.UL_dci_req); + send_slt_resp = true; + } + if (send_slt_resp) { + oai_fapi_send_end_request(0, ind->sfn, ind->slot); + } +#else + if (sched_response.DL_req.dl_tti_request_body.nPDUs > 0) + oai_nfapi_dl_tti_req(&sched_response.DL_req); + + if (sched_response.UL_tti_req.n_pdus > 0) + oai_nfapi_ul_tti_req(&sched_response.UL_tti_req); + + if (sched_response.TX_req.Number_of_PDUs > 0) + oai_nfapi_tx_data_req(&sched_response.TX_req); + + if (sched_response.UL_dci_req.numPdus > 0) + oai_nfapi_ul_dci_req(&sched_response.UL_dci_req); +#endif + + /* the below works because the function behind the callback collects + * messages from queue into which messages have been copied. + * TODO we should have different callbacks for received messages and call + * into the scheduler separately for each message instead of one big one. */ + NR_UL_IND_t ul_ind = {.frame = ind->sfn, .slot = ind->slot, }; + ifi->NR_UL_indication(&ul_ind); return 1; } diff --git a/nfapi/open-nFAPI/pnf/inc/pnf_p7.h b/nfapi/open-nFAPI/pnf/inc/pnf_p7.h index 5805e07445..3040d9de09 100644 --- a/nfapi/open-nFAPI/pnf/inc/pnf_p7.h +++ b/nfapi/open-nFAPI/pnf/inc/pnf_p7.h @@ -145,8 +145,14 @@ int pnf_nr_p7_message_pump(pnf_p7_t* pnf_p7); int pnf_p7_pack_and_send_p7_message(pnf_p7_t* pnf_p7, nfapi_p7_message_header_t* msg, uint32_t msg_len); int pnf_p7_send_message(pnf_p7_t* pnf_p7, uint8_t* msg, uint32_t msg_len); - -int pnf_p7_slot_ind(pnf_p7_t* config, uint16_t phy_id, uint16_t sfn, uint16_t slot); +int nr_pnf_p7_get_msgs(pnf_p7_t* pnf_p7, + uint16_t phy_id, + uint16_t sfn, + uint16_t slot, + nfapi_nr_dl_tti_request_t* ret_dl_tti, + nfapi_nr_ul_tti_request_t* ret_ul_tti, + nfapi_nr_ul_dci_request_t* ret_ul_dci, + nfapi_nr_tx_data_request_t* ret_tx_data); int pnf_p7_subframe_ind(pnf_p7_t* config, uint16_t phy_id, uint16_t sfn_sf); int nfapi_pnf_p7_nr_slot_ind(nfapi_pnf_p7_config_t* config, nfapi_nr_slot_indication_scf_t* ind); int nfapi_pnf_p7_nr_rx_data_ind(nfapi_pnf_p7_config_t* config, nfapi_nr_rx_data_indication_t* ind); diff --git a/nfapi/open-nFAPI/pnf/public_inc/nfapi_pnf_interface.h b/nfapi/open-nFAPI/pnf/public_inc/nfapi_pnf_interface.h index 957e032f69..6576f6406e 100644 --- a/nfapi/open-nFAPI/pnf/public_inc/nfapi_pnf_interface.h +++ b/nfapi/open-nFAPI/pnf/public_inc/nfapi_pnf_interface.h @@ -856,7 +856,7 @@ int nfapi_pnf_p7_start(nfapi_pnf_p7_config_t* config); */ int nfapi_pnf_p7_stop(nfapi_pnf_p7_config_t* config); -/*! NR Slot indication +/*! NR get stuff * message copied from nfapi_pnf_p7_subframe_ind * \param config A pointer to a PNF P7 config * \param phy_id The phy_id for the phy instance @@ -868,8 +868,14 @@ int nfapi_pnf_p7_stop(nfapi_pnf_p7_config_t* config); * * If messages are not in the subframe buffer, they dummy subframe messages will be sent */ -int nfapi_pnf_p7_slot_ind(nfapi_pnf_p7_config_t* config, uint16_t phy_id, uint16_t sfn, uint16_t slot); - +int nfapi_pnf_p7_get_msgs(nfapi_pnf_p7_config_t* config, + uint16_t phy_id, + uint16_t sfn, + uint16_t slot, + nfapi_nr_dl_tti_request_t* ret_dl_tti, + nfapi_nr_ul_tti_request_t* ret_ul_tti, + nfapi_nr_ul_dci_request_t* ret_ul_dci, + nfapi_nr_tx_data_request_t* ret_tx_data); /*! Subframe indication * \param config A pointer to a PNF P7 config diff --git a/nfapi/open-nFAPI/pnf/src/pnf_p7.c b/nfapi/open-nFAPI/pnf/src/pnf_p7.c index e2b6d253d2..197bac22b7 100644 --- a/nfapi/open-nFAPI/pnf/src/pnf_p7.c +++ b/nfapi/open-nFAPI/pnf/src/pnf_p7.c @@ -672,145 +672,157 @@ void send_dummy_subframe(pnf_p7_t* pnf_p7, uint16_t sfn_sf) } } +int nr_pnf_p7_get_msgs(pnf_p7_t* pnf_p7, + uint16_t phy_id, + uint16_t sfn, + uint16_t slot, + nfapi_nr_dl_tti_request_t* ret_dl_tti, + nfapi_nr_ul_tti_request_t* ret_ul_tti, + nfapi_nr_ul_dci_request_t* ret_ul_dci, + nfapi_nr_tx_data_request_t* ret_tx_data) +{ + if (pthread_mutex_lock(&(pnf_p7->mutex)) != 0) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to lock mutex\n"); + return -1; + } -int pnf_p7_slot_ind(pnf_p7_t* pnf_p7, uint16_t phy_id, uint16_t sfn, uint16_t slot) -{ - //This function is aligned with rx sfn/slot + // save the curren time, sfn and slot + // TODO useful? + pnf_p7->slot_start_time_hr = pnf_get_current_time_hr(); - // We could either send an event to the p7 thread have have it run the - // subframe or we could handle it here and lock access to the subframe - // buffers. If we do it on the p7 thread then we run the risk of blocking - // on the udp send. - - // todo : consider a more efficent lock mechasium - //uint16_t NUM_SLOTS = 20;//10* 2^mu - - if(pthread_mutex_lock(&(pnf_p7->mutex)) != 0) - { - NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to lock mutex\n"); - return -1; - } + // We align the pnf_p7 sfn/slot with tx sfn/slot, and vnf is synced with pnf_p7 sfn/slot. This is so that the scheduler runs + // slot_ahead from rx thread. + pnf_p7->sfn = sfn; + pnf_p7->slot = slot; - // save the curren time, sfn and slot - pnf_p7->slot_start_time_hr = pnf_get_current_time_hr(); + uint32_t tx_slot_dec = NFAPI_SFNSLOT2DEC(pnf_p7->mu, sfn, slot); + uint8_t buffer_index_tx = tx_slot_dec % NFAPI_SLOTNUM(pnf_p7->mu); - //We align the pnf_p7 sfn/slot with tx sfn/slot, and vnf is synced with pnf_p7 sfn/slot. This is so that the scheduler runs slot_ahead from rx thread. + // If the subframe_buffer has been configured + if (pnf_p7->_public.slot_buffer_size != 0) // for now value is same as sf_buffer_size + { + // apply the shift to the incoming sfn_sf + if (pnf_p7->slot_shift != 0) // see in vnf_build_send_dl_node_sync + { + uint16_t shifted_slot = slot + pnf_p7->slot_shift; - pnf_p7->sfn = sfn; - pnf_p7->slot = slot; + // adjust for wrap-around + if (shifted_slot < 0) + shifted_slot += NFAPI_MAX_SFNSLOTDEC(pnf_p7->mu); + else if (shifted_slot > NFAPI_MAX_SFNSLOTDEC(pnf_p7->mu)) + shifted_slot -= NFAPI_MAX_SFNSLOTDEC(pnf_p7->mu); - uint32_t tx_slot_dec = NFAPI_SFNSLOT2DEC(pnf_p7->mu, sfn,slot); - uint8_t buffer_index_tx = tx_slot_dec % NFAPI_SLOTNUM(pnf_p7->mu); + //NFAPI_TRACE(NFAPI_TRACE_INFO, "Applying shift %d to sfn/slot (%d -> %d)\n", pnf_p7->sfn_slot_shift, + //NFAPI_SFNSF2DEC(sfn_slot), shifted_sfn_slot); + slot = shifted_slot; - // If the subframe_buffer has been configured - if(pnf_p7->_public.slot_buffer_size!= 0) // for now value is same as sf_buffer_size - { + // + // why does the shift not apply to pnf_p7->sfn_sf??? + // - // apply the shift to the incoming sfn_sf - if(pnf_p7->slot_shift != 0) // see in vnf_build_send_dl_node_sync - { - uint16_t shifted_slot = slot + pnf_p7->slot_shift; + pnf_p7->slot_shift = 0; + } - // adjust for wrap-around - if(shifted_slot < 0) - shifted_slot += NFAPI_MAX_SFNSLOTDEC(pnf_p7->mu); - else if(shifted_slot > NFAPI_MAX_SFNSLOTDEC(pnf_p7->mu)) - shifted_slot -= NFAPI_MAX_SFNSLOTDEC(pnf_p7->mu); - - // NFAPI_TRACE(NFAPI_TRACE_INFO, "Applying shift %d to sfn/slot (%d -> %d)\n", pnf_p7->sfn_slot_shift, NFAPI_SFNSF2DEC(sfn_slot), shifted_sfn_slot); - slot = shifted_slot; - - // - // why does the shift not apply to pnf_p7->sfn_sf??? - // - - pnf_p7->slot_shift = 0; - } - - nfapi_pnf_p7_slot_buffer_t* tx_slot_buffer = &(pnf_p7->slot_buffer[buffer_index_tx]); + nfapi_pnf_p7_slot_buffer_t* tx_slot_buffer = &(pnf_p7->slot_buffer[buffer_index_tx]); + ret_dl_tti->SFN = sfn; + ret_dl_tti->Slot = slot; + ret_dl_tti->dl_tti_request_body.nPDUs = 0; + ret_tx_data->SFN = sfn; + ret_tx_data->Slot = slot; + ret_tx_data->Number_of_PDUs = 0; nfapi_nr_dl_tti_request_t* dl_tti_req = &tx_slot_buffer->dl_tti_req; - nfapi_nr_tx_data_request_t* tx_data_req = &tx_slot_buffer->tx_data_req; - if (dl_tti_req->dl_tti_request_body.nPDUs > 0 && dl_tti_req->SFN == sfn && dl_tti_req->Slot == slot) { - DevAssert(pnf_p7->_public.dl_tti_req_fn != NULL); - DevAssert(pnf_p7->_public.tx_data_req_fn != NULL); - if (tx_data_req->Number_of_PDUs > 0 && tx_data_req->SFN == sfn && tx_data_req->Slot == slot) { - (pnf_p7->_public.dl_tti_req_fn)(NULL, &(pnf_p7->_public), dl_tti_req); - (pnf_p7->_public.tx_data_req_fn)(&(pnf_p7->_public), tx_data_req); - } else { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "%4d.%2d no corresponding tx_data.request for dl_tti.request, dropping\n", sfn, slot); + nfapi_nr_tx_data_request_t* txd = &tx_slot_buffer->tx_data_req; + if (dl_tti_req->SFN == sfn && dl_tti_req->Slot == slot && txd->SFN == sfn && txd->Slot == slot) { + nfapi_nr_dl_tti_request_body_t* p_tti = &dl_tti_req->dl_tti_request_body; + int ret_idx = 0; + for (int i = 0; i < p_tti->nPDUs; ++i) { + int tx_index = p_tti->dl_tti_pdu_list[i].pdsch_pdu.pdsch_pdu_rel15.pduIndex - 1; + if (tx_index >= txd->Number_of_PDUs) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, + "%4d.%2d no corresponding tx_data.request for dl_tti.request index %d, dropping\n", + sfn, + slot, + tx_index); + continue; + } + ret_dl_tti->dl_tti_request_body.dl_tti_pdu_list[ret_idx] = p_tti->dl_tti_pdu_list[i]; + // TODO avoid huge copy + ret_tx_data->pdu_list[ret_idx] = txd->pdu_list[i]; + ret_idx++; } + ret_dl_tti->dl_tti_request_body.nPDUs = ret_idx; + ret_tx_data->Number_of_PDUs = ret_idx; + tx_slot_buffer->dl_tti_req.SFN = -1; tx_slot_buffer->dl_tti_req.Slot = -1; tx_slot_buffer->tx_data_req.SFN = -1; tx_slot_buffer->tx_data_req.Slot = -1; } - if (tx_data_req->Number_of_PDUs > 0 && tx_data_req->SFN == sfn && tx_data_req->Slot == slot) { - // there is a tx_data.request in this slot, but no corresponding - // dl_tti.request (when they need to come pairwise) - NFAPI_TRACE(NFAPI_TRACE_ERROR, "%4d.%2d no corresponding dl_tti.request for tx_data.request, dropping\n", sfn, slot); - tx_slot_buffer->tx_data_req.SFN = -1; - tx_slot_buffer->tx_data_req.Slot = -1; - } - if(tx_slot_buffer->ul_tti_req.n_pdus > 0 && tx_slot_buffer->ul_tti_req.SFN == sfn && tx_slot_buffer->ul_tti_req.Slot == slot) - { - DevAssert(pnf_p7->_public.ul_tti_req_fn != NULL); - (pnf_p7->_public.ul_tti_req_fn)(NULL, &(pnf_p7->_public), &tx_slot_buffer->ul_tti_req); + ret_ul_tti->SFN = sfn; + ret_ul_tti->Slot = slot; + ret_ul_tti->n_pdus = 0; + if (tx_slot_buffer->ul_tti_req.SFN == sfn && tx_slot_buffer->ul_tti_req.Slot == slot) { + nfapi_nr_ul_tti_request_t* p = &tx_slot_buffer->ul_tti_req; + ret_ul_tti->n_pdus = p->n_pdus; + for (int i = 0; i < p->n_pdus; ++i) + ret_ul_tti->pdus_list[i] = p->pdus_list[i]; tx_slot_buffer->ul_tti_req.SFN = -1; tx_slot_buffer->ul_tti_req.Slot = -1; - } + } - if(tx_slot_buffer->ul_dci_req.numPdus > 0 && tx_slot_buffer->ul_dci_req.SFN == sfn && tx_slot_buffer->ul_dci_req.Slot == slot) - { - DevAssert(pnf_p7->_public.ul_dci_req_fn != NULL); - (pnf_p7->_public.ul_dci_req_fn)(NULL, &(pnf_p7->_public), &tx_slot_buffer->ul_dci_req); + ret_ul_dci->SFN = sfn; + ret_ul_dci->Slot = slot; + ret_ul_dci->numPdus = 0; + if (tx_slot_buffer->ul_dci_req.SFN == sfn && tx_slot_buffer->ul_dci_req.Slot == slot) { + nfapi_nr_ul_dci_request_t* p = &tx_slot_buffer->ul_dci_req; + ret_ul_dci->numPdus = p->numPdus; + for (int i = 0; i < p->numPdus; ++i) + ret_ul_dci->ul_dci_pdu_list[i] = p->ul_dci_pdu_list[i]; tx_slot_buffer->ul_dci_req.SFN = -1; tx_slot_buffer->ul_dci_req.Slot = -1; - } + } - //send the periodic timing info if configured - if(pnf_p7->_public.timing_info_mode_periodic && (pnf_p7->timing_info_period_counter++) == pnf_p7->_public.timing_info_period) - { - pnf_nr_pack_and_send_timing_info(pnf_p7); + // send the periodic timing info if configured + if (pnf_p7->_public.timing_info_mode_periodic && (pnf_p7->timing_info_period_counter++) == pnf_p7->_public.timing_info_period) { + pnf_nr_pack_and_send_timing_info(pnf_p7); - pnf_p7->timing_info_period_counter = 0; - } - else if(pnf_p7->_public.timing_info_mode_aperiodic && pnf_p7->timing_info_aperiodic_send) - { - pnf_nr_pack_and_send_timing_info(pnf_p7); + pnf_p7->timing_info_period_counter = 0; + } else if (pnf_p7->_public.timing_info_mode_aperiodic && pnf_p7->timing_info_aperiodic_send) { + pnf_nr_pack_and_send_timing_info(pnf_p7); - pnf_p7->timing_info_aperiodic_send = 0; - } - else - { - pnf_p7->timing_info_ms_counter++; - } - - } + pnf_p7->timing_info_aperiodic_send = 0; + } else { + pnf_p7->timing_info_ms_counter++; + } + } if (sfn % 128 == 0 && slot == 0) { pnf_p7_nr_stats_t* s = &pnf_p7->nr_stats; int ontime = s->dl_tti.ontime + s->ul_tti.ontime + s->ul_dci.ontime + s->tx_data.ontime; int late = s->dl_tti.late + s->ul_tti.late + s->ul_dci.late + s->tx_data.late; - float dl_thr = (float) s->dl.bytes * 8 / 1000 / 1000 / 1.28f; // every 128 frames = 1.28 s - float ul_thr = (float) s->ul.bytes * 8 / 1000 / 1000 / 1.28f; - NFAPI_TRACE(NFAPI_TRACE_INFO, "[P7:%d] msgs ontime %d thr DL %.2f UL %.2f msg late %d (vtime)\n", pnf_p7->_public.phy_id, ontime, dl_thr, ul_thr, late); + float dl_thr = (float)s->dl.bytes * 8 / 1000 / 1000 / 1.28f; // every 128 frames = 1.28 s + float ul_thr = (float)s->ul.bytes * 8 / 1000 / 1000 / 1.28f; + NFAPI_TRACE(NFAPI_TRACE_INFO, + "[P7:%d] msgs ontime %d thr DL %.2f UL %.2f msg late %d (vtime)\n", + pnf_p7->_public.phy_id, + ontime, + dl_thr, + ul_thr, + late); memset(s, 0, sizeof(*s)); } - if(pthread_mutex_unlock(&(pnf_p7->mutex)) != 0) - { - NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to unlock mutex\n"); - return -1; - } + if (pthread_mutex_unlock(&(pnf_p7->mutex)) != 0) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to unlock mutex\n"); + return -1; + } - return 0; + return 0; } - - int pnf_p7_subframe_ind(pnf_p7_t* pnf_p7, uint16_t phy_id, uint16_t sfn_sf) { // We could either send an event to the p7 thread have have it run the diff --git a/nfapi/open-nFAPI/pnf/src/pnf_p7_interface.c b/nfapi/open-nFAPI/pnf/src/pnf_p7_interface.c index b021e67fc9..af02ef7a4e 100644 --- a/nfapi/open-nFAPI/pnf/src/pnf_p7_interface.c +++ b/nfapi/open-nFAPI/pnf/src/pnf_p7_interface.c @@ -89,15 +89,22 @@ int nfapi_pnf_p7_stop(nfapi_pnf_p7_config_t* config) return 0; } -int nfapi_pnf_p7_slot_ind(nfapi_pnf_p7_config_t* config, uint16_t phy_id, uint16_t sfn, uint16_t slot) +int nfapi_pnf_p7_get_msgs(nfapi_pnf_p7_config_t* config, + uint16_t phy_id, + uint16_t sfn, + uint16_t slot, + nfapi_nr_dl_tti_request_t* ret_dl_tti, + nfapi_nr_ul_tti_request_t* ret_ul_tti, + nfapi_nr_ul_dci_request_t* ret_ul_dci, + nfapi_nr_tx_data_request_t* ret_tx_data) { - // Verify that config is not null - if(config == 0) - return -1; - - pnf_p7_t* _this = (pnf_p7_t*)(config); + // Verify that config is not null + if (config == 0) + return -1; - return pnf_p7_slot_ind(_this, phy_id, sfn, slot); + pnf_p7_t* _this = (pnf_p7_t*)(config); + + return nr_pnf_p7_get_msgs(_this, phy_id, sfn, slot, ret_dl_tti, ret_ul_tti, ret_ul_dci, ret_tx_data); } int nfapi_pnf_p7_subframe_ind(nfapi_pnf_p7_config_t* config, uint16_t phy_id, uint16_t sfn_sf) diff --git a/nfapi/open-nFAPI/pnf/tests/pnf_cunit_main.c b/nfapi/open-nFAPI/pnf/tests/pnf_cunit_main.c index bd6bedbea5..3460d4d9d7 100644 --- a/nfapi/open-nFAPI/pnf/tests/pnf_cunit_main.c +++ b/nfapi/open-nFAPI/pnf/tests/pnf_cunit_main.c @@ -1210,12 +1210,6 @@ void send_dl_subframe_msgs_interleaved(int p7Sock, int phy_id, struct sockaddr_i //free(req.tx_request_body.tx_pdu_list); } -void send_slot_indication(phy_info_t* phy_info) -{ - // DONE: add sfn and slot as members in the phy_info - nfapi_pnf_p7_slot_ind(phy_info->config, phy_info->phy_id, phy_info->sfn, phy_info->slot); -} - void send_subframe_indication(phy_info_t* phy_info) { nfapi_pnf_p7_subframe_ind(phy_info->config, phy_info->phy_id, phy_info->sfn_sf); diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c index faf07154ee..9c53b50b76 100644 --- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c @@ -379,15 +379,13 @@ static void match_crc_rx_pdu(nfapi_nr_rx_data_indication_t *rx_ind, nfapi_nr_crc } } -extern void handle_nr_slot_ind(uint16_t sfn, uint16_t slot); +extern void handle_nr_slot_ind(uint16_t sfn, uint16_t slot, NR_Sched_Rsp_t *sched_response); static void pnf_send_slot_ind(const nfapi_nr_slot_indication_scf_t *ind, NR_Sched_Rsp_t *rsp) { module_id_t module_id = 0; int CC_id = 0; reset_sched_response(rsp, ind->sfn, ind->slot, module_id, CC_id); - handle_nr_slot_ind(ind->sfn, ind->slot); - - // TODO copy messages from FAPI buffers + handle_nr_slot_ind(ind->sfn, ind->slot, rsp); } static void run_scheduler_monolithic(const nfapi_nr_slot_indication_scf_t *ind, NR_Sched_Rsp_t *rsp) @@ -398,7 +396,8 @@ static void run_scheduler_monolithic(const nfapi_nr_slot_indication_scf_t *ind, gNB_dlsch_ulsch_scheduler(rsp->module_id, ind->sfn, ind->slot, rsp); } -void NR_UL_indication(NR_UL_IND_t *UL_info) { +static void NR_UL_indication(NR_UL_IND_t *UL_info) +{ AssertFatal(UL_info!=NULL,"UL_info is null\n"); module_id_t module_id = UL_info->module_id; int CC_id = UL_info->CC_id; @@ -475,12 +474,14 @@ NR_IF_Module_t *NR_IF_Module_init(int Mod_id) { nr_if_inst[Mod_id]->CC_mask=0; nr_if_inst[Mod_id]->NR_UL_indication = NR_UL_indication; - if (NFAPI_MODE == NFAPI_MONOLITHIC) + if (NFAPI_MODE == NFAPI_MONOLITHIC) { nr_if_inst[Mod_id]->NR_slot_indication = run_scheduler_monolithic; - else if (NFAPI_MODE == NFAPI_MODE_PNF) + } else if (NFAPI_MODE == NFAPI_MODE_PNF) { nr_if_inst[Mod_id]->NR_slot_indication = pnf_send_slot_ind; - else // NFAPI_MODE_VNF - NULL; + } else { // NFAPI_MODE_VNF + DevAssert(NFAPI_MODE == NFAPI_MODE_VNF || NFAPI_MODE == NFAPI_MODE_AERIAL); + nr_if_inst[Mod_id]->NR_slot_indication = run_scheduler_monolithic; + } AssertFatal(pthread_mutex_init(&nr_if_inst[Mod_id]->if_mutex,NULL)==0, "allocation of nr_if_inst[%d]->if_mutex fails\n",Mod_id); } diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.h b/openair2/NR_PHY_INTERFACE/NR_IF_Module.h index fe5c0738c4..ca7e705f4a 100644 --- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.h +++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.h @@ -91,7 +91,7 @@ typedef struct { // Downlink slot P7 -typedef struct { +typedef struct NR_Sched_Rsp { /// the ID of this sched_response - used by sched_reponse memory management int sched_response_id; /// Module ID @@ -137,8 +137,6 @@ NR_IF_Module_t *NR_IF_Module_init(int Mod_id); void NR_IF_Module_kill(int Mod_id); -void NR_UL_indication(NR_UL_IND_t *UL_INFO); - /*Interface for Downlink, transmitting the DLSCH SDU, DCI SDU*/ void NR_Schedule_Response(NR_Sched_Rsp_t *Sched_INFO); From 5ac381dd5933c3e2098533203fe627b416b9c9ca Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 13 Nov 2025 19:33:17 +0100 Subject: [PATCH 65/80] Remove dead code --- CMakeLists.txt | 3 - ci-scripts/datalog_rt_stats.100.2x2.yaml | 2 - ci-scripts/datalog_rt_stats.1x1.60.yaml | 2 - ci-scripts/datalog_rt_stats.2x2.yaml | 2 - ci-scripts/datalog_rt_stats.60.2x2.yaml | 2 - ci-scripts/datalog_rt_stats.default.yaml | 2 - doc/Doxyfile | 5 - executables/lte-softmodem.c | 4 - executables/lte-uesoftmodem.c | 4 - executables/nr-gnb.c | 11 - executables/nr-softmodem.c | 2 - nfapi/oai_integration/nfapi_pnf.c | 57 +---- .../nrLDPC_coding_segment_decoder.c | 1 - .../nrLDPC_coding_xdma/nrLDPC_coding_xdma.c | 1 - openair1/PHY/INIT/nr_init.c | 3 - openair1/PHY/NR_TRANSPORT/nr_dlsch.h | 3 - openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c | 60 ----- openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c | 1 - openair1/PHY/defs_gNB.h | 14 -- openair1/SCHED_NR/fapi_nr_l1.c | 213 ------------------ openair1/SCHED_NR/fapi_nr_l1.h | 37 --- openair1/SCHED_NR/nr_prach_procedures.c | 1 - openair1/SCHED_NR/phy_procedures_nr_gNB.c | 1 - openair2/NR_PHY_INTERFACE/NR_IF_Module.c | 3 - openair2/NR_PHY_INTERFACE/NR_IF_Module.h | 4 - openair2/NR_PHY_INTERFACE/nr_sched_response.c | 157 ------------- openair2/NR_PHY_INTERFACE/nr_sched_response.h | 32 --- 27 files changed, 4 insertions(+), 623 deletions(-) delete mode 100644 openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c delete mode 100644 openair1/SCHED_NR/fapi_nr_l1.c delete mode 100644 openair1/SCHED_NR/fapi_nr_l1.h delete mode 100644 openair2/NR_PHY_INTERFACE/nr_sched_response.c delete mode 100644 openair2/NR_PHY_INTERFACE/nr_sched_response.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c5f54f1e67..8f8a6006bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -652,7 +652,6 @@ add_library(SCHED_LIB ${SCHED_SRC}) target_link_libraries(SCHED_LIB PRIVATE asn1_lte_rrc_hdrs) set(SCHED_NR_SRC - ${OPENAIR1_DIR}/SCHED_NR/fapi_nr_l1.c ${OPENAIR1_DIR}/SCHED_NR/phy_procedures_nr_gNB.c ${OPENAIR1_DIR}/SCHED_NR/nr_prach_procedures.c ${OPENAIR1_DIR}/SCHED_NR/phy_frame_config_nr.c @@ -939,7 +938,6 @@ set(PHY_SRC_UE ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_dci.c ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_dci_tools.c ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_dlsch.c - ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_dlsch_tools.c ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_dlsch_coding.c ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_ulsch_decoding.c ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_ulsch.c @@ -1215,7 +1213,6 @@ set (MAC_SRC set (MAC_NR_SRC ${NR_PHY_INTERFACE_DIR}/NR_IF_Module.c - ${NR_PHY_INTERFACE_DIR}/nr_sched_response.c ${NR_GNB_MAC_DIR}/main.c ${NR_GNB_MAC_DIR}/config.c ${NR_GNB_MAC_DIR}/gNB_scheduler.c diff --git a/ci-scripts/datalog_rt_stats.100.2x2.yaml b/ci-scripts/datalog_rt_stats.100.2x2.yaml index 7c5cb48add..360ba57402 100644 --- a/ci-scripts/datalog_rt_stats.100.2x2.yaml +++ b/ci-scripts/datalog_rt_stats.100.2x2.yaml @@ -15,7 +15,6 @@ Ref : DLSCH encoding : 200.0 L1 Rx processing : 530.0 PUSCH inner-receiver : 360.0 - Schedule Response : 1.0 DL & UL scheduling timing : 17.0 UL Indication : 1.0 Slot Indication : 13.0 @@ -31,7 +30,6 @@ DeviationThreshold : DLSCH encoding : 0.25 L1 Rx processing : 0.25 PUSCH inner-receiver : 0.25 - Schedule Response : 1.00 DL & UL scheduling timing : 0.25 UL Indication : 1.00 Slot Indication : 0.50 diff --git a/ci-scripts/datalog_rt_stats.1x1.60.yaml b/ci-scripts/datalog_rt_stats.1x1.60.yaml index 5e0564977b..b418b74940 100644 --- a/ci-scripts/datalog_rt_stats.1x1.60.yaml +++ b/ci-scripts/datalog_rt_stats.1x1.60.yaml @@ -15,7 +15,6 @@ Ref : DLSCH encoding : 110.0 L1 Rx processing : 345.0 PUSCH inner-receiver : 150.0 - Schedule Response : 1.0 DL & UL scheduling timing : 5.0 UL Indication : 1.0 Slot Indication : 6.0 @@ -31,7 +30,6 @@ DeviationThreshold : DLSCH encoding : 0.25 L1 Rx processing : 0.25 PUSCH inner-receiver : 0.25 - Schedule Response : 1.00 DL & UL scheduling timing : 0.50 UL Indication : 1.00 Slot Indication : 0.50 diff --git a/ci-scripts/datalog_rt_stats.2x2.yaml b/ci-scripts/datalog_rt_stats.2x2.yaml index 7d489c171e..25009bad10 100644 --- a/ci-scripts/datalog_rt_stats.2x2.yaml +++ b/ci-scripts/datalog_rt_stats.2x2.yaml @@ -15,7 +15,6 @@ Ref : DLSCH encoding : 230.0 L1 Rx processing : 175.0 PUSCH inner-receiver : 100.0 - Schedule Response : 3.0 DL & UL scheduling timing : 11.0 UL Indication : 3.0 Slot Indication : 14.0 @@ -28,7 +27,6 @@ DeviationThreshold : DLSCH encoding : 0.25 L1 Rx processing : 0.25 PUSCH inner-receiver : 0.25 - Schedule Response : 1.00 DL & UL scheduling timing : 0.50 UL Indication : 1.00 Slot Indication : 0.25 diff --git a/ci-scripts/datalog_rt_stats.60.2x2.yaml b/ci-scripts/datalog_rt_stats.60.2x2.yaml index 7352136764..6df6fded54 100644 --- a/ci-scripts/datalog_rt_stats.60.2x2.yaml +++ b/ci-scripts/datalog_rt_stats.60.2x2.yaml @@ -15,7 +15,6 @@ Ref : DLSCH encoding : 140.0 L1 Rx processing : 345.0 PUSCH inner-receiver : 155.0 - Schedule Response : 1.0 DL & UL scheduling timing : 8.0 UL Indication : 3.0 Slot Indication : 9.0 @@ -31,7 +30,6 @@ DeviationThreshold : DLSCH encoding : 0.25 L1 Rx processing : 0.25 PUSCH inner-receiver : 0.25 - Schedule Response : 1.00 DL & UL scheduling timing : 0.35 UL Indication : 1.00 Slot Indication : 0.35 diff --git a/ci-scripts/datalog_rt_stats.default.yaml b/ci-scripts/datalog_rt_stats.default.yaml index be3f8b277e..65fd678b0f 100644 --- a/ci-scripts/datalog_rt_stats.default.yaml +++ b/ci-scripts/datalog_rt_stats.default.yaml @@ -15,7 +15,6 @@ Ref : DLSCH encoding : 90.0 L1 Rx processing : 290.0 PUSCH inner-receiver : 115.0 - Schedule Response : 1.0 DL & UL scheduling timing : 4.0 UL Indication : 2.0 Slot Indication : 5.0 @@ -31,7 +30,6 @@ DeviationThreshold : DLSCH encoding : 0.25 L1 Rx processing : 0.25 PUSCH inner-receiver : 0.25 - Schedule Response : 1.00 DL & UL scheduling timing : 0.50 UL Indication : 1.00 Slot Indication : 0.50 diff --git a/doc/Doxyfile b/doc/Doxyfile index 5f96bc2e4a..85cb5776c0 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -1916,8 +1916,6 @@ INPUT = \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/E1AP/e1ap_api.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/E1AP/e1ap_setup.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/E1AP/e1ap_asnc.h \ -@CMAKE_CURRENT_SOURCE_DIR@/../openair2/NR_PHY_INTERFACE/nr_sched_response.h \ -@CMAKE_CURRENT_SOURCE_DIR@/../openair2/NR_PHY_INTERFACE/nr_sched_response.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/NR_PHY_INTERFACE/NR_IF_Module.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/NR_PHY_INTERFACE/NR_IF_Module.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/SDAP/nr_sdap/nr_sdap.h \ @@ -2012,7 +2010,6 @@ INPUT = \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/NR_TRANSPORT/nr_transport_common_proto.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/NR_TRANSPORT/nr_sss.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/NR_TRANSPORT/nr_uci_tools_common.c \ -@CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/NR_TRANSPORT/nr_prach.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/NR_TRANSPORT/nr_scrambling.c \ @@ -2294,10 +2291,8 @@ INPUT = \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/SCHED_NR/phy_frame_config_nr.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/SCHED_NR/phy_frame_config_nr.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/SCHED_NR/nr_prach_procedures.c \ -@CMAKE_CURRENT_SOURCE_DIR@/../openair1/SCHED_NR/fapi_nr_l1.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/SCHED_NR/phy_procedures_nr_gNB.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/SCHED_NR/sched_nr.h \ -@CMAKE_CURRENT_SOURCE_DIR@/../openair1/SCHED_NR/fapi_nr_l1.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/SCHED_NR/nr_ru_procedures.c \ @CMAKE_CURRENT_SOURCE_DIR@/../radio/ETHERNET/if_defs.h \ @CMAKE_CURRENT_SOURCE_DIR@/../radio/ETHERNET/ethernet_lib.h \ diff --git a/executables/lte-softmodem.c b/executables/lte-softmodem.c index 0932702910..6ff535fb5b 100644 --- a/executables/lte-softmodem.c +++ b/executables/lte-softmodem.c @@ -194,10 +194,6 @@ void handle_nr_srs_measurements(const module_id_t module_id, void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]); /* TODO these declarations are to be removed */ -void nr_schedule_dl_tti_req(void) {}; -void nr_schedule_ul_dci_req() {}; -void nr_schedule_tx_req() {}; -void nr_schedule_ul_tti_req() {}; void nr_slot_select() {}; /*------------------------------------------------------------------------*/ diff --git a/executables/lte-uesoftmodem.c b/executables/lte-uesoftmodem.c index b212ceb3f1..f36bdde2b5 100644 --- a/executables/lte-uesoftmodem.c +++ b/executables/lte-uesoftmodem.c @@ -156,10 +156,6 @@ extern char uecap_xer[1024]; char uecap_xer_in=0; /* TODO these declarations are to be removed */ -void nr_schedule_dl_tti_req(void) {}; -void nr_schedule_ul_dci_req() {}; -void nr_schedule_tx_req() {}; -void nr_schedule_ul_tti_req() {}; void nr_slot_select() {}; /* see file openair2/LAYER2/MAC/main.c for why abstraction_flag is needed diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 1485b6de1d..94fc22cf46 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -55,7 +55,6 @@ #include "PHY/defs_gNB.h" #include "PHY/defs_nr_common.h" #include "PHY/impl_defs_nr.h" -#include "SCHED_NR/fapi_nr_l1.h" #include "SCHED_NR/phy_frame_config_nr.h" #include "SCHED_NR/sched_nr.h" #include "assertions.h" @@ -65,7 +64,6 @@ #include "nfapi/oai_integration/vendor_ext.h" #include "nfapi_nr_interface_scf.h" #include "notified_fifo.h" -#include "openair2/NR_PHY_INTERFACE/nr_sched_response.h" #include "thread-pool.h" #include "time_meas.h" #include "utils.h" @@ -251,7 +249,6 @@ static size_t dump_L1_meas_stats(PHY_VARS_gNB *gNB, RU_t *ru, char *output, size output += print_meas_log(&gNB->ul_indication_stats, "UL Indication", NULL, NULL, output, end - output); output += print_meas_log(&gNB->slot_indication_stats, "Slot Indication", NULL, NULL, output, end - output); output += print_meas_log(&gNB->rx_pusch_stats, "PUSCH inner-receiver", NULL, NULL, output, end - output); - output += print_meas_log(&gNB->schedule_response_stats, "Schedule Response", NULL, NULL, output, end - output); output += print_meas_log(&gNB->rx_prach, "PRACH RX", NULL, NULL, output, end - output); if (ru->feprx) output += print_meas_log(&ru->ofdm_demod_stats, "feprx", NULL, NULL, output, end - output); @@ -313,7 +310,6 @@ void *nrL1_stats_thread(void *param) { reset_meas(&gNB->ul_indication_stats); reset_meas(&gNB->slot_indication_stats); reset_meas(&gNB->rx_pusch_stats); - reset_meas(&gNB->schedule_response_stats); reset_meas(&gNB->dlsch_scrambling_stats); reset_meas(&gNB->dlsch_modulation_stats); reset_meas(&gNB->dlsch_resource_mapping_stats); @@ -361,12 +357,6 @@ void init_gNB_Tpool(int inst) // create the TX thread responsible for TX processing start event (L1_tx_out msg queue), then launch tx_func() threadCreate(&gNB->L1_tx_thread, L1_tx_thread, (void *)gNB, "L1_tx_thread", gNB->L1_tx_thread_core, OAI_PRIORITY_RT_MAX); - notifiedFIFO_elt_t *msgL1Tx = newNotifiedFIFO_elt(sizeof(processingData_L1tx_t), 0, &gNB->L1_tx_out, NULL); - processingData_L1tx_t *msgDataTx = (processingData_L1tx_t *)NotifiedFifoData(msgL1Tx); - memset(msgDataTx, 0, sizeof(processingData_L1tx_t)); - // this will be removed when the msgDataTx is not necessary anymore - gNB->msgDataTx = msgDataTx; - if (!IS_SOFTMODEM_NOSTATS) threadCreate(&proc->L1_stats_thread, nrL1_stats_thread, (void *)gNB, "L1_stats", -1, OAI_PRIORITY_RT_LOW); } @@ -443,7 +433,6 @@ void init_gNB() AssertFatal((gNB->if_inst = NR_IF_Module_init(inst)) != NULL, "Cannot register interface"); LOG_I(NR_PHY, "Registered with MAC interface module (%p)\n", gNB->if_inst); - gNB->if_inst->NR_Schedule_response = nr_schedule_response; gNB->if_inst->NR_PHY_config_req = nr_phy_config_request; gNB->prach_energy_counter = 0; diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index 0bd583662b..d7ca4a5e69 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -423,8 +423,6 @@ int start_L1L2(module_id_t gnb_id) /* block threads */ oai_exit = 0; sync_var = -1; - extern void init_sched_response(void); - init_sched_response(); /* update config */ gNB_MAC_INST *mac = RC.nrmac[0]; diff --git a/nfapi/oai_integration/nfapi_pnf.c b/nfapi/oai_integration/nfapi_pnf.c index 79c0d689c7..bb3ac8555b 100644 --- a/nfapi/oai_integration/nfapi_pnf.c +++ b/nfapi/oai_integration/nfapi_pnf.c @@ -55,7 +55,6 @@ #include "PHY/INIT/phy_init.h" #include "PHY/INIT/nr_phy_init.h" #include "PHY/LTE_TRANSPORT/transport_proto.h" -#include "openair1/SCHED_NR/fapi_nr_l1.h" #include "openair1/PHY/NR_TRANSPORT/nr_dlsch.h" #include "openair1/PHY/defs_gNB.h" #include @@ -1108,17 +1107,6 @@ void pnf_nr_phy_deallocate_p7_vendor_ext(void *header) free(header); } -extern void nr_schedule_ul_dci_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_dci_request_t *UL_dci_req); -int pnf_phy_ul_dci_req(gNB_L1_rxtx_proc_t *proc, nfapi_pnf_p7_config_t *pnf_p7, nfapi_nr_ul_dci_request_t *req) -{ - DevAssert(RC.gNB != NULL && RC.gNB[0] != NULL); - PHY_VARS_gNB *gNB = RC.gNB[0]; // phy_inst? - - nr_schedule_ul_dci_req(gNB, req); - - return 0; -} - int pnf_phy_hi_dci0_req(L1_rxtx_proc_t *proc, nfapi_pnf_p7_config_t *pnf_p7, nfapi_hi_dci0_request_t *req) { if (req->hi_dci0_request_body.number_of_dci == 0 && req->hi_dci0_request_body.number_of_hi == 0) @@ -1149,21 +1137,6 @@ int pnf_phy_hi_dci0_req(L1_rxtx_proc_t *proc, nfapi_pnf_p7_config_t *pnf_p7, nfa } -// from dl_tti_req_fn fptr -extern void nr_schedule_dl_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_dl_tti_request_t *DL_req); -int pnf_phy_dl_tti_req(gNB_L1_rxtx_proc_t *proc, nfapi_pnf_p7_config_t *pnf_p7, nfapi_nr_dl_tti_request_t *DL_req) -{ - DevAssert(proc == NULL); - DevAssert(sync_var == 0); - DevAssert(RC.gNB != NULL && RC.gNB[0] != NULL); - PHY_VARS_gNB *gNB = RC.gNB[0]; // phy_inst? - - nr_schedule_dl_tti_req(gNB, DL_req); - - return 0; -} - - int pnf_phy_dl_config_req(L1_rxtx_proc_t *proc, nfapi_pnf_p7_config_t *pnf_p7, nfapi_dl_config_request_t *req) { if (RC.eNB == 0) { @@ -1256,18 +1229,6 @@ int pnf_phy_dl_config_req(L1_rxtx_proc_t *proc, nfapi_pnf_p7_config_t *pnf_p7, n } -extern void nr_schedule_tx_req(PHY_VARS_gNB *gNB, nfapi_nr_tx_data_request_t *TX_req); -int pnf_phy_tx_data_req(nfapi_pnf_p7_config_t *pnf_p7, nfapi_nr_tx_data_request_t *req) -{ - DevAssert(RC.gNB != NULL && RC.gNB[0] != NULL); - PHY_VARS_gNB *gNB = RC.gNB[0]; // phy_inst? - - nr_schedule_tx_req(gNB, req); - - return 0; -} - - int pnf_phy_tx_req(nfapi_pnf_p7_config_t *pnf_p7, nfapi_tx_request_t *req) { uint16_t sfn = NFAPI_SFNSF2SFN(req->sfn_sf); uint16_t sf = NFAPI_SFNSF2SF(req->sfn_sf); @@ -1293,16 +1254,6 @@ int pnf_phy_tx_req(nfapi_pnf_p7_config_t *pnf_p7, nfapi_tx_request_t *req) { return 0; } -extern void nr_schedule_ul_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_tti_request_t *UL_tti_req); -int pnf_phy_ul_tti_req(gNB_L1_rxtx_proc_t *proc, nfapi_pnf_p7_config_t *pnf_p7, nfapi_nr_ul_tti_request_t *req) -{ - DevAssert(RC.gNB != NULL && RC.gNB[0] != NULL); - PHY_VARS_gNB *gNB = RC.gNB[0]; // phy_inst? - - nr_schedule_ul_tti_req(gNB, req); - return 0; -} - int pnf_phy_ul_config_req(L1_rxtx_proc_t *proc, nfapi_pnf_p7_config_t *pnf_p7, nfapi_ul_config_request_t *req) { if (0)LOG_D(PHY,"[PNF] UL_CONFIG_REQ %s() sfn_sf:%d pdu:%d rach_prach_frequency_resources:%d srs_present:%u\n", __FUNCTION__, @@ -1711,10 +1662,10 @@ int nr_start_request(nfapi_pnf_config_t *config, nfapi_pnf_phy_config_t *phy, nf } // NR - p7_config->dl_tti_req_fn = &pnf_phy_dl_tti_req; - p7_config->ul_tti_req_fn = &pnf_phy_ul_tti_req; - p7_config->ul_dci_req_fn = &pnf_phy_ul_dci_req; - p7_config->tx_data_req_fn = &pnf_phy_tx_data_req; + p7_config->dl_tti_req_fn = NULL; + p7_config->ul_tti_req_fn = NULL; + p7_config->ul_dci_req_fn = NULL; + p7_config->tx_data_req_fn = NULL; // LTE p7_config->dl_config_req = &pnf_phy_dl_config_req; diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c index 3fece46ac8..374ecb4b19 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c @@ -36,7 +36,6 @@ #include "PHY/NR_TRANSPORT/nr_ulsch.h" #include "PHY/NR_TRANSPORT/nr_dlsch.h" #include "SCHED_NR/sched_nr.h" -#include "SCHED_NR/fapi_nr_l1.h" #include "defs.h" #include "common/utils/LOG/vcd_signal_dumper.h" #include "common/utils/LOG/log.h" diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c index b23db3781d..1d9aa53d25 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c @@ -38,7 +38,6 @@ #include "PHY/NR_TRANSPORT/nr_transport_proto.h" #include "PHY/NR_TRANSPORT/nr_ulsch.h" #include "PHY/defs_gNB.h" -#include "SCHED_NR/fapi_nr_l1.h" #include "SCHED_NR/sched_nr.h" #include "common/utils/LOG/log.h" #include "common/utils/LOG/vcd_signal_dumper.h" diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index f744b441ab..5da6559937 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -39,7 +39,6 @@ #include #include "PHY/NR_TRANSPORT/nr_ulsch.h" #include "PHY/NR_REFSIG/nr_refsig.h" -#include "SCHED_NR/fapi_nr_l1.h" #include "PHY/NR_REFSIG/ul_ref_seq_nr.h" #include #include "nfapi/open-nFAPI/fapi/inc/nr_fapi_p5_utils.h" @@ -61,7 +60,6 @@ int l1_north_init_gNB() LOG_D(NR_PHY, "RC.gNB[%d]: installing callbacks\n", i); RC.gNB[i]->if_inst->NR_PHY_config_req = nr_phy_config_request; - RC.gNB[i]->if_inst->NR_Schedule_response = nr_schedule_response; } return 0; @@ -292,7 +290,6 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB) void install_nr_schedule_handlers(NR_IF_Module_t *if_inst) { if_inst->NR_PHY_config_req = nr_phy_config_request; - if_inst->NR_Schedule_response = nr_schedule_response; } void nr_phy_config_request_sim(PHY_VARS_gNB *gNB, diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.h b/openair1/PHY/NR_TRANSPORT/nr_dlsch.h index 443035274b..0a82b2c47f 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.h +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.h @@ -35,9 +35,6 @@ #include "PHY/defs_gNB.h" -void nr_fill_dlsch_dl_tti_req(processingData_L1tx_t *msgTx, nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu); -void nr_fill_dlsch_tx_req(processingData_L1tx_t *msgTx, int idx, uint8_t *sdu); - void nr_generate_pdsch(PHY_VARS_gNB *gNB, int n_dlsch, NR_gNB_DLSCH_t *dlsch_array, int frame, int slot); int nr_dlsch_encoding(PHY_VARS_gNB *gNB, diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c deleted file mode 100644 index 17766da629..0000000000 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file PHY/NR_TRANSPORT/nr_dlsch_tools.c -* \brief Top-level routines for decoding DLSCH transport channel from 38-214, V15.2.0 2018-06 -* \author Guy De Souza -* \date 2018 -* \version 0.1 -* \company Eurecom -* \email: desouza@eurecom.fr -* \note - -* \warning -*/ - -#include "nr_dlsch.h" -#include "../../../nfapi/oai_integration/vendor_ext.h" - -void nr_fill_dlsch_dl_tti_req(processingData_L1tx_t *msgTx, nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu) -{ - NR_gNB_DLSCH_t *dlsch = &msgTx->gNB->dlsch[msgTx->num_pdsch_slot]; - /// DLSCH struct - memcpy((void*)&dlsch->pdsch_pdu, (void*)pdsch_pdu, sizeof(nfapi_nr_dl_tti_pdsch_pdu)); - AssertFatal(msgTx->num_pdsch_slot == pdsch_pdu->pdsch_pdu_rel15.pduIndex, - "PDSCH PDU index %d does not match msgTx index %d\n", - pdsch_pdu->pdsch_pdu_rel15.pduIndex, - msgTx->num_pdsch_slot); - msgTx->num_pdsch_slot++; - dlsch->pdu = NULL; -} - -void nr_fill_dlsch_tx_req(processingData_L1tx_t *msgTx, int idx, uint8_t *sdu) -{ - AssertFatal(sdu != NULL, "sdu is null\n"); - - /* not sure if FAPI could transmit DL_TTI_req and TX_req in different orders. - * for the moment, assume they are in the same order (and check!) */ - NR_gNB_DLSCH_t *dlsch = &msgTx->gNB->dlsch[idx]; - const nfapi_nr_dl_tti_pdsch_pdu *pdsch = dlsch->pdsch_pdu; - AssertFatal(pdsch->pdsch_pdu_rel15.pduIndex == idx, "PDSCH PDU index %d does not match %d\n", pdsch->pdsch_pdu_rel15.pduIndex, idx); - dlsch->pdu = sdu; -} diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c index 239b6f2f29..24d4950dfa 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c @@ -35,7 +35,6 @@ #include "PHY/NR_TRANSPORT/nr_ulsch.h" #include "PHY/NR_TRANSPORT/nr_dlsch.h" #include "SCHED_NR/sched_nr.h" -#include "SCHED_NR/fapi_nr_l1.h" #include "defs.h" #include "common/utils/LOG/vcd_signal_dumper.h" #include "common/utils/LOG/log.h" diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index fdaae94b49..abc700f9d2 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -473,7 +473,6 @@ typedef struct PHY_VARS_gNB_s { time_stats_t rx_pusch_symbol_processing_stats; time_stats_t ul_indication_stats; time_stats_t slot_indication_stats; - time_stats_t schedule_response_stats; time_stats_t ulsch_decoding_stats; time_stats_t ts_deinterleave; time_stats_t ts_rate_unmatch; @@ -501,7 +500,6 @@ typedef struct PHY_VARS_gNB_s { int L1_rx_thread_core; pthread_t L1_tx_thread; int L1_tx_thread_core; - struct processingData_L1tx *msgDataTx; void *scopeData; } PHY_VARS_gNB; @@ -578,18 +576,6 @@ typedef struct processingData_L1tx { int slot_rx; openair0_timestamp timestamp_tx; PHY_VARS_gNB *gNB; - nfapi_nr_dl_tti_pdcch_pdu pdcch_pdu[NFAPI_NR_MAX_NB_CORESETS]; - /// corresponds to UL_dci_req->ul_dci_pdu_list - nfapi_nr_dl_tti_pdcch_pdu ul_pdcch_pdu[NFAPI_NR_MAX_NB_CORESETS]; - nfapi_nr_dl_tti_csi_rs_pdu csirs_pdu[NFAPI_NR_MAX_NB_CORESETS]; - nfapi_nr_dl_tti_ssb_pdu ssb_pdu[64]; - int n_ssb_pdu; - int n_csirs_pdu; - uint16_t num_pdsch_slot; - int num_dl_pdcch; - int num_ul_pdcch; - /* a reference to the sched_response, to release it when not needed anymore */ - int sched_response_id; } processingData_L1tx_t; typedef struct processingData_L1rx { diff --git a/openair1/SCHED_NR/fapi_nr_l1.c b/openair1/SCHED_NR/fapi_nr_l1.c deleted file mode 100644 index 0d122cedf5..0000000000 --- a/openair1/SCHED_NR/fapi_nr_l1.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file fapi_nr_l1.c - * \brief functions for FAPI L1 interface - * \author R. Knopp, WEI-TAI CHEN - * \date 2017, 2018 - * \version 0.1 - * \company Eurecom, NTUST - * \email: knopp@eurecom.fr, kroempa@gmail.com - * \note - * \warning - */ -#include "fapi_nr_l1.h" -#include "common/ran_context.h" -#include "PHY/NR_TRANSPORT/nr_transport_proto.h" -#include "PHY/NR_TRANSPORT/nr_dlsch.h" -#include "PHY/NR_TRANSPORT/nr_dci.h" -#include "nfapi/oai_integration/vendor_ext.h" -#include "openair2/NR_PHY_INTERFACE/nr_sched_response.h" -#include "nfapi/oai_integration/nfapi_vnf.h" - -static void handle_nr_nfapi_ssb_pdu(processingData_L1tx_t *msgTx, int frame, int slot, nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdu) -{ - - AssertFatal(dl_tti_pdu->ssb_pdu.ssb_pdu_rel15.bchPayloadFlag== 1, "bchPayloadFlat %d != 1\n", - dl_tti_pdu->ssb_pdu.ssb_pdu_rel15.bchPayloadFlag); - - uint8_t i_ssb = dl_tti_pdu->ssb_pdu.ssb_pdu_rel15.SsbBlockIndex; - - LOG_D(NR_PHY,"%d.%d : ssb index %d pbch_pdu: %x\n",frame,slot,i_ssb,dl_tti_pdu->ssb_pdu.ssb_pdu_rel15.bchPayload); - msgTx->ssb_pdu[msgTx->n_ssb_pdu++] = dl_tti_pdu->ssb_pdu; -} - -static void handle_nfapi_nr_csirs_pdu(processingData_L1tx_t *msgTx, int frame, int slot, nfapi_nr_dl_tti_csi_rs_pdu *csirs_pdu) -{ - msgTx->csirs_pdu[msgTx->n_csirs_pdu++] = *csirs_pdu; -} - -void nr_schedule_dl_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_dl_tti_request_t *DL_req) -{ - DevAssert(gNB != NULL); - DevAssert(DL_req != NULL); - nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config; - - int frame = DL_req->SFN; - int slot = DL_req->Slot; - - int slot_type = nr_slot_select(cfg, frame, slot); - DevAssert(slot_type == NR_DOWNLINK_SLOT || slot_type == NR_MIXED_SLOT); - - processingData_L1tx_t *msgTx = gNB->msgDataTx; - msgTx->slot = slot; - msgTx->frame = frame; - - uint8_t number_dl_pdu = DL_req->dl_tti_request_body.nPDUs; - - for (int i = 0; i < number_dl_pdu; i++) { - nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdu = &DL_req->dl_tti_request_body.dl_tti_pdu_list[i]; - LOG_D(NR_PHY, "NFAPI: dl_pdu %d : type %d\n", i, dl_tti_pdu->PDUType); - switch (dl_tti_pdu->PDUType) { - case NFAPI_NR_DL_TTI_SSB_PDU_TYPE: - handle_nr_nfapi_ssb_pdu(msgTx, frame, slot, dl_tti_pdu); - break; - - case NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE: - LOG_D(NR_PHY, "frame %d, slot %d, Got NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE for %d.%d\n", frame, slot, DL_req->SFN, DL_req->Slot); - msgTx->pdcch_pdu[msgTx->num_dl_pdcch] = dl_tti_pdu->pdcch_pdu; - msgTx->num_dl_pdcch++; - break; - - case NFAPI_NR_DL_TTI_CSI_RS_PDU_TYPE: - LOG_D(NR_PHY, "frame %d, slot %d, Got NFAPI_NR_DL_TTI_CSI_RS_PDU_TYPE for %d.%d\n", frame, slot, DL_req->SFN, DL_req->Slot); - handle_nfapi_nr_csirs_pdu(msgTx, frame, slot, &dl_tti_pdu->csi_rs_pdu); - break; - - case NFAPI_NR_DL_TTI_PDSCH_PDU_TYPE: - LOG_D(NR_PHY, "frame %d, slot %d, Got NFAPI_NR_DL_TTI_PDSCH_PDU_TYPE for %d.%d\n", frame, slot, DL_req->SFN, DL_req->Slot); - nr_fill_dlsch_dl_tti_req(msgTx, &dl_tti_pdu->pdsch_pdu); - } - } -} - -void nr_schedule_ul_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_tti_request_t *UL_tti_req) -{ - DevAssert(gNB != NULL); - DevAssert(UL_tti_req != NULL); - - int frame = UL_tti_req->SFN; - int slot = UL_tti_req->Slot; - - for (int i = 0; i < UL_tti_req->n_pdus; i++) { - int type = UL_tti_req->pdus_list[i].pdu_type; - LOG_D(NR_PHY, - "frame %d, slot %d got %s for %d.%d\n", - frame, - slot, - txt_nfapi_nr_ul_config_pdu_type[type], - UL_tti_req->SFN, - UL_tti_req->Slot); - switch (type) { - case NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE: - nr_fill_ulsch(gNB, UL_tti_req->SFN, UL_tti_req->Slot, &UL_tti_req->pdus_list[i].pusch_pdu); - break; - case NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE: - nr_fill_pucch(gNB, UL_tti_req->SFN, UL_tti_req->Slot, &UL_tti_req->pdus_list[i].pucch_pdu); - break; - case NFAPI_NR_UL_CONFIG_PRACH_PDU_TYPE: { - nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[i].prach_pdu; - prach_item_t *prach = nr_schedule_rx_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu); - if (!prach) - LOG_W(NR_PHY_RACH, "Error in scheduling rach\n"); - } break; - case NFAPI_NR_UL_CONFIG_SRS_PDU_TYPE: - nr_fill_srs(gNB, UL_tti_req->SFN, UL_tti_req->Slot, &UL_tti_req->pdus_list[i].srs_pdu); - break; - } - } -} - -void nr_schedule_tx_req(PHY_VARS_gNB *gNB, nfapi_nr_tx_data_request_t *TX_req) -{ - DevAssert(gNB != NULL); - DevAssert(TX_req != NULL); - processingData_L1tx_t *msgTx = gNB->msgDataTx; - - for (int idx = 0; idx < TX_req->Number_of_PDUs; ++idx) { - uint8_t *sdu = (uint8_t *)TX_req->pdu_list[idx].TLVs[0].value.direct; - nr_fill_dlsch_tx_req(msgTx, idx, sdu); - } -} - -void nr_schedule_ul_dci_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_dci_request_t *UL_dci_req) -{ - DevAssert(gNB != NULL); - DevAssert(UL_dci_req != NULL); - processingData_L1tx_t *msgTx = gNB->msgDataTx; - - msgTx->num_ul_pdcch = UL_dci_req->numPdus; - for (int i = 0; i < UL_dci_req->numPdus; i++) - msgTx->ul_pdcch_pdu[i] = UL_dci_req->ul_dci_pdu_list[i].pdcch_pdu; -} - -void nr_schedule_response(NR_Sched_Rsp_t *Sched_INFO) -{ - // copy data from L2 interface into L1 structures - module_id_t Mod_id = Sched_INFO->module_id; - frame_t frame = Sched_INFO->frame; - slot_t slot = Sched_INFO->slot; - - AssertFatal(RC.gNB != NULL, "RC.gNB is null\n"); - AssertFatal(RC.gNB[Mod_id] != NULL, "RC.gNB[%d] is null\n", Mod_id); - - PHY_VARS_gNB *gNB = RC.gNB[Mod_id]; - start_meas(&gNB->schedule_response_stats); - - nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config; - - int slot_type = nr_slot_select(cfg, frame, slot); - - clear_slot_beamid(gNB, slot); // reset beam_id information for the slot to be processed - DevAssert(NFAPI_MODE == NFAPI_MONOLITHIC); - bool is_dl = slot_type == NR_DOWNLINK_SLOT || slot_type == NR_MIXED_SLOT; - - processingData_L1tx_t *msgTx = gNB->msgDataTx; - /* store the sched_response_id for the TX thread to release it when done */ - msgTx->sched_response_id = Sched_INFO->sched_response_id; - - DevAssert(Sched_INFO->DL_req.SFN == frame); - DevAssert(Sched_INFO->DL_req.Slot == slot); - - if (is_dl) { - nr_schedule_dl_tti_req(gNB, &Sched_INFO->DL_req); - } - - nr_schedule_ul_tti_req(gNB, &Sched_INFO->UL_tti_req); - - if (is_dl) { - nr_schedule_tx_req(gNB, &Sched_INFO->TX_req); - - nr_schedule_ul_dci_req(gNB, &Sched_INFO->UL_dci_req); - /* Both the current thread and the TX thread will access the sched_info - * at the same time, so increase its reference counter, so that it is - * released only when both threads are done with it. - */ - inc_ref_sched_response(Sched_INFO->sched_response_id); - } - - /* this thread is done with the sched_info, decrease the reference counter */ - if ((slot_type == NR_DOWNLINK_SLOT || slot_type == NR_MIXED_SLOT) && NFAPI_MODE == NFAPI_MONOLITHIC) { - LOG_D(NR_PHY, "Calling dref_sched_response for id %d in %d.%d (sched_response)\n", Sched_INFO->sched_response_id, frame, slot); - deref_sched_response(Sched_INFO->sched_response_id); - } - stop_meas(&gNB->schedule_response_stats); -} diff --git a/openair1/SCHED_NR/fapi_nr_l1.h b/openair1/SCHED_NR/fapi_nr_l1.h deleted file mode 100644 index b8f1b6e238..0000000000 --- a/openair1/SCHED_NR/fapi_nr_l1.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file fapi_nr_l1.h - * \brief function prototypes for FAPI L1 interface - * \author R. Knopp, WEI-TAI CHEN - * \date 2017, 2018 - * \version 0.1 - * \company Eurecom, NTUST - * \email: knopp@eurecom.fr, kroempa@gmail.com - * \note - * \warning - */ - -#include "PHY/defs_gNB.h" -#include "SCHED_NR/sched_nr.h" -#include "nfapi_nr_interface_scf.h" - -void nr_schedule_response(NR_Sched_Rsp_t *Sched_INFO); diff --git a/openair1/SCHED_NR/nr_prach_procedures.c b/openair1/SCHED_NR/nr_prach_procedures.c index e6cd15b4a9..d5d6a8860e 100644 --- a/openair1/SCHED_NR/nr_prach_procedures.c +++ b/openair1/SCHED_NR/nr_prach_procedures.c @@ -33,7 +33,6 @@ #include "PHY/defs_gNB.h" #include "PHY/NR_TRANSPORT/nr_transport_proto.h" #include "nfapi_nr_interface_scf.h" -#include "fapi_nr_l1.h" #include "nfapi_pnf.h" #include "common/utils/LOG/log.h" #include "common/utils/LOG/vcd_signal_dumper.h" diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index eb4f1c8e84..8fab2bde81 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -27,7 +27,6 @@ #include "PHY/NR_TRANSPORT/nr_dci.h" #include "PHY/NR_ESTIMATION/nr_ul_estimation.h" #include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h" -#include "fapi_nr_l1.h" #include "common/utils/LOG/log.h" #include "common/utils/LOG/vcd_signal_dumper.h" #include "PHY/INIT/nr_phy_init.h" diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c index 9c53b50b76..18944a8099 100644 --- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c @@ -41,7 +41,6 @@ #include "nfapi/oai_integration/gnb_ind_vars.h" #include "nfapi/oai_integration/vendor_ext.h" #include "nfapi_interface.h" -#include "openair2/NR_PHY_INTERFACE/nr_sched_response.h" #include "openair2/PHY_INTERFACE/queue_t.h" #include "utils.h" #include "nfapi/oai_integration/nfapi_pnf.h" @@ -486,8 +485,6 @@ NR_IF_Module_t *NR_IF_Module_init(int Mod_id) { "allocation of nr_if_inst[%d]->if_mutex fails\n",Mod_id); } - init_sched_response(); - return nr_if_inst[Mod_id]; } diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.h b/openair2/NR_PHY_INTERFACE/NR_IF_Module.h index ca7e705f4a..49219a0af1 100644 --- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.h +++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.h @@ -122,7 +122,6 @@ typedef struct { typedef struct NR_IF_Module_s { //define the function pointer void (*NR_UL_indication)(NR_UL_IND_t *UL_INFO); - void (*NR_Schedule_response)(NR_Sched_Rsp_t *Sched_INFO); void (*NR_slot_indication)(const nfapi_nr_slot_indication_scf_t *ind, NR_Sched_Rsp_t *rsp); void (*NR_PHY_config_req)(NR_PHY_Config_t *config_INFO); uint32_t CC_mask; @@ -137,7 +136,4 @@ NR_IF_Module_t *NR_IF_Module_init(int Mod_id); void NR_IF_Module_kill(int Mod_id); -/*Interface for Downlink, transmitting the DLSCH SDU, DCI SDU*/ -void NR_Schedule_Response(NR_Sched_Rsp_t *Sched_INFO); - #endif /*_NFAPI_INTERFACE_NR_H_*/ diff --git a/openair2/NR_PHY_INTERFACE/nr_sched_response.c b/openair2/NR_PHY_INTERFACE/nr_sched_response.c deleted file mode 100644 index 9c66b21536..0000000000 --- a/openair2/NR_PHY_INTERFACE/nr_sched_response.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/* sched response memory management */ - -/* A system with reference counting is implemented. - * It is needed because several threads will access the structure, - * which has to be released only when all the threads are done with it. - * So the main thread allocates a sched_response with allocate_sched_response() - * which allocates a sched_response with a reference counter == 1 - * and then for each other thread that will access sched_response, a - * call to inc_ref_sched_response() is done. When a thread has finished - * using the sched_response, it calls deref_sched_response() which will - * in turn call release_sched_response() when the reference counter becomes 0. - * - * The several threads in question are accessing the _same_ sched_response, - * it has not to be confused with the various TX processes that may run in - * parallel and which are accessing _different_ sched_response (the maximum - * number of parallel processes is N_RESP). - */ - -#include "nr_sched_response.h" -#include -#include -#include -#include "NR_PHY_INTERFACE/NR_IF_Module.h" -#include "common/utils/LOG/log.h" -#include "common/utils/assertions.h" - -#define N_RESP 3 -static NR_Sched_Rsp_t resp[N_RESP]; -static int resp_refcount[N_RESP]; -static int resp_freelist_next[N_RESP]; -static int resp_freelist_head; -static pthread_mutex_t resp_mutex = PTHREAD_MUTEX_INITIALIZER; -static bool resp_freelist_inited = false; - -void init_sched_response(void) -{ - /* init only once */ - if (pthread_mutex_lock(&resp_mutex)) - AssertFatal(0, "pthread_mutex_lock failed\n"); - if (resp_freelist_inited) { - if (pthread_mutex_unlock(&resp_mutex)) - AssertFatal(0, "pthread_mutex_unlock failed\n"); - return; - } - resp_freelist_inited = true; - if (pthread_mutex_unlock(&resp_mutex)) - AssertFatal(0, "pthread_mutex_unlock failed\n"); - - int i; - for (i = 0; i < N_RESP - 1; i++) - resp_freelist_next[i] = i + 1; - resp_freelist_next[N_RESP - 1] = -1; - resp_freelist_head = 0; -} - -NR_Sched_Rsp_t *allocate_sched_response(void) -{ - NR_Sched_Rsp_t *ret; - int new_head; - - if (pthread_mutex_lock(&resp_mutex)) - AssertFatal(0, "pthread_mutex_lock failed\n"); - - AssertFatal(resp_freelist_inited, "sched_response used before init\n"); - - if (resp_freelist_head == -1) { - LOG_E(PHY, "fatal: sched_response cannot be allocated, increase N_RESP\n"); - exit(1); - } - - ret = &resp[resp_freelist_head]; - ret->sched_response_id = resp_freelist_head; - resp_refcount[resp_freelist_head] = 1; - - new_head = resp_freelist_next[resp_freelist_head]; - resp_freelist_next[resp_freelist_head] = -1; - resp_freelist_head = new_head; - - if (pthread_mutex_unlock(&resp_mutex)) - AssertFatal(0, "pthread_mutex_unlock failed\n"); - - return ret; -} - -static void release_sched_response(int sched_response_id) -{ - LOG_D(NR_MAC,"Releasing sched_response %d\n",sched_response_id); - resp_freelist_next[sched_response_id] = resp_freelist_head; - resp_freelist_head = sched_response_id; -} - -void deref_sched_response(int sched_response_id) -{ - /* simulators (ulsim/dlsim) deal with their own sched_response but call - * functions that call this one, let's handle this case with a special - * value -1 where we do nothing (yes it's a hack) - */ - if (sched_response_id == -1) - return; - - if (pthread_mutex_lock(&resp_mutex)) - AssertFatal(0, "pthread_mutex_lock failed\n"); - - AssertFatal(resp_freelist_inited, "sched_response used before init\n"); - AssertFatal(resp_refcount[sched_response_id] > 0, "sched_reponse decreased too much\n"); - - LOG_D(NR_MAC,"resp_refcount[%d] %d\n",sched_response_id,resp_refcount[sched_response_id]); - resp_refcount[sched_response_id]--; - if (resp_refcount[sched_response_id] == 0) - release_sched_response(sched_response_id); - - if (pthread_mutex_unlock(&resp_mutex)) - AssertFatal(0, "pthread_mutex_unlock failed\n"); -} - -void inc_ref_sched_response(int sched_response_id) -{ - /* simulators (ulsim/dlsim) deal with their own sched_response but call - * functions that call this one, let's handle this case with a special - * value -1 where we do nothing (yes it's a hack) - */ - if (sched_response_id == -1) - return; - - LOG_D(NR_MAC,"Incrementing sched_resp resp_refounct[%d] = %d\n", - sched_response_id,resp_refcount[sched_response_id]); - if (pthread_mutex_lock(&resp_mutex)) - AssertFatal(0, "pthread_mutex_lock failed\n"); - - AssertFatal(resp_freelist_inited, "sched_response used before init\n"); - - resp_refcount[sched_response_id]++; - - if (pthread_mutex_unlock(&resp_mutex)) - AssertFatal(0, "pthread_mutex_unlock failed\n"); -} diff --git a/openair2/NR_PHY_INTERFACE/nr_sched_response.h b/openair2/NR_PHY_INTERFACE/nr_sched_response.h deleted file mode 100644 index 33a0af93d0..0000000000 --- a/openair2/NR_PHY_INTERFACE/nr_sched_response.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -#ifndef OPENAIR2_NR_PHY_INTERFACE_NR_SCHED_RESPONSE_H -#define OPENAIR2_NR_PHY_INTERFACE_NR_SCHED_RESPONSE_H - -#include "NR_IF_Module.h" - -void init_sched_response(void); -NR_Sched_Rsp_t *allocate_sched_response(void); -void deref_sched_response(int sched_response_id); -void inc_ref_sched_response(int sched_response_id); - -#endif /* OPENAIR2_NR_PHY_INTERFACE_NR_SCHED_RESPONSE_H */ From c8fba9964f24b6aac635aaff86e9c279afa9cdef Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 10 Nov 2025 19:23:30 +0100 Subject: [PATCH 66/80] Remove dead code --- nfapi/oai_integration/nfapi_vnf.c | 1 - openair1/PHY/INIT/nr_init.c | 6 ------ openair1/SCHED/nfapi_lte_dummy.c | 2 -- 3 files changed, 9 deletions(-) diff --git a/nfapi/oai_integration/nfapi_vnf.c b/nfapi/oai_integration/nfapi_vnf.c index 6f73121c68..d5f644055a 100644 --- a/nfapi/oai_integration/nfapi_vnf.c +++ b/nfapi/oai_integration/nfapi_vnf.c @@ -124,7 +124,6 @@ int vnf_nr_unpack_vendor_extension_tlv(nfapi_tl_t *tl, { return -1; } -void install_nr_schedule_handlers(NR_IF_Module_t *if_inst); void install_schedule_handlers(IF_Module_t *if_inst); extern int sf_ahead; diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 5da6559937..eb584e4f8a 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -286,12 +286,6 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB) } -//Adding nr_schedule_handler -void install_nr_schedule_handlers(NR_IF_Module_t *if_inst) -{ - if_inst->NR_PHY_config_req = nr_phy_config_request; -} - void nr_phy_config_request_sim(PHY_VARS_gNB *gNB, int N_RB_DL, int N_RB_UL, diff --git a/openair1/SCHED/nfapi_lte_dummy.c b/openair1/SCHED/nfapi_lte_dummy.c index 3e56b51fc1..fa59cbdb71 100644 --- a/openair1/SCHED/nfapi_lte_dummy.c +++ b/openair1/SCHED/nfapi_lte_dummy.c @@ -29,8 +29,6 @@ void nr_schedule_rx_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_p void nr_phy_config_request(NR_PHY_Config_t *gNB){} -void install_nr_schedule_handlers(NR_IF_Module_t *if_inst){} - void nr_dump_frame_parms(NR_DL_FRAME_PARMS *fp){} bool vnf_nr_send_p5_msg(vnf_t *vnf, uint16_t p5_idx, nfapi_nr_p4_p5_message_header_t *msg, uint32_t msg_len) From aa3f01b6779f97753a82099d3b137934fbefa23d Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 10 Nov 2025 19:42:26 +0100 Subject: [PATCH 67/80] Delete dead code --- nfapi/oai_integration/nfapi_vnf.c | 91 +------------------------------ 1 file changed, 2 insertions(+), 89 deletions(-) diff --git a/nfapi/oai_integration/nfapi_vnf.c b/nfapi/oai_integration/nfapi_vnf.c index d5f644055a..b251d9d762 100644 --- a/nfapi/oai_integration/nfapi_vnf.c +++ b/nfapi/oai_integration/nfapi_vnf.c @@ -325,71 +325,6 @@ int pnf_config_resp_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_pnf_config_ return 0; } -int wake_gNB_rxtx(PHY_VARS_gNB *gNB, uint16_t sfn, uint16_t slot) { - struct timespec curr_t; - clock_gettime(CLOCK_MONOTONIC,&curr_t); - //NFAPI_TRACE(NFAPI_TRACE_INFO, "\n wake_gNB_rxtx before assignment sfn:%d slot:%d TIME %d.%d",sfn,slot,curr_t.tv_sec,curr_t.tv_nsec); - gNB_L1_proc_t *proc=&gNB->proc; - gNB_L1_rxtx_proc_t *L1_proc= (slot&1)? &proc->L1_proc : &proc->L1_proc_tx; - - NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; - //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s(eNB:%p, sfn:%d, sf:%d)\n", __FUNCTION__, eNB, sfn, sf); - //int i; - struct timespec wait; - clock_gettime(CLOCK_REALTIME, &wait); - wait.tv_sec = 0; - wait.tv_nsec +=5000L; - //wait.tv_nsec = 0; - // wake up TX for subframe n+sf_ahead - // lock the TX mutex and make sure the thread is ready - AssertFatal(gNB->if_inst->sl_ahead==6,"gNB->if_inst->sl_ahead %d : This is hard-coded to 6 in nfapi P7!!!\n",gNB->if_inst->sl_ahead); - if (pthread_mutex_timedlock(&L1_proc->mutex,&wait) != 0) { - LOG_E( PHY, "[gNB] ERROR pthread_mutex_lock for gNB RXTX thread %d (IC %d)\n", L1_proc->slot_rx&1,L1_proc->instance_cnt ); - exit_fun( "error locking mutex_rxtx" ); - return(-1); - } - - { - static uint16_t old_slot = 0; - static uint16_t old_sfn = 0; - proc->slot_rx = old_slot; - proc->frame_rx = old_sfn; - // Try to be 1 frame back - old_slot = slot; - old_sfn = sfn; - //NFAPI_TRACE(NFAPI_TRACE_INFO, "\n wake_gNB_rxtx after assignment sfn:%d slot:%d",proc->frame_rx,proc->slot_rx); - if (old_slot == 0 && old_sfn % 100 == 0) LOG_W( PHY,"[gNB] sfn/slot:%d%d old_sfn/slot:%d%d proc[rx:%d%d]\n", sfn, slot, old_sfn, old_slot, proc->frame_rx, proc->slot_rx); - } - - ++L1_proc->instance_cnt; - //LOG_D( PHY,"[VNF-subframe_ind] sfn/sf:%d:%d proc[frame_rx:%d subframe_rx:%d] L1_proc->instance_cnt_rxtx:%d \n", sfn, sf, proc->frame_rx, proc->subframe_rx, L1_proc->instance_cnt_rxtx); - // We have just received and processed the common part of a subframe, say n. - // TS_rx is the last received timestamp (start of 1st slot), TS_tx is the desired - // transmitted timestamp of the next TX slot (first). - // The last (TS_rx mod samples_per_frame) was n*samples_per_tti, - // we want to generate subframe (n+N), so TS_tx = TX_rx+N*samples_per_tti, - // and proc->subframe_tx = proc->subframe_rx+sf_ahead - L1_proc->timestamp_tx = proc->timestamp_rx + (gNB->if_inst->sl_ahead *fp->samples_per_subframe); - L1_proc->frame_rx = proc->frame_rx; - L1_proc->slot_rx = proc->slot_rx; - L1_proc->frame_tx = (L1_proc->slot_rx > (19-gNB->if_inst->sl_ahead)) ? (L1_proc->frame_rx+1)&1023 : L1_proc->frame_rx; - L1_proc->slot_tx = (L1_proc->slot_rx + gNB->if_inst->sl_ahead)%20; - - //LOG_D(PHY, "sfn/sf:%d%d proc[rx:%d%d] rx:%d%d] About to wake rxtx thread\n\n", sfn, slot, proc->frame_rx, proc->slot_rx, L1_proc->frame_rx, L1_proc->slot_rx); - //NFAPI_TRACE(NFAPI_TRACE_INFO, "\nEntering wake_gNB_rxtx sfn %d slot %d\n",L1_proc->frame_rx,L1_proc->slot_rx); - // the thread can now be woken up - if (pthread_cond_signal(&L1_proc->cond) != 0) { - LOG_E( PHY, "[gNB] ERROR pthread_cond_signal for gNB RXn-TXnp4 thread\n"); - exit_fun( "ERROR pthread_clond_signal" ); - return(-1); - } - - //LOG_D(PHY,"%s() About to attempt pthread_mutex_unlock\n", __FUNCTION__); - pthread_mutex_unlock( &L1_proc->mutex ); - //LOG_D(PHY,"%s() UNLOCKED pthread_mutex_unlock\n", __FUNCTION__); - return(0); -} - int wake_eNB_rxtx(PHY_VARS_eNB *eNB, uint16_t sfn, uint16_t sf) { L1_proc_t *proc=&eNB->proc; L1_rxtx_proc_t *L1_proc= (sf&1)? &proc->L1_proc : &proc->L1_proc_tx; @@ -497,28 +432,6 @@ int phy_sync_indication(struct nfapi_vnf_p7_config *config, uint8_t sync) { } -int phy_slot_indication(struct nfapi_vnf_p7_config *config, uint16_t phy_id, uint16_t sfn, uint16_t slot) { - static uint8_t first_time = 1; - - if (first_time) { - NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] slot indication %d.%d\n", sfn, slot); - first_time = 0; - } - - if (RC.gNB && RC.gNB[0]->configured) { - // uint16_t sfn = NFAPI_SFNSF2SFN(sfn_sf); - // uint16_t sf = NFAPI_SFNSF2SF(sfn_sf); - LOG_D(PHY,"[VNF] slot indication sfn:%d slot:%d\n", sfn, slot); - wake_gNB_rxtx(RC.gNB[0], sfn, slot); // DONE: find NR equivalent - } else { - NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] %s() RC.gNB:%p\n", __FUNCTION__, RC.gNB); - - if (RC.gNB) NFAPI_TRACE(NFAPI_TRACE_INFO, "RC.gNB[0]->configured:%d\n", RC.gNB[0]->configured); - } - - return 0; -} - int phy_subframe_indication(struct nfapi_vnf_p7_config *config, uint16_t phy_id, uint16_t sfn_sf) { static uint8_t first_time = 1; @@ -1302,7 +1215,7 @@ void *configure_nr_p7_vnf(void *ptr) p7_vnf->config->port = p7_vnf->local_port; #ifndef ENABLE_AERIAL p7_vnf->config->sync_indication = &phy_sync_indication; - p7_vnf->config->slot_indication = &phy_slot_indication; + p7_vnf->config->slot_indication = NULL; p7_vnf->config->harq_indication = &phy_harq_indication; #endif p7_vnf->config->nr_crc_indication = &phy_nr_crc_indication; @@ -1364,7 +1277,7 @@ void *vnf_p7_thread_start(void *ptr) { p7_vnf->config->port = p7_vnf->local_port; p7_vnf->config->sync_indication = &phy_sync_indication; p7_vnf->config->subframe_indication = &phy_subframe_indication; - p7_vnf->config->slot_indication = &phy_slot_indication; + p7_vnf->config->slot_indication = NULL; p7_vnf->config->harq_indication = &phy_harq_indication; p7_vnf->config->crc_indication = &phy_crc_indication; From 15441c741c48305c8f5fbf0e00f881c56791604d Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 14 Nov 2025 17:31:57 +0100 Subject: [PATCH 68/80] Cleanup: move slot_parameters to where they are used --- openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c index c1a4dd152d..f74685ed71 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c @@ -122,15 +122,6 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, nrLDPC_TB_encoding_parameters_t TBs[n_dlsch]; memset(TBs, 0, sizeof(TBs)); - nrLDPC_slot_encoding_parameters_t slot_parameters = {.frame = frame, - .slot = slot, - .nb_TBs = n_dlsch, - .threadPool = &gNB->threadPool, - .tinput = tinput, - .tprep = tprep, - .tparity = tparity, - .toutput = toutput, - .TBs = TBs}; int num_segments = 0; @@ -280,6 +271,15 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, dlsch_offset += ceil_mod(dlsch_size, 8 * 64); } + nrLDPC_slot_encoding_parameters_t slot_parameters = {.frame = frame, + .slot = slot, + .nb_TBs = n_dlsch, + .threadPool = &gNB->threadPool, + .tinput = tinput, + .tprep = tprep, + .tparity = tparity, + .toutput = toutput, + .TBs = TBs}; gNB->nrLDPC_coding_interface.nrLDPC_coding_encoder(&slot_parameters); for (int i = 0; i < n_dlsch; i++) { From 0713b2f655128d2d6a21e96aea4afb147d1603cb Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 4 Nov 2025 13:09:28 +0100 Subject: [PATCH 69/80] Rewrite doc/SW-archi-graph.md --- doc/SW-archi-graph.md | 165 ++++++++++++++++++++++++------------------ 1 file changed, 94 insertions(+), 71 deletions(-) diff --git a/doc/SW-archi-graph.md b/doc/SW-archi-graph.md index cf826e6e43..467ce5cd04 100644 --- a/doc/SW-archi-graph.md +++ b/doc/SW-archi-graph.md @@ -1,74 +1,97 @@ +This document is a high-level overview over the L1 threading mechanism. + ```mermaid flowchart TB - A[ru_thread] --> RFin>block rx_rf] --> feprx - feprx --> half-slot --> end_feprx - feprx --> second-thread -- block_end_feprx --> end_feprx>feprx] - end_feprx --> rx_nr_prach_ru -rx_nr_prach_ru -- block_queue_singleton --> resp_L1>resp L1] -resp_L1 -- async launch --> rx_func -resp_L1 -- immediate return --> RFin - -subgraph rxfunc -rx_func_implem[rx_func] - subgraph rxfuncbeg - handle_nr_slot_ind - --> rnti_to_remove-mgmt - --> L1_nr_prach_procedures - --> apply_nr_rotation_RX - end - subgraph phy_procedures_gNB_uespec_RX - fill_ul_rb_mask - --> pucch(decode each gNB->pucch) - -->nr_fill_ul_indication - --> nr_ulsch_procedures - --> nr_ulsch_decoding - --> segInParallel[[all segments decode in parallel]] - --> barrier_end_of_ulsch_decoding - end - subgraph NR_UL_indication - handle_nr_rach - --> handle_nr_uci - --> handle_nr_ulsch - subgraph gNB_dlsch_ulsch_scheduler - run_pdcp - --> schedule_xxxx - end - handle_nr_ulsch --> gNB_dlsch_ulsch_scheduler - subgraph NR_Schedule_response - L1_tx_free3>L1_tx_free] - --> handle_nr_nfapi_xxx_pdu - --> sendTxFilled((L1_tx_filled)) - --> nr_fill_ul_xxx - --> nr_schedule_rx_prach() - end - gNB_dlsch_ulsch_scheduler --> NR_Schedule_response - end - rx_func_implem --> rxfuncbeg - rxfuncbeg --> phy_procedures_gNB_uespec_RX -phy_procedures_gNB_uespec_RX --> NR_UL_indication --- block_queue_block_PNF_monolithic --> L1_tx_free2>L1 tx filled] --- async launch --> tx_func -L1_tx_free2 -- send_msg --> rsp((resp_L1)) -end -rx_func --> rxfunc - - -subgraph tx_func - direction LR - subgraph phy_procedures_gNB_TX - dcitop[nr_generate dci top] - --> nr_generate_csi_rs - --> apply_nr_rotation_TX - -- send_msg --> end_tx_func((L1_tx_out)) - end - subgraph tx_reorder_thread - L1_tx_out>L1_tx_out] - --> reorder{re order} --> reorder - reorder --> ru_tx_func - reorder --> L1_tx_free((L1_tx_free)) - ru_tx_func --> feptx_prec - --> feptx_ofdm - end -end - + ru_thread --> RFin[block rx_rf] --> UL{is UL slot?} + UL -- yes --> wait_free_rx_tti --> fep_rx --> rx_nr_prach_ru --> msg:L1_tx_out + UL -- no --> msg:L1_tx_out + msg:L1_tx_out -- asnyc launch --> L1_tx_thread + msg:L1_tx_out --> RFin ``` + +The main thread is `ru_thread()`. It blocks on reception of radio samples +(either time domain or frequency domain). In the case of an UL slot, it waits +that no more than N UL jobs are scheduled (via `wait_free_rx_tti()`, which +waits on queue `L1_rx_out`, cf. the RX L1 processing further below). Then: + +- if the radio is time domain-based, it performs RX front-end processing (RX + FEP -> `fep_rx()`, i.e. DFT) to reach a frequency domain representation of + the RX signal, as well as does DFT for PRACH. +- if the radio is frequency domain-based, nothing is done. + +Afterwards, it triggers TX processing by pushing a message into the FIFO queue +`L1_tx_out`, which asynchronously starts a TX job in `L1_tx_thread()` (see +below). After that, it blocks again on reception on the radio. + + +```mermaid +flowchart TB + L1_tx_thread --> TX_in[block L1_tx_out] --> NR_slot_indication + + subgraph tx_func + + NR_slot_indication --> msg:resp_L1 --> phy_procedures_gNB_tx --> ru_tx_func + NR_slot_indication["run the scheduler: + - monolithic: run_scheduler_monolithic() + - nFAPI: send indication via pnf_send_slot_ind()"] + msg:resp_L1 -- async launch --> L1_RX_thread + end + ru_tx_func --> TX_in +``` + +The `L1_tx_thread()` processes individual TX jobs sequentially, by waiting for +new messages on queue `L1_tx_out`, signalling individual TX jobs. For each +message, it calls `tx_func()` which does in order: + +- run the scheduler through `NR_slot_indication`, which corresponds to a + "Slot.indication" in FAPI parlance. This runs the scheduler, and schedules a + given slot (either downlink, uplink, or both). +- trigger RX processing by pushing a message into the FIFO queue `resp_L1`, + asynchronously starting an RX job in `L1_rx_thread()` (see below). +- process the current L1 TX job through `phy_procedures_gNB_tx()` +- write to the radio board via `ru_tx_func()`. + +After these steps, `tx_func()` return to `L1_tx_thread()`, which will wait for +the next TX job. + +```mermaid +flowchart TB + L1_rx_thread --> RX_in[block resp_L1] --> L1_nr_prach_proc + + subgraph rx_func + + L1_nr_prach_proc --> phase_comp{apply phase comp.?} + phase_comp -- yes --> apply_nr_rotation --> phy_procedures_gNB_uespec_RX + phase_comp -- no --> phy_procedures_gNB_uespec_RX + phy_procedures_gNB_uespec_RX --> NR_ul_indication --> msg:L1_rx_out + NR_ul_indication["run the scheduler: NR_UL_indication()"] + msg:L1_rx_out -- async signal free --> ru_thread + end + msg:L1_rx_out --> RX_in +``` + +The `L1_rx_thread()` processes individual RX jobs sequentially. It waits for a +new RX job through the queue `resp_L1`, and then calls `rx_func()`, which does +in order: + +- run PRACH processing via `L1_nr_prach_proc()` +- optionally apply rotation to the RX signal if phase compensation is to be + applied +- run the current L1 RX job through (`phy_procedures_gNB_uespec_RX()`), which + notably includes PUCCH, PUSCH, SRS processing +- call the scheduler through `NR_ul_indication()`, which corresponds to FAPI + uplink messages (e.g., `RX_data.indication`, `CRC.indication`, + `UCI.indication` etc.) +- signal completion via FIFO queue `L1_rx_out()`, which tells `ru_thread()` + that RX processing finished. + +The signalling of scheduler data is done through a variable `UL_INFO`, which is +filled by `L1_nr_prach_proc()` (for PRACH) and `phy_procedures_gNB_uespec_RX()` +(for PUCCH, PUSCH, SRS). + +After these steps, `rx_func()` returns to `L1_rx_thread()`, which will wait the +next RX job. + +Note that while individual TX (RX) jobs are run sequentially through +`L1_tx_thread()` (`L1_rx_thread()`), both TX and RX processing run in +parallel. From bd8f088ffa8a39d2f976faf569cf99c38e2092a4 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 11 Nov 2025 16:14:17 +0100 Subject: [PATCH 70/80] Update documentation FAPI --- doc/NR_NFAPI_archi.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/NR_NFAPI_archi.md b/doc/NR_NFAPI_archi.md index 8065ddb4fc..8e6647f73c 100644 --- a/doc/NR_NFAPI_archi.md +++ b/doc/NR_NFAPI_archi.md @@ -161,9 +161,9 @@ unpack function is called. ## P7 DL Transmission by VNF DL messages are scheduled at the VNF, through gNB_dlsch_ulsch_scheduler(). gNB_dlsch_ulsch_scheduler() is called when -handling a SLOT.indication message in trigger_scheduler(). +handling a SLOT.indication message in phy_nr_slot_indication(). -The function trigger_scheduler(nfapi_nr_slot_indication_scf_t *slot_ind) calls the functions oai_nfapi_[DL P7 msg]_ +The function phy_nr_slot_indication(nfapi_nr_slot_indication_scf_t *slot_ind) calls the functions oai_nfapi_[DL P7 msg]_ req(), calling in turn call the send_p7_msg function pointer, which contain the logic to pack the message into a buffer and send it to the PNF. Finally, NR_UL_indication is called to process the other P7 messages received from the PNF that were put in theire @@ -215,7 +215,7 @@ bool nfapi_vnf_p7_tx_data_req(nfapi_vnf_p7_config_t* config, nfapi_nr_tx_data_re graph TD softmodem_start[nr-softmodem init] --> P5_configuration[configure_nr_nfapi_vnf] --> transport_init[Transport mechanism init] --> send_first_msg[Send first P5 message to PNF] transport_init[Transport mechanism init] --> P5_recv_loop[P5 receive loop] -- P5 Message processing --> P5_recv_loop[P5 receive loop] - P5_recv_loop[P5 receive loop] -- Start.response callback called --> P7_config[P7 Configuration] --> P7_loop[P7 Loop] --> P7_msg_recv[P7 message received] --> call_vnf_handle_p7[Call vnf_nr_handle_p7_msg] --> hdr_unpack[Unpack header] --> call_specific_p7_handler[Call specific P7 message handler] --> slot_ind[Is a SLOT.indication?] -- Yes --> trig_scheduler[Call trigger_scheduler] --> gNB_ulsch_dlsch_sched[Call gNB_dlsch_ulsch_scheduler] --> send_p7_dl[Process and send P7 messages to PNF] --> call_ul_ind[Call NR_UL_indication] --> proc_p7[Process P7 messages in queue] --> P7_loop[P7 Loop] + P5_recv_loop[P5 receive loop] -- Start.response callback called --> P7_config[P7 Configuration] --> P7_loop[P7 Loop] --> P7_msg_recv[P7 message received] --> call_vnf_handle_p7[Call vnf_nr_handle_p7_msg] --> hdr_unpack[Unpack header] --> call_specific_p7_handler[Call specific P7 message handler] --> slot_ind[Is a SLOT.indication?] -- Yes --> trig_scheduler[Call phy_nr_slot_indication] --> gNB_ulsch_dlsch_sched[Call gNB_dlsch_ulsch_scheduler] --> send_p7_dl[Process and send P7 messages to PNF] --> call_ul_ind[Call NR_UL_indication] --> proc_p7[Process P7 messages in queue] --> P7_loop[P7 Loop] slot_ind[Is a SLOT.indication?] -- No --> put_queue[Put message in queue] --> P7_loop[P7 Loop]; From f5239f49b09e4d5d0f15dc472958c7c7a8d5ee46 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 15 Oct 2025 12:20:52 +0200 Subject: [PATCH 71/80] PDCP: Increase upper DRB ID limit --- openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c index 07edfb5814..f4dc5c1d5d 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c @@ -178,7 +178,7 @@ void nr_pdcp_ue_add_srb_pdcp_entity(nr_pdcp_ue_t *ue, int srb_id, nr_pdcp_entity /* must be called with lock acquired */ void nr_pdcp_ue_add_drb_pdcp_entity(nr_pdcp_ue_t *ue, int drb_id, nr_pdcp_entity_t *entity) { - if (drb_id < 1 || drb_id > 5) { + if (drb_id < 1 || drb_id > MAX_DRBS_PER_UE) { LOG_E(PDCP, "%s:%d:%s: fatal, bad drb id\n", __FILE__, __LINE__, __FUNCTION__); exit(1); } From a9ad90a26ace63c5ed5f79c2f5bbe0b955e12259 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 3 Nov 2025 09:54:10 +0100 Subject: [PATCH 72/80] Add FOR_EACH_SEQ_ARR to .clang-format --- .clang-format | 1 + 1 file changed, 1 insertion(+) diff --git a/.clang-format b/.clang-format index a7248821a9..3b0be979ba 100644 --- a/.clang-format +++ b/.clang-format @@ -62,6 +62,7 @@ ForEachMacros: - BOOST_FOREACH - RB_FOREACH - UE_iterator + - FOR_EACH_SEQ_ARR IncludeBlocks: Preserve IncludeCategories: - Regex: '^' From a58cf178edf8fa190def6f06d177bcc77275257b Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 17 Jun 2025 11:38:48 +0200 Subject: [PATCH 73/80] RRC PDU Session Release: end-to-end DRB and PDU session release This commit implements proper PDU Session Release handling across RRC, PDCP, F1AP, E1AP to ensure clean resource cleanup when a PDU session is terminated. Key changes: NGAP: In `rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND()`: * Populates E1AP Bearer Modification for each released session * If a CU-UP is connected, triggers `bearer_context_mod()` for PDU teardown PDCP: * Added `nr_pdcp_release_drbs()` to remove all DRBs linked to a given PDU session * Called from `e1_bearer_context_modif()` for correct clean-up during session release F1AP UE Context Modification: Replace direct RRC message transfer with F1AP UE Context Modification Request to properly handle PDU session release according to 3GPP TS 38.331. 3GPP TS 38.331 `5.3.5.6.4 DRB release` says: whether or not the RLC and MAC entities associated with a PDCP entity are reset or released is determined by the CellGroupConfig. Thus, updated CellGroupConfig needs to be received by the UE. This has to be retrieved by CUCP from the DU. Therefore: After receiving an NGAP_PDUSESSION_RELEASE_COMMAND, the CUCP shall: 1) forward (store for later) the NAS PDU to the UE, if present as per 3GPP TS 38.413, and 2) send a UE Context Modification to the DU with the list of DRBs to release and the RRC container (RRCReconfiguration with NAS PDU) After reception of UE Context Modification Response, the list of drbs to release is prepared based on PDU session status PDU_SESSION_STATUS_TORELEASE in rrc_gNB_generate_dedicatedRRCReconfiguration and then encoded in drb_ToReleaseList for a new RRCReconfiguration with the new cellGroupConfig. Key changes: * rrc_gNB_generate_dedicatedRRCReconfiguration_release() now uses F1AP UE Context Modification Request instead of direct RRC transfer * Only DRBs to be released are now added to the list. * The ASN.1 memory allocation is entirely done in build_RRCReconfiguration_IEs * No longer needed to store ASN1 struct in UE context GTP-U: * Previous implementation had incomplete tunnel cleanup during PDU session release - Missing distinction between N3 (PDU session level) and F1-U (DRB level) tunnels - Lack of proper DRB identification for F1-U tunnel deletion Major Changes: * GTP tunnel teardown now handled in `e1_bearer_context_modif()` using the correct F1 or N3 GTP instance (`newGtpuDeleteOneTunnel()`) * Enhanced Tunnel Deletion Logic (cucp_cuup_handler.c): - Separate handling for N3 tunnels (1 per PDU session) and F1-U tunnels (1 per DRB) - Added proper DRB identification for F1-U tunnel cleanup - Improved error handling with detailed logging for each tunnel deletion - Enhanced logging to distinguish between N3 and F1-U tunnel operations * New PDCP API Function (nr_pdcp_oai_api.c/h): - Added nr_pdcp_get_drb_ids_for_pdusession() function - Enables retrieval of all DRB IDs associated with a specific PDU session - Supports proper F1-U tunnel cleanup by providing DRB identifiers in CUUP * Enhanced GTP Interface (gtp_itf.cpp/h): - Modified newGtpuDeleteOneTunnel() to accept tunnel_type parameter - Improved logging to distinguish between PDU session and DRB tunnel types - Better error messages for tunnel deletion failures - Enhanced debugging information for remaining tunnels Clean-up: * Ensured xid tracking works consistently between PDU Session Establishment (with NAS PDU) and dedicated RRCReconfiguration * Add function to release GTP-U tunnel in Bearer Context Modification Request handler * Do not send rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE when no PDU session are to be released: it is sent upon completion of the RRCReconfiguration and needs to contain released PDU Sessions (mandatory IE), therefore it is no necessary to send it in case there is no PDU session to release. Related to #867 Co-authored-by: rmagueta --- .../LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 5 +- openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c | 55 +++++++- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c | 24 ++++ openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h | 1 + openair2/RRC/NR/MESSAGES/asn1_msg.c | 8 +- openair2/RRC/NR/MESSAGES/asn1_msg.h | 3 +- .../RRC/NR/MESSAGES/tests/test_asn1_msg.cpp | 1 - openair2/RRC/NR/nr_rrc_defs.h | 2 - openair2/RRC/NR/nr_rrc_proto.h | 6 - openair2/RRC/NR/rrc_gNB.c | 128 +++++++++++------- openair2/RRC/NR/rrc_gNB_NGAP.c | 48 ++++--- openair2/SDAP/nr_sdap/nr_sdap_entity.c | 5 +- openair3/ocp-gtpu/gtp_itf.cpp | 6 +- 13 files changed, 195 insertions(+), 97 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 064857a8e3..5a982df256 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -381,12 +381,9 @@ static int handle_ue_context_drbs_release(NR_UE_info_t *UE, { DevAssert(req_drbs != NULL && cellGroupConfig != NULL); instance_t f1inst = get_f1_gtp_instance(); - cellGroupConfig->rlc_BearerToReleaseList = calloc(1, sizeof(*cellGroupConfig->rlc_BearerToReleaseList)); AssertFatal(cellGroupConfig->rlc_BearerToReleaseList != NULL, "out of memory\n"); - /* Note: the actual GTP tunnels are already removed in the F1AP message - * decoding */ for (int i = 0; i < drbs_len; i++) { const f1ap_drb_to_release_t *drb = &req_drbs[i]; @@ -401,7 +398,7 @@ static int handle_ue_context_drbs_release(NR_UE_info_t *UE, if (idx < cellGroupConfig->rlc_BearerToAddModList->list.count) { nr_mac_remove_lcid(&UE->UE_sched_ctrl, lcid); nr_rlc_release_entity(UE->rnti, lcid); - if (f1inst >= 0) + if (f1inst >= 0) /* Delete F1 tunnel */ newGtpuDeleteOneTunnel(f1inst, UE->rnti, drb->id); asn_sequence_del(&cellGroupConfig->rlc_BearerToAddModList->list, idx, 1); long *plcid = malloc(sizeof(*plcid)); diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c index 4b95963257..ecdf3dfd72 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -259,17 +259,58 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) get_e1_if()->bearer_setup_response(&resp); } +static void release_gtpu_tunnel(uint32_t ue_id, int pdusession_id) +{ + instance_t n3inst = get_n3_gtp_instance(); + + // Handle N3 tunnel (1 tunnel per PDU session) + if (n3inst >= 0) { + LOG_I(E1AP, "UE %u: Deleting N3 tunnel for PDU session %d\n", ue_id, pdusession_id); + int result = newGtpuDeleteOneTunnel(n3inst, ue_id, pdusession_id); + if (result == GTPNOK) { + LOG_E(E1AP, "UE %u: Failed to delete N3 tunnel for PDU session %d\n", ue_id, pdusession_id); + } + } +} + +static void release_f1_drbs(uint32_t ue_id, int pdusession_id) +{ + instance_t f1inst = get_f1_gtp_instance(); + // Handle F1 tunnels (1 tunnel per DRB, fetch PDCP entities and get DRB IDs) + int drb_ids[MAX_DRBS_PER_UE]; + int n_drbs = nr_pdcp_get_drb_ids_for_pdusession(ue_id, pdusession_id, drb_ids); + if (n_drbs > 0) { + LOG_I(E1AP, "UE %u: Deleting %d F1 tunnels for PDU session %d\n", ue_id, n_drbs, pdusession_id); + // Delete each F1 tunnel using the DRB IDs + for (int i = 0; i < n_drbs; i++) { + int drb_id = drb_ids[i]; + if (f1inst >= 0) { + int result = newGtpuDeleteOneTunnel(f1inst, ue_id, drb_id); + if (result == GTPNOK) { + LOG_E(E1AP, "UE %u: Failed to delete F1 tunnel for DRB %d\n", ue_id, drb_id); + } + } + // Release PDCP entity + nr_pdcp_release_drb(ue_id, drb_id); + } + } else { + LOG_W(E1AP, "UE %u: No DRBs found for PDU session %d\n", ue_id, pdusession_id); + } +} + /** * @brief Fill Bearer Context Modification Response and send to callback */ void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) { - AssertFatal(req->numPDUSessionsMod > 0, "need at least one PDU session to modify\n"); + AssertFatal(req->numPDUSessionsMod > 0 || req->numPDUSessionsRem > 0, + "need at least one PDU session to modify or release (mod=%u, rel=%u)\n", + req->numPDUSessionsMod, + req->numPDUSessionsRem); e1ap_bearer_modif_resp_t modif = { .gNB_cu_cp_ue_id = req->gNB_cu_cp_ue_id, .gNB_cu_up_ue_id = req->gNB_cu_up_ue_id, - .numPDUSessionsMod = req->numPDUSessionsMod, }; instance_t f1inst = get_f1_gtp_instance(); @@ -284,6 +325,7 @@ void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) req->pduSessionMod[i].numDRB2Modify); modif.pduSessionMod[i].id = req->pduSessionMod[i].sessionId; modif.pduSessionMod[i].numDRBModified = req->pduSessionMod[i].numDRB2Modify; + modif.numPDUSessionsMod++; /* DRBs to modify */ for (int j = 0; j < req->pduSessionMod[i].numDRB2Modify; j++) { const DRB_nGRAN_to_mod_t *to_modif = &req->pduSessionMod[i].DRBnGRanModList[j]; @@ -347,6 +389,15 @@ void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) } } + /* PDU Session Resource To Remove List (see 9.3.3.12 of TS 38.463) */ + for (int i = 0; i < req->numPDUSessionsRem; i++) { + modif.pduSessionMod[i].id = req->pduSessionRem[i].sessionId; + modif.numPDUSessionsMod++; + release_gtpu_tunnel(req->gNB_cu_up_ue_id, req->pduSessionRem[i].sessionId); + release_f1_drbs(req->gNB_cu_up_ue_id, req->pduSessionRem[i].sessionId); + nr_sdap_delete_entity(req->gNB_cu_up_ue_id, req->pduSessionRem[i].sessionId); + } + get_e1_if()->bearer_modif_response(&modif); } diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index 94d44fe8ce..3fd4c4bdd4 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -653,6 +653,30 @@ void nr_pdcp_add_srbs(eNB_flag_t enb_flag, LOG_W(PDCP, "nr_pdcp_add_srbs() with void list\n"); } +/** @brief Get DRB IDs for a specific PDU session */ +int nr_pdcp_get_drb_ids_for_pdusession(ue_id_t ue_id, long pdusession_id, int *drb_ids) +{ + int num_found = 0; + nr_pdcp_manager_lock(nr_pdcp_ue_manager); + nr_pdcp_ue_t *ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, ue_id); + if (ue) { + for (int i = 0; i < MAX_DRBS_PER_UE; i++) { + nr_pdcp_entity_t *drb = ue->drb[i]; + if (drb && drb->pdusession_id == pdusession_id) { + if (num_found < MAX_DRBS_PER_UE) { + drb_ids[num_found] = drb->rb_id; + num_found++; + } else { + LOG_W(PDCP, "Found more DRBs than MAX_DRBS_PER_UE=%d\n", MAX_DRBS_PER_UE); + break; + } + } + } + } + nr_pdcp_manager_unlock(nr_pdcp_ue_manager); + return num_found; +} + uint64_t get_pdcp_optmask(void) { return pdcp_optmask; diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h index 884ea11f60..75435ed695 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h @@ -66,6 +66,7 @@ void nr_pdcp_reconfigure_srb(ue_id_t ue_id, int srb_id, long t_Reordering); void nr_pdcp_reconfigure_drb(ue_id_t ue_id, int drb_id, NR_PDCP_Config_t *pdcp_config); void nr_pdcp_release_srb(ue_id_t ue_id, int srb_id); void nr_pdcp_release_drb(ue_id_t ue_id, int drb_id); +int nr_pdcp_get_drb_ids_for_pdusession(ue_id_t ue_id, long pdusession_id, int *drb_ids); void add_srb(int is_gnb, ue_id_t UEid, diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 2136e966ab..585b1e48e2 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -519,7 +519,13 @@ static NR_RRCReconfiguration_IEs_t *build_RRCReconfiguration_IEs(const nr_rrc_re cfg->drb_ToAddModList = params->drb_config_list; cfg->securityConfig = params->security_config; cfg->srb3_ToRelease = NULL; - cfg->drb_ToReleaseList = params->drb_release_list; + if (params->n_drb_rel) { + asn1cCalloc(cfg->drb_ToReleaseList, to_release); + for (int i = 0; i < params->n_drb_rel; i++) { + asn1cSequenceAdd(to_release->list, NR_DRB_Identity_t, DRB_release); + *DRB_release = params->drb_rel[i]; + } + } } /* measConfig */ diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index 48a0ea734b..eb8da91c2a 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -64,7 +64,8 @@ typedef struct { uint8_t transaction_id; NR_SRB_ToAddModList_t *srb_config_list; NR_DRB_ToAddModList_t *drb_config_list; - NR_DRB_ToReleaseList_t *drb_release_list; + int *drb_rel; + int n_drb_rel; NR_SecurityConfig_t *security_config; NR_MeasConfig_t *meas_config; byte_array_t dedicated_NAS_msg_list[MAX_DRBS_PER_UE]; diff --git a/openair2/RRC/NR/MESSAGES/tests/test_asn1_msg.cpp b/openair2/RRC/NR/MESSAGES/tests/test_asn1_msg.cpp index 1f92c5aae5..025978218e 100644 --- a/openair2/RRC/NR/MESSAGES/tests/test_asn1_msg.cpp +++ b/openair2/RRC/NR/MESSAGES/tests/test_asn1_msg.cpp @@ -88,7 +88,6 @@ TEST(nr_asn1, paging) void free_RRCReconfiguration_params(nr_rrc_reconfig_param_t params) { ASN_STRUCT_FREE(asn_DEF_NR_MeasConfig, params.meas_config); - ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToReleaseList, params.drb_release_list); ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList, params.drb_config_list); ASN_STRUCT_FREE(asn_DEF_NR_SRB_ToAddModList, params.srb_config_list); ASN_STRUCT_FREE(asn_DEF_NR_SecurityConfig, params.security_config); diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 27e17e03f0..e8820bcc76 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -167,8 +167,6 @@ typedef struct nr_handover_context_s nr_handover_context_t; typedef struct gNB_RRC_UE_s { time_t last_seen; // last time this UE has been accessed - NR_DRB_ToReleaseList_t *DRB_ReleaseList; - NR_SRB_INFO_TABLE_ENTRY Srb[NR_NUM_SRB]; NR_MeasConfig_t *measConfig; nr_handover_context_t *ho_context; diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 777ea9a8d1..2fc7bf5e5e 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -66,12 +66,6 @@ void *rrc_gnb_task(void *args_p); int nr_rrc_reconfiguration_req(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p, const int dl_bwp_id, const int ul_bwp_id); -void rrc_gNB_generate_dedicatedRRCReconfiguration_release(gNB_RRC_INST *rrc, - gNB_RRC_UE_t *ue_p, - uint8_t xid, - uint32_t nas_length, - uint8_t *nas_buffer); - NR_MeasConfig_t *nr_rrc_get_measconfig(const gNB_RRC_INST *rrc, uint64_t nr_cellid); bool ue_associated_to_cuup(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index bc4cca38f1..1e08c9cf25 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -629,10 +629,10 @@ static NR_ReportConfigToAddMod_t *prepare_a3_event_report(const nr_a3_event_t *a void free_RRCReconfiguration_params(nr_rrc_reconfig_param_t params) { - ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToReleaseList, params.drb_release_list); ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList, params.drb_config_list); ASN_STRUCT_FREE(asn_DEF_NR_SRB_ToAddModList, params.srb_config_list); ASN_STRUCT_FREE(asn_DEF_NR_SecurityConfig, params.security_config); + free(params.drb_rel); for (int i = 0; i < params.num_nas_msg; i++) FREE_AND_ZERO_BYTE_ARRAY(params.dedicated_NAS_msg_list[i]); } @@ -710,19 +710,37 @@ nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, gNB_RRC nr_rrc_reconfig_param_t params = {.cell_group_config = UE->masterCellGroup, .transaction_id = xid, .drb_config_list = DRBs, - .drb_release_list = UE->DRB_ReleaseList, .meas_config = UE->measConfig, .srb_config_list = SRBs}; - UE->DRB_ReleaseList = NULL; // pointer transferred to params FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, item, &UE->pduSessions) { pdusession_t *session = &item->param; + // Collect NAS PDUs if (session->nas_pdu.len > 0) { params.dedicated_NAS_msg_list[params.num_nas_msg++] = session->nas_pdu; session->nas_pdu.buf = NULL; session->nas_pdu.len = 0; LOG_D(NR_RRC, "Transfer NAS info with size %ld to RRCReconfiguration params\n", session->nas_pdu.len); } + // Collect DRBs to release for PDU sessions marked for release + if (item->status == PDU_SESSION_STATUS_TORELEASE) { + if (!params.drb_rel) + params.drb_rel = calloc_or_fail(MAX_DRBS_PER_UE, sizeof(int)); + FOR_EACH_SEQ_ARR (drb_t *, drb, &UE->drbs) { + if (drb->pdusession_id == session->pdusession_id) { + if (params.n_drb_rel >= MAX_DRBS_PER_UE) { + LOG_E(NR_RRC, "UE %d: Too many DRBs to release (max %d)\n", UE->rrc_ue_id, MAX_DRBS_PER_UE); + break; + } + params.drb_rel[params.n_drb_rel++] = drb->drb_id; + LOG_D(NR_RRC, + "UE %d: Added DRB %d to release list for PDU session %d\n", + UE->rrc_ue_id, + drb->drb_id, + session->pdusession_id); + } + } + } } if (UE->nas_pdu.len > 0) { @@ -750,21 +768,24 @@ static void rrc_gNB_generate_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_ { /* do not re-establish PDCP for any bearer */ nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, ue_p, 0, false); - ue_p->xids[params.transaction_id] = RRC_PDUSESSION_ESTABLISH; + FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, item, &ue_p->pduSessions) { + if (item->status == PDU_SESSION_STATUS_NEW) { + item->status = PDU_SESSION_STATUS_DONE; + continue; + } + // Set xid for all PDU sessions + item->xid = params.transaction_id; + } + + // Set xid for RRC transaction + ue_p->xids[params.transaction_id] = params.n_drb_rel > 0 ? RRC_PDUSESSION_RELEASE : RRC_PDUSESSION_ESTABLISH; + byte_array_t msg = rrc_gNB_encode_RRCReconfiguration(rrc, ue_p, params); if (msg.len <= 0) { LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", ue_p->rrc_ue_id); return; } - FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, item, &ue_p->pduSessions) { - if (item->param.nas_pdu.buf) - item->xid = params.transaction_id; - if (item->status < PDU_SESSION_STATUS_ESTABLISHED) { - item->status = PDU_SESSION_STATUS_DONE; - } - } - LOG_UE_DL_EVENT(ue_p, "Generate RRCReconfiguration (bytes %ld, xid %d)\n", msg.len, params.transaction_id); const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, msg.buf, msg.len); @@ -835,44 +856,27 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t free_byte_array(msg); } -//----------------------------------------------------------------------------- -void rrc_gNB_generate_dedicatedRRCReconfiguration_release(gNB_RRC_INST *rrc, - gNB_RRC_UE_t *ue_p, - uint8_t xid, - uint32_t nas_length, - uint8_t *nas_buffer) -//----------------------------------------------------------------------------- +static void rrc_gNB_send_f1_drb_release_request(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p, int *drb_to_release, int n_drb_to_release) { - nr_rrc_reconfig_param_t params = {.transaction_id = xid}; + f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id); + RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); + f1ap_ue_context_mod_req_t req = { + .gNB_CU_ue_id = ue_p->rrc_ue_id, + .gNB_DU_ue_id = ue_data.secondary_ue, + .servCellIndex = 0, + }; + req.plmn = malloc_or_fail(sizeof(*req.plmn)); + *req.plmn = rrc->configuration.plmn[0]; + req.nr_cellid = malloc_or_fail(sizeof(*req.nr_cellid)); + *req.nr_cellid = rrc->nr_cellid; + req.drbs_rel = malloc_or_fail(sizeof(*req.drbs_rel)); + req.drbs_rel_len = n_drb_to_release; + memcpy(req.drbs_rel, drb_to_release, n_drb_to_release * sizeof(int)); - NR_DRB_ToReleaseList_t *to_release = CALLOC(sizeof(*to_release), 1); - FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, item, &ue_p->pduSessions) { - if ((item->status != PDU_SESSION_STATUS_TORELEASE) && item->xid != xid) - continue; - FOR_EACH_SEQ_ARR(drb_t *, drb, &ue_p->drbs) { - if (drb->pdusession_id == item->param.pdusession_id) { - asn1cSequenceAdd(to_release->list, NR_DRB_Identity_t, DRB_release); - *DRB_release = drb->drb_id; // DRB ID - } - } - } - params.drb_release_list = to_release; - - if (nas_length > 0) { - params.dedicated_NAS_msg_list[params.num_nas_msg].buf = nas_buffer; - params.dedicated_NAS_msg_list[params.num_nas_msg++].len = nas_length; - } - byte_array_t msg = do_RRCReconfiguration(¶ms); - if (msg.len <= 0) { - LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", ue_p->rrc_ue_id); - return; - } - LOG_DUMPMSG(NR_RRC, DEBUG_RRC, msg.buf, msg.len, "[MSG] RRC Reconfiguration\n"); - LOG_I(NR_RRC, "UE %d: Generate NR_RRCReconfiguration (bytes %ld)\n", ue_p->rrc_ue_id, msg.len); - const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; - nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, msg.buf, msg.len); - free_RRCReconfiguration_params(params); - free_byte_array(msg); + /* send UE Context Modification to DU without attaching any RRC container */ + rrc->mac_rrc.ue_context_modification_request(ue_data.du_assoc_id, &req); + LOG_I(NR_RRC, "UE %d: send F1 UE Context Modification Request with DRB release (%d DRBs)\n", ue_p->rrc_ue_id, req.drbs_rel_len); + free_ue_context_mod_req(&req); } static void fill_security_info(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, security_information_t *secInfo) @@ -1851,9 +1855,6 @@ static void handle_rrcReconfigurationComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *U switch (UE->xids[xid]) { case RRC_PDUSESSION_RELEASE: { - gtpv1u_gnb_delete_tunnel_req_t req = {0}; - gtpv1u_delete_ngu_tunnel(rrc->module_id, &req); - // NGAP_PDUSESSION_RELEASE_RESPONSE rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE(rrc, UE, xid); } break; case RRC_PDUSESSION_ESTABLISH: @@ -2732,15 +2733,19 @@ void rrc_gNB_process_e1_bearer_context_setup_failure(e1ap_bearer_context_setup_f */ void rrc_gNB_process_e1_bearer_context_modif_resp(const e1ap_bearer_modif_resp_t *resp) { + LOG_I(NR_RRC, "Received E1AP Bearer Context Modification Response for UE CU-CP ID %d\n", resp->gNB_cu_cp_ue_id); gNB_RRC_INST *rrc = RC.nrrrc[0]; rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, resp->gNB_cu_cp_ue_id); if (ue_context_p == NULL) { LOG_E(RRC, "no UE with CU-CP UE ID %d found\n", resp->gNB_cu_cp_ue_id); return; } + gNB_RRC_UE_t *ue = &ue_context_p->ue_context; int n_drb_mod = 0; int drb_ids[MAX_DRBS_PER_UE] = {0}; + int drb_to_release[MAX_DRBS_PER_UE] = {0}; + int n_drb_to_release = 0; e1_pdcp_status_info_t pdcp_status[MAX_DRBS_PER_UE] = {0}; for (int i = 0; i < resp->numPDUSessionsMod; ++i) { const pdu_session_modif_t *pdu = &resp->pduSessionMod[i]; @@ -2753,13 +2758,32 @@ void rrc_gNB_process_e1_bearer_context_modif_resp(const e1ap_bearer_modif_resp_t pdcp_status[n_drb_mod++] = *pdu->DRBnGRanModList[j].pdcp_status; } } + // Collect DRBs to release for PDU sessions marked for release + rrc_pdu_session_param_t *pdu_session = find_pduSession(&ue->pduSessions, pdu->id); + if (pdu_session && pdu_session->status == PDU_SESSION_STATUS_TORELEASE) { + FOR_EACH_SEQ_ARR(drb_t *, drb, &ue->drbs) { + if (drb->pdusession_id == pdu->id) { + DevAssert(n_drb_to_release < MAX_DRBS_PER_UE); + drb_to_release[n_drb_to_release++] = drb->drb_id; + } + } + if (n_drb_to_release == 0) { + LOG_E(NR_RRC, "UE %d: no DRBs to release for PDU session %ld\n", ue->rrc_ue_id, pdu->id); + } + } } + if (n_drb_mod) { LOG_I(NR_RRC, "UE %d: received PDU Status Info - send UL RAN Status Transfer\n", resp->gNB_cu_cp_ue_id); - gNB_RRC_UE_t *ue = &ue_context_p->ue_context; if (ue->ho_context && ue->ho_context->source) ue->ho_context->source->ho_status_transfer(rrc, ue, n_drb_mod, drb_ids, pdcp_status); } + + // Send F1 UE Context Modification Request with DRB release + if (n_drb_to_release) { + LOG_I(NR_RRC, "Send F1 UE Context Modification Request with DRB to release\n"); + rrc_gNB_send_f1_drb_release_request(rrc, ue, drb_to_release, n_drb_to_release); + } } /** @brief E1AP Bearer Context Modification Failure processing on CU-CP */ diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 3b30341371..570e3912fa 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -1585,13 +1585,12 @@ int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(MessageDef *msg_p, instance_ return -1; } - LOG_I(NR_RRC, "[gNB %ld] gNB_ue_ngap_id %u \n", instance, gNB_ue_ngap_id); gNB_RRC_UE_t *UE = &ue_context_p->ue_context; - LOG_I( - NR_RRC, "PDU Session Release Command: AMF_UE_NGAP_ID %lu rrc_ue_id %u release_pdusessions %d \n", cmd->amf_ue_ngap_id, gNB_ue_ngap_id, cmd->nb_pdusessions_torelease); - bool found = false; - uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); - UE->xids[xid] = RRC_PDUSESSION_RELEASE; + LOG_I(NR_RRC, "PDU Session Release: AMF_UE_NGAP_ID %lu rrc_ue_id %u release_pdusessions %d \n", + cmd->amf_ue_ngap_id, + gNB_ue_ngap_id, + cmd->nb_pdusessions_torelease); + e1ap_bearer_mod_req_t req = {0}; for (int pdusession = 0; pdusession < cmd->nb_pdusessions_torelease; pdusession++) { rrc_pdu_session_param_t *pduSession = find_pduSession(&UE->pduSessions, cmd->pdusession_release_params[pdusession].pdusession_id); if (!pduSession) { @@ -1599,30 +1598,35 @@ int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(MessageDef *msg_p, instance_ continue; } if (pduSession->status == PDU_SESSION_STATUS_FAILED) { - pduSession->xid = xid; continue; } if (pduSession->status == PDU_SESSION_STATUS_ESTABLISHED) { - found = true; - LOG_I(NR_RRC, "RELEASE pdusession %d \n", pduSession->param.pdusession_id); + LOG_I(NR_RRC, "NG Release PDU Session %d \n", pduSession->param.pdusession_id); + pdu_session_to_remove_t *release = &req.pduSessionRem[req.numPDUSessionsRem++]; + release->sessionId = pduSession->param.pdusession_id; + release->cause.type = E1AP_CAUSE_RADIO_NETWORK; + release->cause.value = E1AP_RADIO_CAUSE_NORMAL_RELEASE; pduSession->status = PDU_SESSION_STATUS_TORELEASE; - pduSession->xid = xid; } } - if (found) { - // TODO RRCReconfiguration To UE - LOG_I(NR_RRC, "Send RRCReconfiguration To UE \n"); - rrc_gNB_generate_dedicatedRRCReconfiguration_release(rrc, UE, xid, cmd->nas_pdu.len, cmd->nas_pdu.buf); + if (req.numPDUSessionsRem == 0) { + LOG_E(NR_RRC, "Received NG PDU Session Release Command but no PDU Sessions to release\n"); + return -1; + } else if (!ue_associated_to_cuup(rrc, UE)) { + LOG_E(NR_RRC, "UE %d is not associated to CU-UP\n", UE->rrc_ue_id); + // TODO handle, e.g., only trigger F1 release + return 0; } else { - // gtp tunnel delete - LOG_I(NR_RRC, "gtp tunnel delete all tunnels for UE %04x\n", UE->rnti); - gtpv1u_gnb_delete_tunnel_req_t req = {0}; - req.ue_id = UE->rnti; - gtpv1u_delete_ngu_tunnel(rrc->module_id, &req); - // NGAP_PDUSESSION_RELEASE_RESPONSE - rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE(rrc, UE, xid); - LOG_I(NR_RRC, "Send PDU Session Release Response \n"); + /* If present, store NAS-PDU in the UE context for later inclusion in RRCReconfiguration */ + if (cmd->nas_pdu.len > 0) { + UE->nas_pdu = copy_byte_array(cmd->nas_pdu); + } + LOG_I(NR_RRC, "Send F1 Bearer Context Modification Request with PDU Session release \n"); + req.gNB_cu_cp_ue_id = UE->rrc_ue_id; + req.gNB_cu_up_ue_id = UE->rrc_ue_id; + sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, UE); + rrc->cucp_cuup.bearer_context_mod(assoc_id, &req); } return 0; } diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index 389213986e..c34c453e60 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -590,14 +590,13 @@ bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id) LOG_E(SDAP, "SDAP entities not established or Invalid range of pdusession_id [0, 256].\n"); return false; } - LOG_D(SDAP, "Deleting SDAP entity for UE %lx and PDU Session id %d\n", ue_id, entityPtr->pdusession_id); if (entityPtr->ue_id == ue_id && entityPtr->pdusession_id == pdusession_id) { sdap_info.sdap_entity_llist = sdap_info.sdap_entity_llist->next_entity; if (entityPtr->pdusession_sock != -1) remove_ip_if(entityPtr); free(entityPtr); - LOG_D(SDAP, "Successfully deleted Entity.\n"); + LOG_D(SDAP, "Successfully deleted SDAP entity for UE %lx and PDU Session id %d\n", ue_id, pdusession_id); return true; } else { while ((entityPtr->ue_id != ue_id || entityPtr->pdusession_id != pdusession_id) && entityPtr->next_entity != NULL @@ -613,7 +612,7 @@ bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id) remove_ip_if(entityPtr); } free(entityPtr); - LOG_D(SDAP, "Successfully deleted Entity.\n"); + LOG_D(SDAP, "Successfully deleted Entity for UE %lx and PDU Session id %d\n", ue_id, pdusession_id); return true; } } diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index ab14ee6241..9f22b05b09 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -905,7 +905,7 @@ int newGtpuDeleteOneTunnel(instance_t instance, ue_id_t ue_id, int rb_id) } map::iterator rb_it = ue_it->second.bearers.find(rb_id); if (rb_it == ue_it->second.bearers.end()) { - LOG_E(GTPU, "%s() UE %ld has no bearer %d, available\n", __func__, ue_id, rb_id); + LOG_E(GTPU, "%s() UE %ld has no tunnel for bearer %d\n", __func__, ue_id, rb_id); pthread_mutex_unlock(&globGtp.gtp_lock); return !GTPNOK; } @@ -913,9 +913,9 @@ int newGtpuDeleteOneTunnel(instance_t instance, ue_id_t ue_id, int rb_id) globGtp.te2ue_mapping.erase(teid); ue_it->second.bearers.erase(rb_id); pthread_mutex_unlock(&globGtp.gtp_lock); - LOG_I(GTPU, "Deleted tunnel TEID %d (RB %d) for ue id %ld, remaining bearers:\n", teid, rb_id, ue_id); + LOG_I(GTPU, "Deleted tunnel TEID 0x%x for bearer %d of UE %ld, remaining tunnels:\n", teid, rb_id, ue_id); for (auto b : ue_it->second.bearers) - LOG_I(GTPU, "bearer %ld\n", b.first); + LOG_I(GTPU, "Bearer %ld\n", b.first); return !GTPNOK; } From 7d5e20fd03ec7e21cf2d80e34413a1a05c66b981 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 3 Sep 2025 22:57:48 +0200 Subject: [PATCH 74/80] gtpu: cleanup unused newGtpuDeleteTunnels() The partial-tunnel deletion API was buggy and redundant: * e.g. It erased entries from globGtp.te2ue_mapping but never erases the corresponding entries from inst->ue2te_mapping[ue].bearers All current use cases are already covered by: * newGtpuDeleteOneTunnel() for targeted deletion * newGtpuDeleteAllTunnels() for full cleanup Call sites should explicitly loop over newGtpuDeleteOneTunnel() if multiple tunnels need removal. --- openair3/ocp-gtpu/gtp_itf.cpp | 33 --------------------------------- openair3/ocp-gtpu/gtp_itf.h | 4 ---- 2 files changed, 37 deletions(-) diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index 9f22b05b09..ed15d48f80 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -982,45 +982,12 @@ int gtpv1u_delete_all_s1u_tunnel(const instance_t instance, const rnti_t rnti) return newGtpuDeleteAllTunnels(instance, rnti); } -int newGtpuDeleteTunnels(instance_t instance, ue_id_t ue_id, int nbTunnels, int *pdusession_id) -{ - LOG_D(GTPU, "[%ld] Start delete tunnels for ue id %lu\n", instance, ue_id); - pthread_mutex_lock(&globGtp.gtp_lock); - getInstRetInt(compatInst(instance)); - getUeRetInt(inst, ue_id); - int nb = 0; - - for (int i = 0; i < nbTunnels; i++) { - auto ptr2 = ptrUe->second.bearers.find(pdusession_id[i]); - - if (ptr2 == ptrUe->second.bearers.end()) { - LOG_E(GTPU, "[%ld] GTP-U instance: delete of not existing tunnel UE ID:RAB: %ld/%x\n", instance, ue_id, pdusession_id[i]); - } else { - globGtp.te2ue_mapping.erase(ptr2->second.teid_incoming); - nb++; - } - } - - if (ptrUe->second.bearers.size() == 0) - // no tunnels on this ue id, erase the ue entry - inst->ue2te_mapping.erase(ptrUe); - - pthread_mutex_unlock(&globGtp.gtp_lock); - LOG_I(GTPU, "[%ld] Deleted all tunnels for ue id %lu (%d tunnels deleted)\n", instance, ue_id, nb); - return !GTPNOK; -} - int gtpv1u_delete_x2u_tunnel(const instance_t instanceP, const gtpv1u_enb_delete_tunnel_req_t *const req_pP) { LOG_E(GTPU, "x2 tunnel not implemented\n"); return 0; } -int gtpv1u_delete_ngu_tunnel(const instance_t instance, gtpv1u_gnb_delete_tunnel_req_t *req) -{ - return newGtpuDeleteTunnels(instance, req->ue_id, req->num_pdusession, req->pdusession_id); -} - static gtpv1u_bearer_t create_bearer(int socket, const struct sockaddr_in *addr, uint32_t teid, uint16_t seq) { gtpv1u_bearer_t bearer = {.sock_fd = socket, .teid_outgoing = teid, .seqNum = seq}; diff --git a/openair3/ocp-gtpu/gtp_itf.h b/openair3/ocp-gtpu/gtp_itf.h index c31f8c935e..9274cd52f2 100644 --- a/openair3/ocp-gtpu/gtp_itf.h +++ b/openair3/ocp-gtpu/gtp_itf.h @@ -100,9 +100,6 @@ typedef struct gtpv1u_gnb_delete_tunnel_req_s gtpv1u_gnb_delete_tunnel_req_t; gtpCallback callBack, gtpCallbackSDAP callBackSDAP); - int gtpv1u_delete_ngu_tunnel( const instance_t instance, - gtpv1u_gnb_delete_tunnel_req_t *req); - int gtpv1u_update_ue_id(const instance_t instanceP, ue_id_t old_ue_id, ue_id_t new_ue_id); // New API @@ -124,7 +121,6 @@ typedef struct gtpv1u_gnb_delete_tunnel_req_s gtpv1u_gnb_delete_tunnel_req_t; int newGtpuDeleteOneTunnel(instance_t instance, ue_id_t ue_id, int rb_id); int newGtpuDeleteAllTunnels(instance_t instance, ue_id_t ue_id); - int newGtpuDeleteTunnels(instance_t instance, ue_id_t ue_id, int nbTunnels, int *pdusession_id); void gtpv1uSendDirect(instance_t instance, ue_id_t ue_id, int bearer_id, uint8_t *buf, size_t len, bool seqNumFlag, bool npduNumFlag); void gtpv1uSendDirectWithNRUSeqNum(instance_t instance, From 3cfe2e265ae1617766306abb4528e5741aa043d0 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 17 Jun 2025 13:32:21 +0200 Subject: [PATCH 75/80] RRC PDU Session Release: DRBs and PDU session teardown in NGAP PDU Session Release Response callback We need to keep PDU sessions and DRBs in list until the NGAP PDU Session Release Response is sent. * Introduced find_drb() and remove_drbs_by_pdu_session() helpers to locate and clean up DRBs linked to a specific PDU session * Targeted per-session DRB removal in rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE() * Ensures DRBs for unaffected PDU sessions remain intact * Remove unused PDU_SESSION_STATUS_RELEASED status: keeping this status is no longer relevant since the PDU sessions are effectively removed from the RRC lists Closes #867 Also, refactor rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND 3GPP TS 38.413 8.2.2 PDU Session Resource Release says: > upon reception the NG-RAN node shall execute the release of the requested PDU sessions. > For each PDU session to be released the NG-RAN node shall release the corresponding > resources over Uu and over NG, if any. Therefore, any PDU session in the pdusession_release_params list that is also present in the RRC list can be set to release, regardless of its status. The function signature was also updated along with other minor changes. --- openair2/RRC/NR/nr_rrc_defs.h | 1 - openair2/RRC/NR/rrc_gNB.c | 3 +- openair2/RRC/NR/rrc_gNB_NGAP.c | 40 +++++++++--------- openair2/RRC/NR/rrc_gNB_NGAP.h | 2 +- openair2/RRC/NR/rrc_gNB_radio_bearers.c | 56 +++++++++++++++++++++++++ openair2/RRC/NR/rrc_gNB_radio_bearers.h | 4 ++ 6 files changed, 83 insertions(+), 23 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index e8820bcc76..e850ce373a 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -97,7 +97,6 @@ typedef enum pdu_session_satus_e { PDU_SESSION_STATUS_TOMODIFY, // ENDC NSA PDU_SESSION_STATUS_FAILED, PDU_SESSION_STATUS_TORELEASE, // to release DRB between eNB and UE - PDU_SESSION_STATUS_RELEASED } pdu_session_status_t; typedef struct pdusession_s { diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 1e08c9cf25..a6c24fc579 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2880,7 +2880,6 @@ static const char *get_pdusession_status_text(pdu_session_status_t status) case PDU_SESSION_STATUS_TOMODIFY: return "to-modify"; case PDU_SESSION_STATUS_FAILED: return "failed"; case PDU_SESSION_STATUS_TORELEASE: return "to-release"; - case PDU_SESSION_STATUS_RELEASED: return "released"; default: AssertFatal(false, "illegal PDU status code %d\n", status); return "illegal"; } return "illegal"; @@ -3014,7 +3013,7 @@ void *rrc_gnb_task(void *args_p) { break; case NGAP_PDUSESSION_RELEASE_COMMAND: - rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(msg_p, instance); + rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(&NGAP_PDUSESSION_RELEASE_COMMAND(msg_p), RC.nrrrc[instance]); break; case NGAP_DL_RAN_STATUS_TRANSFER: diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 570e3912fa..7bcecb2533 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -1562,31 +1562,33 @@ void rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE(gNB_RRC_INST *rrc, gNB_RRC_UE DevAssert(resp->nb_of_pdusessions_released < NGAP_MAX_PDU_SESSION); resp->pdusession_release[resp->nb_of_pdusessions_released++].pdusession_id = pdusession->pdusession_id; } - session->status = PDU_SESSION_STATUS_RELEASED; } } + for (int i = 0; i < resp->nb_of_pdusessions_released; ++i) { + rm_pduSession(&UE->pduSessions, &UE->drbs, resp->pdusession_release[i].pdusession_id); + } + LOG_I(NR_RRC, "NGAP PDUSESSION RELEASE RESPONSE: rrc_ue_id %u release_pdu_sessions %d\n", resp->gNB_ue_ngap_id, resp->nb_of_pdusessions_released); itti_send_msg_to_task (TASK_NGAP, rrc->module_id, msg_p); } -//------------------------------------------------------------------------------ -int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(MessageDef *msg_p, instance_t instance) -//------------------------------------------------------------------------------ +/** @brief Process NG PDU Session Resource Release command (8.2.2 of 3GPP TS 38.413) + * upon reception the NG-RAN node shall execute the release of the requested PDU sessions. + * For each PDU session to be released the NG-RAN node shall release the corresponding + * resources over Uu and over NG, if any. */ +int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(ngap_pdusession_release_command_t *cmd, gNB_RRC_INST *rrc) { - uint32_t gNB_ue_ngap_id; - ngap_pdusession_release_command_t *cmd = &NGAP_PDUSESSION_RELEASE_COMMAND(msg_p); - gNB_ue_ngap_id = cmd->gNB_ue_ngap_id; - gNB_RRC_INST *rrc = RC.nrrrc[instance]; + uint32_t gNB_ue_ngap_id = cmd->gNB_ue_ngap_id; rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, gNB_ue_ngap_id); if (!ue_context_p) { - LOG_E(NR_RRC, "[gNB %ld] not found ue context gNB_ue_ngap_id %u \n", instance, gNB_ue_ngap_id); + LOG_E(NR_RRC, "[gNB %d] UE context not found for gNB_ue_ngap_id %u \n", rrc->module_id, gNB_ue_ngap_id); return -1; } gNB_RRC_UE_t *UE = &ue_context_p->ue_context; - LOG_I(NR_RRC, "PDU Session Release: AMF_UE_NGAP_ID %lu rrc_ue_id %u release_pdusessions %d \n", + LOG_I(NR_RRC, "NG PDU Session Release command: AMF_UE_NGAP_ID=%lu, rrc_ue_id=%u, nb_pdusessions_torelease=%d \n", cmd->amf_ue_ngap_id, gNB_ue_ngap_id, cmd->nb_pdusessions_torelease); @@ -1597,17 +1599,17 @@ int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(MessageDef *msg_p, instance_ LOG_E(NR_RRC, "Failed to release non-existing PDU Session %d\n", cmd->pdusession_release_params[pdusession].pdusession_id); continue; } - if (pduSession->status == PDU_SESSION_STATUS_FAILED) { + if (pduSession->status == PDU_SESSION_STATUS_TORELEASE) { + LOG_W(NR_RRC, "PDU Session %d already set to be released\n", pduSession->param.pdusession_id); continue; } - if (pduSession->status == PDU_SESSION_STATUS_ESTABLISHED) { - LOG_I(NR_RRC, "NG Release PDU Session %d \n", pduSession->param.pdusession_id); - pdu_session_to_remove_t *release = &req.pduSessionRem[req.numPDUSessionsRem++]; - release->sessionId = pduSession->param.pdusession_id; - release->cause.type = E1AP_CAUSE_RADIO_NETWORK; - release->cause.value = E1AP_RADIO_CAUSE_NORMAL_RELEASE; - pduSession->status = PDU_SESSION_STATUS_TORELEASE; - } + // Set PDU session to release, regardless of the status + LOG_I(NR_RRC, "Set PDU Session %d to release\n", pduSession->param.pdusession_id); + pdu_session_to_remove_t *release = &req.pduSessionRem[req.numPDUSessionsRem++]; + release->sessionId = pduSession->param.pdusession_id; + release->cause.type = E1AP_CAUSE_RADIO_NETWORK; + release->cause.value = E1AP_RADIO_CAUSE_NORMAL_RELEASE; + pduSession->status = PDU_SESSION_STATUS_TORELEASE; } if (req.numPDUSessionsRem == 0) { diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.h b/openair2/RRC/NR/rrc_gNB_NGAP.h index 91c7722c52..c3f692ff5f 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.h +++ b/openair2/RRC/NR/rrc_gNB_NGAP.h @@ -78,7 +78,7 @@ void rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(instance_t instance, uint32_t void rrc_gNB_send_NGAP_UE_CAPABILITIES_IND(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const NR_UECapabilityInformation_t *const ue_cap_info); -int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(MessageDef *msg_p, instance_t instance); +int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(ngap_pdusession_release_command_t *cmd, gNB_RRC_INST *rrc); void rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_t xid); diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.c b/openair2/RRC/NR/rrc_gNB_radio_bearers.c index 5af84f0399..c636e9e639 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.c +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.c @@ -141,6 +141,62 @@ rrc_pdu_session_param_t *add_pduSession(seq_arr_t *sessions_ptr, const pdusessio return added; } +static bool eq_drb_pdu_session_id(const void *vval, const void *vit) +{ + const int *id = (const int *)vval; + const drb_t *elem = (const drb_t *)vit; + return elem->pdusession_id == *id; +} + +/** @brief Finds the first DRB with the given PDU session ID. + * @return Pointer to matching drb_t or NULL if not found. */ +static drb_t *find_drb_by_pdusession_id(seq_arr_t *seq, int pdusession_id) +{ + DevAssert(seq); + DevAssert(pdusession_id > 0 && pdusession_id <= NGAP_MAX_PDU_SESSION); + elm_arr_t elm = find_if(seq, &pdusession_id, eq_drb_pdu_session_id); + if (elm.found) + return (drb_t *)elm.it; + return NULL; +} + +/** @brief Removes a DRB from the list + * @param drbs The DRB list + * @param drb Pointer to the DRB to remove */ +static void nr_rrc_rm_drb(seq_arr_t *drbs, drb_t *drb) +{ + DevAssert(drbs); + DevAssert(drb); + LOG_I(NR_RRC, "Removing DRB ID %d (PDU Session ID=%d)\n", drb->drb_id, drb->pdusession_id); + seq_arr_erase_deep(drbs, drb, free_drb); +} + +/** @brief Removes a PDU Session from the list by ID + * Also removes all associated DRBs for this PDU session. + * @return true if successfully removed, false if not found */ +bool rm_pduSession(seq_arr_t *sessions, seq_arr_t *drbs, int pdusession_id) +{ + DevAssert(sessions); + DevAssert(drbs); + + rrc_pdu_session_param_t *session = find_pduSession(sessions, pdusession_id); + + if (session) { + LOG_I(NR_RRC, "Removing PDU Session %d from RRC setup list\n", pdusession_id); + // Remove all associated DRBs first + drb_t *drb; + while ((drb = find_drb_by_pdusession_id(drbs, pdusession_id))) { + nr_rrc_rm_drb(drbs, drb); + } + // Then remove the PDU session + seq_arr_erase_deep(sessions, session, free_pdusession); + return true; + } + + LOG_W(NR_RRC, "pdusession_id=%d not found to remove\n", pdusession_id); + return false; +} + /** @brief Add drb_t item in the UE context list for @param pdusession_id */ drb_t *nr_rrc_add_drb(seq_arr_t *drb_ptr, int pdusession_id, nr_pdcp_configuration_t *pdcp) { diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.h b/openair2/RRC/NR/rrc_gNB_radio_bearers.h index f6821e314b..a1b09a5b02 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.h +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.h @@ -39,6 +39,10 @@ rrc_pdu_session_param_t *add_pduSession(seq_arr_t *sessions_ptr, const pdusessio /// @brief get PDU session of UE ue through the DRB drb_id rrc_pdu_session_param_t *find_pduSession_from_drbId(gNB_RRC_UE_t *ue, int drb_id); +/// @brief Remove PDU Session from RRC list +/// Also removes all associated DRBs for this PDU session. +bool rm_pduSession(seq_arr_t *sessions, seq_arr_t *drbs, int pdusession_id); + /// @brief set PDCP configuration in E1 Bearer Context Management message bearer_context_pdcp_config_t set_bearer_context_pdcp_config(const nr_pdcp_configuration_t pdcp, bool um_on_default_drb, From 653c0fd6d5c084b633af9584975c29d592cb939b Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 17 Jun 2025 13:26:35 +0200 Subject: [PATCH 76/80] Telnet: add ci command to trigger NGAP PDU Session Release This commit introduces a new telnet server command `pdu_session_release` to manually trigger the NGAP PDU Session Release Command message from the telnet ci shell. This is useful for integration testing of PDU session teardown behavior. Details: - Added `trigger_ngap_pdu_session_release()` to send NGAP_PDUSESSION_RELEASE_COMMAND to the RRC task, targeting the specified `gNB_ue_ngap_id`. - The command currently releases PDU session ID 10 (hardcoded). - Hooked into telnet shell with command: `pdu_session_release [gNB_ue_ngap_id]` Usage example: telnet > pdu_session_release 1 --- common/utils/telnetsrv/telnetsrv_ci.c | 82 +++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/common/utils/telnetsrv/telnetsrv_ci.c b/common/utils/telnetsrv/telnetsrv_ci.c index 291f1f37a2..8b00d529c5 100644 --- a/common/utils/telnetsrv/telnetsrv_ci.c +++ b/common/utils/telnetsrv/telnetsrv_ci.c @@ -39,6 +39,7 @@ #include "openair2/LAYER2/nr_rlc/nr_rlc_entity_am.h" #include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h" #include "openair2/RRC/NR/rrc_gNB_mobility.h" +#include "openair3/NGAP/ngap_gNB_ue_context.h" #define TELNETSERVERCODE #include "telnetsrv.h" @@ -284,6 +285,86 @@ static int get_current_bwp(char *buf, int debug, telnet_printfunc_t prnt) return 0; } +/** @brief Trigger NGAP PDU Session Release for one or more PDU sessions associated with a UE ID/ + * Syntax: trigger_pdu_session_release [ue_id=gNB_ue_ngap_id(int,opt)],pdusession_id(int)[,pdusession_id(int)...] + * - If the gNB_ue_ngap_id is omitted, it is fetched from the only UE present in the RRC layer + * - At least one valid PDU session ID must be provided + * @param[in] buf Comma-separated input string: [ue_id=gNB_ue_ngap_id(int,opt)],PDU1[,PDU2,...] + * @param[in] debug Not used. + * @param[in] prnt Callback for telnet output printing. + * @return 0 on success; negative value on error. */ +static int trigger_ngap_pdu_session_release(char *buf, int debug, telnet_printfunc_t prnt) +{ + if (buf == NULL) { + ERROR_MSG_RET("Missing input. Usage: trigger_pdu_session_release [ue_id=gNB_ue_ngap_id(int,opt)],pdusession_id(int)[,pdusession_id(int)...]\n"); + } + + char *tokens[NGAP_MAX_PDU_SESSION + 1]; + int count = 0; + + for (char *tok = strtok(buf, ","); tok != NULL && count < (int)sizeofArray(tokens); tok = strtok(NULL, ",")) { + tokens[count++] = tok; + } + + if (count < 1) { + ERROR_MSG_RET("Invalid input. Usage: trigger_pdu_session_release [ue_id=gNB_ue_ngap_id(int,opt)],pdusession_id(int)[,pdusession_id(int)...]\n"); + } + + int gNB_ue_ngap_id = -1; + int pdu_start_index = 0; + + if (strncmp(tokens[0], "ue_id=", 6) == 0) { + gNB_ue_ngap_id = atoi(tokens[0] + 6); + pdu_start_index = 1; + } else { + // No UE ID: infer it + if (!RC.nrrrc) + ERROR_MSG_RET("No RRC present\n"); + rrc_gNB_ue_context_t *ue = get_single_rrc_ue(); + if (!ue) + ERROR_MSG_RET("No single UE in RRC present\n"); + gNB_ue_ngap_id = ue->ue_context.rrc_ue_id; + } + + if (pdu_start_index >= count) { + ERROR_MSG_RET("No pdusession_id(int) provided\n"); + } + + ngap_gNB_ue_context_t *ngap = ngap_get_ue_context(gNB_ue_ngap_id); + if (!ngap) { + ERROR_MSG_RET("No NGAP UE context for gNB_ue_ngap_id %d\n", gNB_ue_ngap_id); + } + + MessageDef *message_p = itti_alloc_new_message(TASK_NGAP, 0, NGAP_PDUSESSION_RELEASE_COMMAND); + ngap_pdusession_release_command_t *msg = &NGAP_PDUSESSION_RELEASE_COMMAND(message_p); + memset(msg, 0, sizeof(*msg)); + + msg->amf_ue_ngap_id = ngap->amf_ue_ngap_id; + msg->gNB_ue_ngap_id = ngap->gNB_ue_ngap_id; + + int nb_sessions = 0; + for (int i = pdu_start_index; i < count; ++i) { + int sid = atoi(tokens[i]); + if (sid < 1 || sid > 255) { + ERROR_MSG_RET("Invalid pdusession_id(int): %s (must be between 1 and 255)\n", tokens[i]); + } + msg->pdusession_release_params[nb_sessions++].pdusession_id = sid; + } + + msg->nb_pdusessions_torelease = nb_sessions; + + if (prnt) { + prnt("Triggering NGAP PDU Session Release for gNB_ue_ngap_id=%d: releasing pdusession_id=%d", gNB_ue_ngap_id); + for (int i = 0; i < nb_sessions; ++i) { + prnt(" %d,", msg->pdusession_release_params[i].pdusession_id); + } + prnt("\n"); + } + + itti_send_msg_to_task(TASK_RRC_GNB, 0, message_p); + return 0; +} + static telnetshell_cmddef_t cicmds[] = { {"get_single_rnti", "", get_single_rnti}, {"force_reestab", "[rnti(hex,opt)]", trigger_reestab}, @@ -294,6 +375,7 @@ static telnetshell_cmddef_t cicmds[] = { {"fetch_du_by_ue_id", "[rrc_ue_id(int,opt)]", fetch_du_by_ue_id}, {"get_current_bwp", "[rnti(hex,opt)]", get_current_bwp}, {"trigger_n2_ho", "[neighbour_pci(uint32_t),ueId(uint32_t)]", rrc_gNB_trigger_n2_ho}, + {"pdu_session_release", "[gNB_ue_ngap_id(int,opt)]", trigger_ngap_pdu_session_release}, {"", "", NULL}, }; From 55c3cd2b3149cd36a841ec9d92e124fecf815589 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 13 Aug 2025 14:29:56 +0200 Subject: [PATCH 77/80] Telnet: add ciUE command to trigger establishment of a new PDU Session --- common/utils/telnetsrv/CMakeLists.txt | 2 +- common/utils/telnetsrv/telnetsrv_ciUE.c | 44 +++++++++++++++++++++++++ openair3/NAS/NR_UE/nr_nas_msg.c | 2 +- openair3/NAS/NR_UE/nr_nas_msg.h | 1 + 4 files changed, 47 insertions(+), 2 deletions(-) diff --git a/common/utils/telnetsrv/CMakeLists.txt b/common/utils/telnetsrv/CMakeLists.txt index a249596d97..40380c0418 100644 --- a/common/utils/telnetsrv/CMakeLists.txt +++ b/common/utils/telnetsrv/CMakeLists.txt @@ -62,7 +62,7 @@ add_dependencies(telnetsrv telnetsrv_ci) message(STATUS "Add CI specific telnet functions for nrUE in telnetsrv_ciUE.so") add_library(telnetsrv_ciUE MODULE telnetsrv_ciUE.c) -target_link_libraries(telnetsrv_ciUE PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs UTIL) +target_link_libraries(telnetsrv_ciUE PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs UTIL NR_L2_UE nr_nas) add_dependencies(telnetsrv telnetsrv_ciUE) message(STATUS "Add bearer specific telnet functions in libtelnetsrv_bearer.so") diff --git a/common/utils/telnetsrv/telnetsrv_ciUE.c b/common/utils/telnetsrv/telnetsrv_ciUE.c index 88320a6ce0..6f86f1678f 100644 --- a/common/utils/telnetsrv/telnetsrv_ciUE.c +++ b/common/utils/telnetsrv/telnetsrv_ciUE.c @@ -39,6 +39,7 @@ #include "openair2/RRC/NR_UE/rrc_proto.h" #include "openair1/PHY/phy_extern_nr_ue.h" #include "openair1/PHY/defs_nr_common.h" +#include "openair3/NAS/NR_UE/nr_nas_msg.h" #define TELNETSERVERCODE #include "telnetsrv.h" @@ -52,6 +53,14 @@ const char* NR_UE_L2_STATE_STR[] = { #undef UE_STATE }; +static int get_default_ue_id(void) +{ + NR_UE_RRC_INST_t *rrc = get_NR_UE_rrc_inst(0); + if (!rrc) + return -1; + return rrc->ue_id; +} + /** * Get the synchronization state of a UE. * @@ -132,6 +141,40 @@ static int get_dl_toa(char *buf, int debug, telnet_printfunc_t prnt) return 0; } +static int add_pdu_session(char *buf, int debug, telnet_printfunc_t prnt) +{ + int ue_id = -1; + int pdusession_id = -1; + + if (!buf) { + ERROR_MSG_RET("Missing argument: expected PDUSessionID[,UE_ID]\n"); + } + + // Try parsing values in the form: "PDUSessionID[,UE_ID]" + int n = sscanf(buf, "%d,%d", &pdusession_id, &ue_id); + if (n == 1) { + // Only PDUSessionID provided: use default UE ID + ue_id = get_default_ue_id(); + if (ue_id < 0) + ERROR_MSG_RET("No default UE context found\n"); + } else if (n != 2) { + ERROR_MSG_RET("Invalid format: expected PDUSessionID[,UE_ID]\n"); + } + + if (pdusession_id < 0 || pdusession_id > 255) + ERROR_MSG_RET("PDUSessionID must be in range [0,255]\n"); + if (ue_id < 0) + ERROR_MSG_RET("UE_ID must be >= 0\n"); + + nr_ue_nas_t *nas = get_ue_nas_info(ue_id); + if (!nas) + ERROR_MSG_RET("No NAS context found for UE_ID %d\n", ue_id); + + request_pdusession(nas, pdusession_id); + prnt("Triggered PDU session request for UE %d with ID %d\n", ue_id, pdusession_id); + return 0; +} + /* Telnet shell command definitions */ static telnetshell_cmddef_t cicmds[] = { {"sync_state", "[UE_ID(int,opt)]", get_sync_state}, @@ -140,6 +183,7 @@ static telnetshell_cmddef_t cicmds[] = { {"force_crnti_ra", "", force_crnti_ra}, {"deregistration", "", force_deregistration}, {"get_max_dl_toa", "[ant]", get_dl_toa}, + {"add_pdu_session", "[PDUSessionID(int)],[UE_ID(int,opt)]", add_pdu_session}, {"", "", NULL}, }; diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index d0230e0a03..5a58af6b84 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -1772,7 +1772,7 @@ static void send_nas_5gmm_ind(instance_t instance, const Guti5GSMobileIdentity_t itti_send_msg_to_task(TASK_RRC_NRUE, instance, msg); } -static void request_pdusession(nr_ue_nas_t *nas, int pdusession_id) +void request_pdusession(nr_ue_nas_t *nas, int pdusession_id) { MessageDef *message_p = itti_alloc_new_message(TASK_NAS_NRUE, nas->UE_id, NAS_PDU_SESSION_REQ); NAS_PDU_SESSION_REQ(message_p).pdusession_id = pdusession_id; diff --git a/openair3/NAS/NR_UE/nr_nas_msg.h b/openair3/NAS/NR_UE/nr_nas_msg.h index 2d62c799ea..7a19997444 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.h +++ b/openair3/NAS/NR_UE/nr_nas_msg.h @@ -113,5 +113,6 @@ void *nas_nrue_task(void *args_p); void *nas_nrue(void *args_p); void nas_init_nrue(int num_ues); void nr_ue_create_ip_if(const char *ifnameprefix, const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id); +void request_pdusession(nr_ue_nas_t *nas, int pdusession_id); #endif /* __NR_NAS_MSG_SIM_H__*/ From ed6a25be75cac37f259d35addd35279fbeedda83 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 30 Sep 2025 16:09:01 +0200 Subject: [PATCH 78/80] Add PDU session add/remove test cases to 25 PRB RFSIM pipeline - Enable telnet server on VNF (gNB) and UE in docker-compose.yaml - Add new test cases for PDU session management: * Add PDU session via UE telnet * Release PDU session via telnet * Verify connectivity after PDU session release - Integrate telnet commands into existing container_5g_rfsim_u0_25prb.xml pipeline - Test cases added before undeploy step in proper execution order --- .../xml_files/container_5g_rfsim_u0_25prb.xml | 26 +++++++++++++++++++ .../docker-compose.yaml | 10 ++++--- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/ci-scripts/xml_files/container_5g_rfsim_u0_25prb.xml b/ci-scripts/xml_files/container_5g_rfsim_u0_25prb.xml index d563b3aab4..83bffa90ac 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_u0_25prb.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_u0_25prb.xml @@ -36,6 +36,11 @@ 020003 030001 030002 + 050001 + 050002 + 050003 + 020001 + 020002 100001 222222 @@ -139,6 +144,27 @@ 90 + + Custom_Command + Trigger PDU Session Release via gNB telnet + acamas + echo ci pdu_session_release 2 | ncat 192.168.71.140 9090 + + + + Custom_Command + Add PDU Session via UE telnet + acamas + echo ci add_pdu_session 6,7 | ncat 192.168.71.150 8091 + + + + Custom_Command + Trigger PDU Session Release via gNB telnet + acamas + echo ci pdu_session_release 6 | ncat 192.168.71.140 9090 + + Undeploy_Object true diff --git a/ci-scripts/yaml_files/5g_rfsimulator_u0_25prb/docker-compose.yaml b/ci-scripts/yaml_files/5g_rfsimulator_u0_25prb/docker-compose.yaml index 722290aa38..c4a4e2ebea 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator_u0_25prb/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_rfsimulator_u0_25prb/docker-compose.yaml @@ -97,8 +97,9 @@ services: - ALL environment: USE_ADDITIONAL_OPTIONS: --nfapi VNF --log_config.global_log_options level,nocolor,time + --telnetsrv --telnetsrv.listenaddr 192.168.71.140 --telnetsrv.shrmod ci NFAPI_TRACE_LEVEL: info - ASAN_OPTIONS: detect_leaks=0 + ASAN_OPTIONS: detect_leaks=0:detect_odr_violation=0 depends_on: - oai-ext-dn networks: @@ -122,7 +123,7 @@ services: environment: USE_ADDITIONAL_OPTIONS: --nfapi PNF --rfsim --log_config.global_log_options level,nocolor,time NFAPI_TRACE_LEVEL: info - ASAN_OPTIONS: detect_leaks=0 + ASAN_OPTIONS: detect_leaks=0:detect_odr_violation=0 depends_on: - oai-vnf networks: @@ -147,7 +148,10 @@ services: - NET_ADMIN # for interface bringup - NET_RAW # for ping environment: - USE_ADDITIONAL_OPTIONS: --rfsim -r 25 --numerology 0 --uicc0.imsi 208990100001100 --band 66 -C 2152680000 --CO -400000000 --ssb 48 --rfsimulator.serveraddr 192.168.71.141 --extra-pdu-id 2 --log_config.global_log_options level,nocolor,time + USE_ADDITIONAL_OPTIONS: --rfsim -r 25 --numerology 0 --uicc0.imsi 208990100001100 --band 66 -C 2152680000 --CO -400000000 --ssb 48 + --rfsimulator.serveraddr 192.168.71.141 --extra-pdu-id 2 --log_config.global_log_options level,nocolor,time + --telnetsrv --telnetsrv.shrmod ciUE --telnetsrv.listenaddr 192.168.71.150 --telnetsrv.listenport 8091 + ASAN_OPTIONS: detect_leaks=0:detect_odr_violation=0 depends_on: - oai-pnf networks: From c3ef64d292e5febb3734a5f19df7eea09a13f031 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 10 Sep 2025 10:24:17 +0200 Subject: [PATCH 79/80] Add PDU Session Release documentation --- doc/E1AP/e1ap_procedures.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/doc/E1AP/e1ap_procedures.md b/doc/E1AP/e1ap_procedures.md index c46c710333..8857eee26b 100644 --- a/doc/E1AP/e1ap_procedures.md +++ b/doc/E1AP/e1ap_procedures.md @@ -72,3 +72,36 @@ sequenceDiagram u->>c: BEARER CONTEXT MODIFICATION RESPONSE Note over c: e1apCUCP_handle_BEARER_CONTEXT_MODIFICATION_RESPONSE ``` + +## PDU Session Release + +```mermaid +sequenceDiagram + participant AMF + participant CUCP + participant CUUP + participant DU + participant UE + + AMF->>CUCP: NG PDU SESSION RESOURCE RELEASE COMMAND + Note over CUCP: ngap_gNB_handle_pdusession_release_command + CUCP->>CUCP: rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND + Note over CUCP: set status PDU_SESSION_STATUS_TORELEASE + CUCP->>CUUP: E1 Bearer Context Modification Request + Note over CUUP: release_gtpu_tunnel (GTP tunnel, PDCP, SDAP) + CUUP->>CUCP: E1 Bearer Context Modification Response + Note over CUCP: rrc_gNB_send_f1_drb_release_request + CUCP->>DU: F1 UE Context Modification Request + Note over DU: handle_ue_context_drbs_release (release in MAC/RLC) + DU->>CUCP: F1 UE Context Modification Response + Note over CUCP: rrc_CU_process_ue_context_modification_response + Note over CUCP: replace existing CellGroupConfig + Note over CUCP: rrc_gNB_generate_dedicatedRRCReconfiguration + CUCP->>UE: RRCReconfiguration (DRB release list, NAS PDU) + UE->>CUCP: RRCReconfigurationComplete + Note over CUCP: handle_rrcReconfigurationComplete + Note over CUCP: rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE + CUCP->>AMF: NG PDU SESSION RESOURCE RELEASE RESPONSE + Note over CUCP: rm_drbs_by_pdusession (from stored RRC list) + Note over CUCP: rm_pduSession (from stored RRC list) +``` From 1fea6108a8c546f9e33add264e1f078a669f49ee Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 15 Oct 2025 12:27:34 +0200 Subject: [PATCH 80/80] RRC: unify NG delay control before calling the RRC NGAP handler - Add delayed_action_state_t in the UE context for ongoing delayed action - Move delay check and timer re-enqueue to rrc thread in rrc_gNB.c (rrc_delay_transaction) - Call delay before NGAP setup/release handlers; remove local delay logic from rrc_gNB_NGAP.c - Clear on RRCReconfigurationComplete (reset_delayed_action) Closes #960 --- openair2/RRC/NR/nr_rrc_defs.h | 9 ++- openair2/RRC/NR/nr_rrc_proto.h | 1 + openair2/RRC/NR/rrc_gNB.c | 102 +++++++++++++++++++++++++-- openair2/RRC/NR/rrc_gNB_NGAP.c | 46 +----------- openair2/RRC/NR/rrc_gNB_UE_context.c | 2 - 5 files changed, 108 insertions(+), 52 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index e850ce373a..4d24a771c0 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -148,6 +148,12 @@ typedef enum { RRC_UECAPABILITY_ENQUIRY, } rrc_action_t; +/* Small state for delaying NG-triggered actions (setup/release) */ +typedef struct { + int max_delays; + bool ongoing_transaction; +} delayed_action_state_t; + typedef struct nr_redcap_ue_cap { bool support_of_redcap_r17; bool support_of_16drb_redcap_r17; @@ -241,8 +247,7 @@ typedef struct gNB_RRC_UE_s { byte_array_t nas_pdu; /* hack, see rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ() for more info */ - int max_delays_pdu_session; - bool ongoing_pdusession_setup_request; + delayed_action_state_t delayed_action; nr_redcap_ue_cap_t *redcap_cap; } gNB_RRC_UE_t; diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 2fc7bf5e5e..a36a0778c6 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -122,5 +122,6 @@ NR_SRB_ToAddModList_t *createSRBlist(gNB_RRC_UE_t *ue, uint8_t reestablish); NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish, bool do_integrity, bool do_ciphering); void activate_srb(gNB_RRC_UE_t *UE, int srb_id); void e1_notify_pdcp_status(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const ngap_drb_status_t *drb_status); +void init_delayed_action(delayed_action_state_t *delayed_action); #endif diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index a6c24fc579..b18e820e91 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -115,6 +115,97 @@ mui_t rrc_gNB_mui = 0; +/* Per-transaction max_delays counter to limit retry attempts */ +#define MAX_DELAYS 100 + +/** @brief clone and re-enqueue an NGAP message after delaying + * delays the ongoing transaction (in msg_p) by setting a timer to wait + * 10ms; upon expiry, delivers to RRC, which sends the message to itself */ +static void delay_transaction(MessageDef *msg_p, int wait_us) +{ + MessagesIds id = ITTI_MSG_ID(msg_p); + AssertFatal(id == NGAP_PDUSESSION_SETUP_REQ || id == NGAP_PDUSESSION_RELEASE_COMMAND, + "delay_transaction(): unsupported message id %d\n", + id); + + MessageDef *new = itti_alloc_new_message(TASK_RRC_GNB, 0, id); + + // Copy only the specific message struct, not the entire union. + // The union (msg_t) contains all message types and is much larger than + // the allocated space (which is sized for the specific message type only). + if (id == NGAP_PDUSESSION_SETUP_REQ) { + NGAP_PDUSESSION_SETUP_REQ(new) = NGAP_PDUSESSION_SETUP_REQ(msg_p); + } else if (id == NGAP_PDUSESSION_RELEASE_COMMAND) { + NGAP_PDUSESSION_RELEASE_COMMAND(new) = NGAP_PDUSESSION_RELEASE_COMMAND(msg_p); + } + + int instance = msg_p->ittiMsgHeader.originInstance; + long timer_id; + timer_setup(0, wait_us, TASK_RRC_GNB, instance, TIMER_ONE_SHOT, new, &timer_id); +} + +static void reset_delayed_action(delayed_action_state_t *delayed_action) +{ + delayed_action->ongoing_transaction = false; + delayed_action->max_delays = 0; +} + +void init_delayed_action(delayed_action_state_t *delayed_action) +{ + delayed_action->ongoing_transaction = true; + delayed_action->max_delays = MAX_DELAYS; +} + +/* \brief checks if any transaction is ongoing for any xid of this UE */ +static bool transaction_ongoing(const gNB_RRC_UE_t *UE) +{ + for (int xid = 0; xid < NR_RRC_TRANSACTION_IDENTIFIER_NUMBER; ++xid) { + if (UE->xids[xid] != RRC_ACTION_NONE) + return true; + } + return false; +} + +/** @brief delay control: returns true if delayed, false if should proceed + * This is a hack. We observed that with some UEs, PDU session requests might + * come in quick succession, faster than the RRC reconfiguration for the PDU + * session requests can be carried out (UE is doing reconfig, and second PDU + * session request arrives). We don't have currently the means to "queue up" + * these transactions, which would probably involve some rework of the RRC. + * To still allow these requests to come in and succeed, we below check and delay transactions + * for 10ms. However, to not accidentally end up in infinite loops, the + * maximum number is capped on a per-UE basis as indicated in variable + * max_delays_pdu_session. See commit 277f8da0 for more details. */ +static bool rrc_delay_transaction(instance_t instance, MessageDef *msg_p) +{ + uint32_t cu_ue_id = 0; + if (ITTI_MSG_ID(msg_p) == NGAP_PDUSESSION_SETUP_REQ) { + cu_ue_id = NGAP_PDUSESSION_SETUP_REQ(msg_p).gNB_ue_ngap_id; + } else if (ITTI_MSG_ID(msg_p) == NGAP_PDUSESSION_RELEASE_COMMAND) { + cu_ue_id = NGAP_PDUSESSION_RELEASE_COMMAND(msg_p).gNB_ue_ngap_id; + } + AssertFatal(cu_ue_id > 0, "cu_ue_id not found in message %s\n", ITTI_MSG_NAME(msg_p)); + + rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[instance], cu_ue_id); + DevAssert(ue_context_p); + + gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + bool delay = UE->delayed_action.ongoing_transaction && UE->delayed_action.max_delays > 0; + /* Check if any PDU session action is ongoing */ + if (delay || transaction_ongoing(UE)) { + int wait_us = 10000; + LOG_I(NR_RRC, + "UE %d: ongoing transaction, delaying incoming transaction by %d us\n", + UE->rrc_ue_id, + wait_us); + delay_transaction(msg_p, wait_us); + UE->delayed_action.max_delays--; + return true; /* delayed */ + } + LOG_D(NR_RRC, "UE %d: no delayed action ongoing, proceeding with incoming transaction\n", UE->rrc_ue_id); + return false; /* not delayed */ +} + typedef struct deliver_ue_ctxt_release_data_t { gNB_RRC_INST *rrc; f1ap_ue_context_rel_cmd_t *release_cmd; @@ -1856,6 +1947,7 @@ static void handle_rrcReconfigurationComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *U switch (UE->xids[xid]) { case RRC_PDUSESSION_RELEASE: { rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE(rrc, UE, xid); + reset_delayed_action(&UE->delayed_action); } break; case RRC_PDUSESSION_ESTABLISH: if (UE->n_initial_pdu > 0) { @@ -1870,6 +1962,7 @@ static void handle_rrcReconfigurationComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *U LOG_W(NR_RRC, "UE %d: RRC Reconfiguration Complete for PDU session establishment, but no PDU sessions were setup\n", UE->rrc_ue_id); + reset_delayed_action(&UE->delayed_action); break; case RRC_PDUSESSION_MODIFY: rrc_gNB_send_NGAP_PDUSESSION_MODIFY_RESP(rrc, UE, xid); @@ -1886,9 +1979,6 @@ static void handle_rrcReconfigurationComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *U break; } - if (UE->xids[xid] == RRC_PDUSESSION_ESTABLISH) - UE->ongoing_pdusession_setup_request = false; - UE->xids[xid] = RRC_ACTION_NONE; for (int i = 0; i < NR_RRC_TRANSACTION_IDENTIFIER_NUMBER; ++i) { if (UE->xids[i] != RRC_ACTION_NONE) { @@ -3005,7 +3095,8 @@ void *rrc_gnb_task(void *args_p) { break; case NGAP_PDUSESSION_SETUP_REQ: - rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(msg_p, instance); + if (!rrc_delay_transaction(instance, msg_p)) + rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(msg_p, instance); break; case NGAP_PDUSESSION_MODIFY_REQ: @@ -3013,7 +3104,8 @@ void *rrc_gnb_task(void *args_p) { break; case NGAP_PDUSESSION_RELEASE_COMMAND: - rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(&NGAP_PDUSESSION_RELEASE_COMMAND(msg_p), RC.nrrrc[instance]); + if (!rrc_delay_transaction(instance, msg_p)) + rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(&NGAP_PDUSESSION_RELEASE_COMMAND(msg_p), RC.nrrrc[instance]); break; case NGAP_DL_RAN_STATUS_TRANSFER: diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 7bcecb2533..8ba7b3e950 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -789,29 +789,6 @@ void rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE return; } -/* \brief checks if any transaction is ongoing for any xid of this UE */ -static bool transaction_ongoing(const gNB_RRC_UE_t *UE) -{ - for (int xid = 0; xid < NR_RRC_TRANSACTION_IDENTIFIER_NUMBER; ++xid) { - if (UE->xids[xid] != RRC_ACTION_NONE) - return true; - } - return false; -} - -/* \brief delays the ongoing transaction (in msg_p) by setting a timer to wait - * 10ms; upon expiry, delivers to RRC, which sends the message to itself */ -static void delay_transaction(MessageDef *msg_p, int wait_us) -{ - MessageDef *new = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_PDUSESSION_SETUP_REQ); - ngap_pdusession_setup_req_t *n = &NGAP_PDUSESSION_SETUP_REQ(new); - *n = NGAP_PDUSESSION_SETUP_REQ(msg_p); - - int instance = msg_p->ittiMsgHeader.originInstance; - long timer_id; - timer_setup(0, wait_us, TASK_RRC_GNB, instance, TIMER_ONE_SHOT, new, &timer_id); -} - /** * @brief Fill PDU Session Resource Setup Response with a list of PDU Session Resources Failed to Setup * and send ITTI message to TASK_NGAP @@ -883,25 +860,6 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins UE->amf_ue_ngap_id = msg->amf_ue_ngap_id; - /* This is a hack. We observed that with some UEs, PDU session requests might - * come in quick succession, faster than the RRC reconfiguration for the PDU - * session requests can be carried out (UE is doing reconfig, and second PDU - * session request arrives). We don't have currently the means to "queue up" - * these transactions, which would probably involve some rework of the RRC. - * To still allow these requests to come in and succeed, we below check and delay transactions - * for 10ms. However, to not accidentally end up in infinite loops, the - * maximum number is capped on a per-UE basis as indicated in variable - * max_delays_pdu_session. */ - if (!UE->ongoing_pdusession_setup_request) - UE->max_delays_pdu_session = 100; - - if (UE->max_delays_pdu_session > 0 && (transaction_ongoing(UE) || UE->ongoing_pdusession_setup_request)) { - int wait_us = 10000; - LOG_I(RRC, "UE %d: delay PDU session setup by %d us, pending %d retries\n", UE->rrc_ue_id, wait_us, UE->max_delays_pdu_session); - delay_transaction(msg_p, wait_us); - UE->max_delays_pdu_session--; - return; - } pdusession_t to_setup[NGAP_MAX_PDU_SESSION] = {0}; for (int i = 0; i < msg->nb_pdusessions_tosetup; ++i) @@ -916,7 +874,8 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins send_ngap_pdu_session_setup_resp_fail(instance, msg, cause); rrc_forward_ue_nas_message(rrc, UE); } else { - UE->ongoing_pdusession_setup_request = true; + // Set ongoing_transaction flag to true + init_delayed_action(&UE->delayed_action); } } @@ -1630,6 +1589,7 @@ int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(ngap_pdusession_release_comm sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, UE); rrc->cucp_cuup.bearer_context_mod(assoc_id, &req); } + init_delayed_action(&UE->delayed_action); return 0; } diff --git a/openair2/RRC/NR/rrc_gNB_UE_context.c b/openair2/RRC/NR/rrc_gNB_UE_context.c index 9a2c3fb6f6..86838927ab 100644 --- a/openair2/RRC/NR/rrc_gNB_UE_context.c +++ b/openair2/RRC/NR/rrc_gNB_UE_context.c @@ -218,8 +218,6 @@ rrc_gNB_ue_context_t *rrc_gNB_create_ue_context(sctp_assoc_t assoc_id, ue->rrc_ue_id); bool success = cu_add_f1_ue_data(ue->rrc_ue_id, &ue_data); DevAssert(success); - ue->max_delays_pdu_session = 20; /* see rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ() */ - ue->ongoing_pdusession_setup_request = false; // Initialise setup PDU Sessions list seq_arr_init(&ue->pduSessions, sizeof(rrc_pdu_session_param_t));