From 70a6434168ee35c72cb28bd55c4da3dc728ce2fd Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 17 Sep 2024 09:22:10 +0200 Subject: [PATCH 01/12] remove unused input from get_beam_index function --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 2c51ee5f21..69671e2a89 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -3185,7 +3185,7 @@ void fapi_beam_index_allocation(NR_ServingCellConfigCommon_t *scc, gNB_MAC_INST } } -static inline int get_beam_index(const NR_beam_info_t *beam_info, int frame, int slot, int beam_index, int slots_per_frame) +static inline int get_beam_index(const NR_beam_info_t *beam_info, int frame, int slot, int slots_per_frame) { return ((frame * slots_per_frame + slot) / beam_info->beam_duration) % beam_info->beam_allocation_size; } @@ -3196,7 +3196,7 @@ NR_beam_alloc_t beam_allocation_procedure(NR_beam_info_t *beam_info, int frame, if (!beam_info->beam_allocation) return (NR_beam_alloc_t) {.new_beam = false, .idx = 0}; - const int index = get_beam_index(beam_info, frame, slot, beam_index, slots_per_frame); + const int index = get_beam_index(beam_info, frame, slot, slots_per_frame); for (int i = 0; i < beam_info->beams_per_period; i++) { NR_beam_alloc_t beam_struct = {.new_beam = false, .idx = i}; int *beam = &beam_info->beam_allocation[i][index]; @@ -3215,7 +3215,7 @@ void reset_beam_status(NR_beam_info_t *beam_info, int frame, int slot, int beam_ { if(!new_beam) // need to reset only if the beam was allocated specifically for this instance return; - const int index = get_beam_index(beam_info, frame, slot, beam_index, slots_per_frame); + const int index = get_beam_index(beam_info, frame, slot, slots_per_frame); for (int i = 0; i < beam_info->beams_per_period; i++) { if (beam_info->beam_allocation[i][index] == beam_index) beam_info->beam_allocation[i][index] = -1; From 2d2a92dd127bf2eca6a5406a95ea85f5b219a218 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 17 Sep 2024 11:39:30 +0200 Subject: [PATCH 02/12] improvements in handling CSI report for RSRP --- openair2/LAYER2/NR_MAC_COMMON/nr_mac.h | 4 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 93 +++++++++---------- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 14 +-- 3 files changed, 52 insertions(+), 59 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h index 6ce41a30ea..6d78d6616a 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h @@ -564,8 +564,8 @@ typedef struct nr_csi_report { NR_CSI_ReportConfig__reportQuantity_PR reportQuantity_type; long periodicity; uint16_t offset; - long ** SSB_Index_list; - long ** CSI_Index_list; + long **SSB_Index_list; + long **CSI_Index_list; // uint8_t nb_of_nzp_csi_report; uint8_t nb_of_csi_ssb_report; L1_RSRP_bitlen_t CSI_report_bitlen; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 39f5e2453a..f4c77a9442 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -481,10 +481,11 @@ static bool get_measured_rsrp(uint8_t index, int *rsrp) } //returns the differential RSRP value (upper limit) -static int get_diff_rsrp(uint8_t index, int strongest_rsrp) { - if(strongest_rsrp != -1) { +static int get_diff_rsrp(uint8_t index, int strongest_rsrp) +{ + if(strongest_rsrp != -1) return strongest_rsrp + diff_rsrp_ssb_csi_meas_10_1_6_1_2[index]; - } else + else return MIN_RSRP_VALUE; } @@ -497,7 +498,6 @@ static void tci_handling(NR_UE_info_t *UE, frame_t frame, slot_t slot) int curr_ssb_beam_index = 0; //ToDo: yet to know how to identify the serving ssb beam index uint8_t target_ssb_beam_index = curr_ssb_beam_index; uint8_t is_triggering_ssb_beam_switch =0; - uint8_t ssb_idx = 0; int pdsch_bwp_id = 0; int ssb_index[MAX_NUM_SSB] = {0}; int ssb_rsrp[MAX_NUM_SSB] = {0}; @@ -505,10 +505,8 @@ static void tci_handling(NR_UE_info_t *UE, frame_t frame, slot_t slot) NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - uint8_t nr_ssbri_cri = 0; uint8_t nb_of_csi_ssb_report = UE->csi_report_template[cqi_idx].nb_of_csi_ssb_report; int better_rsrp_reported = -140-(-0); /*minimum_measured_RSRP_value - minimum_differntail_RSRP_value*///considering the minimum RSRP value as better RSRP initially - uint8_t diff_rsrp_idx = 0; uint8_t i, j; //bwp indicator @@ -528,22 +526,16 @@ static void tci_handling(NR_UE_info_t *UE, frame_t frame, slot_t slot) idx: resource set index */ - nr_ssbri_cri = sched_ctrl->CSI_report.ssb_cri_report.nr_ssbri_cri; + int nr_ssbri = sched_ctrl->CSI_report.ssb_rsrp_report.nr_reports; //extracting the ssb indexes - for (ssb_idx = 0; ssb_idx < nr_ssbri_cri; ssb_idx++) { - ssb_index[idx * nb_of_csi_ssb_report + ssb_idx] = sched_ctrl->CSI_report.ssb_cri_report.CRI_SSBRI[ssb_idx]; + for (int ssb_idx = 0; ssb_idx < nr_ssbri; ssb_idx++) { + ssb_index[idx * nb_of_csi_ssb_report + ssb_idx] = sched_ctrl->CSI_report.ssb_rsrp_report.resource_id[ssb_idx]; } //if strongest measured RSRP is configured - int strongest_ssb_rsrp; - int rsrp_index = sched_ctrl->CSI_report.ssb_cri_report.RSRP; - bool valid = get_measured_rsrp(rsrp_index, &strongest_ssb_rsrp); - if (!valid) { - LOG_E(NR_MAC, "UE %04x: reported RSRP index %d invalid\n", UE->rnti, rsrp_index); - return; - } + int strongest_ssb_rsrp = sched_ctrl->CSI_report.ssb_rsrp_report.RSRP[0]; ssb_rsrp[idx * nb_of_csi_ssb_report] = strongest_ssb_rsrp; - LOG_D(NR_MAC,"ssb_rsrp = %d\n",strongest_ssb_rsrp); + LOG_D(NR_MAC,"ssb_rsrp = %d\n", strongest_ssb_rsrp); //if current ssb rsrp is greater than better rsrp if(ssb_rsrp[idx * nb_of_csi_ssb_report] > better_rsrp_reported) { @@ -551,8 +543,8 @@ static void tci_handling(NR_UE_info_t *UE, frame_t frame, slot_t slot) target_ssb_beam_index = idx * nb_of_csi_ssb_report; } - for(diff_rsrp_idx =1; diff_rsrp_idx < nr_ssbri_cri; diff_rsrp_idx++) { - ssb_rsrp[idx * nb_of_csi_ssb_report + diff_rsrp_idx] = get_diff_rsrp(sched_ctrl->CSI_report.ssb_cri_report.diff_RSRP[diff_rsrp_idx-1], strongest_ssb_rsrp); + for(int diff_rsrp_idx = 1; diff_rsrp_idx < nr_ssbri; diff_rsrp_idx++) { + ssb_rsrp[idx * nb_of_csi_ssb_report + diff_rsrp_idx] = sched_ctrl->CSI_report.ssb_rsrp_report.RSRP[diff_rsrp_idx]; //if current reported rsrp is greater than better rsrp if(ssb_rsrp[idx * nb_of_csi_ssb_report + diff_rsrp_idx] > better_rsrp_reported) { @@ -687,10 +679,6 @@ static void evaluate_rsrp_report(NR_UE_info_t *UE, int *cumul_bits, NR_CSI_ReportConfig__reportQuantity_PR reportQuantity_type) { - nr_csi_report_t *csi_report = &UE->csi_report_template[csi_report_id]; - uint8_t cri_ssbri_bitlen = csi_report->CSI_report_bitlen.cri_ssbri_bitlen; - uint16_t curr_payload; - /*! As per the spec 38.212 and table: 6.3.1.1.2-12 in a single UCI sequence we can have multiple CSI_report * the number of CSI_report will depend on number of CSI resource sets that are configured in CSI-ResourceConfig RRC IE * From spec 38.331 from the IE CSI-ResourceConfig for SSB RSRP reporting we can configure only one resource set @@ -708,46 +696,51 @@ static void evaluate_rsrp_report(NR_UE_info_t *UE, resources can be received simultaneously by the UE either with a single spatial domain receive filter, or with multiple simultaneous spatial domain receive filter */ + nr_csi_report_t *csi_report = &UE->csi_report_template[csi_report_id]; + RSRP_report_t *rsrp_report; + long **index_list; + switch (reportQuantity_type) { + case NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP: + rsrp_report = &sched_ctrl->CSI_report.ssb_rsrp_report; + index_list = csi_report->SSB_Index_list; + break; + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP : + rsrp_report = &sched_ctrl->CSI_report.csirs_rsrp_report; + index_list = csi_report->CSI_Index_list; + break; + default : + AssertFatal(false, "Invalid RSRP report type\n"); + } - sched_ctrl->CSI_report.ssb_cri_report.nr_ssbri_cri = csi_report->CSI_report_bitlen.nb_ssbri_cri; - - for (int csi_ssb_idx = 0; csi_ssb_idx < sched_ctrl->CSI_report.ssb_cri_report.nr_ssbri_cri ; csi_ssb_idx++) { - curr_payload = pickandreverse_bits(payload, cri_ssbri_bitlen, *cumul_bits); - - if (NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP == reportQuantity_type) { - sched_ctrl->CSI_report.ssb_cri_report.CRI_SSBRI[csi_ssb_idx] = - *(csi_report->SSB_Index_list[cri_ssbri_bitlen>0?((curr_payload)&~(~1U<<(cri_ssbri_bitlen-1))):cri_ssbri_bitlen]); - LOG_D(MAC,"SSB_index = %d\n",sched_ctrl->CSI_report.ssb_cri_report.CRI_SSBRI[csi_ssb_idx]); - } - else { - sched_ctrl->CSI_report.ssb_cri_report.CRI_SSBRI[csi_ssb_idx] = - *(csi_report->CSI_Index_list[cri_ssbri_bitlen>0?((curr_payload)&~(~1U<<(cri_ssbri_bitlen-1))):cri_ssbri_bitlen]); - LOG_D(MAC,"CSI-RS Resource Indicator = %d\n",sched_ctrl->CSI_report.ssb_cri_report.CRI_SSBRI[csi_ssb_idx]); - } - *cumul_bits += cri_ssbri_bitlen; - + uint16_t curr_payload; + for (int i = 0; i < rsrp_report->nr_reports; i++) { + int bitlen = csi_report->CSI_report_bitlen.cri_ssbri_bitlen; + curr_payload = pickandreverse_bits(payload, bitlen, *cumul_bits); + rsrp_report->resource_id[i] = *(index_list[bitlen > 0 ? ((curr_payload) & ~(~1U << (bitlen - 1))) : bitlen]); + LOG_D(MAC,"SSB/CSI-RS index = %d\n", rsrp_report->resource_id[i]); + *cumul_bits += bitlen; } curr_payload = pickandreverse_bits(payload, 7, *cumul_bits); - sched_ctrl->CSI_report.ssb_cri_report.RSRP = curr_payload & 0x7f; + int rsrp_index = curr_payload & 0x7f; *cumul_bits += 7; - for (int diff_rsrp_idx =0; diff_rsrp_idx < sched_ctrl->CSI_report.ssb_cri_report.nr_ssbri_cri - 1; diff_rsrp_idx++ ) { - curr_payload = pickandreverse_bits(payload, 4, *cumul_bits); - sched_ctrl->CSI_report.ssb_cri_report.diff_RSRP[diff_rsrp_idx] = curr_payload & 0x0f; - *cumul_bits += 4; - } csi_report->nb_of_csi_ssb_report++; - int strongest_ssb_rsrp; - int rsrp_index = sched_ctrl->CSI_report.ssb_cri_report.RSRP; - bool valid = get_measured_rsrp(rsrp_index, &strongest_ssb_rsrp); + bool valid = get_measured_rsrp(rsrp_index, &rsrp_report->RSRP[0]); if (!valid) { LOG_E(NR_MAC, "UE %04x: reported RSRP index %d invalid\n", UE->rnti, rsrp_index); return; } + + for (int i = 1; i < rsrp_report->nr_reports; i++) { + curr_payload = pickandreverse_bits(payload, 4, *cumul_bits); + rsrp_report->RSRP[i] = get_diff_rsrp(curr_payload & 0x0f, rsrp_report->RSRP[0]); + *cumul_bits += 4; + } + NR_mac_stats_t *stats = &UE->mac_stats; // including ssb rsrp in mac stats - stats->cumul_rsrp += strongest_ssb_rsrp; + stats->cumul_rsrp += rsrp_report->RSRP[0]; stats->num_rsrp_meas++; } diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 54be4358a7..df03e59eca 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -523,16 +523,16 @@ struct CRI_RI_LI_PMI_CQI { bool print_report; }; -typedef struct CRI_SSB_RSRP { - uint8_t nr_ssbri_cri; - uint8_t CRI_SSBRI[MAX_NR_OF_REPORTED_RS]; - uint8_t RSRP; - uint8_t diff_RSRP[MAX_NR_OF_REPORTED_RS - 1]; -} CRI_SSB_RSRP_t; +typedef struct RSRP_report { + uint8_t nr_reports; + uint8_t resource_id[MAX_NR_OF_REPORTED_RS]; + int RSRP[MAX_NR_OF_REPORTED_RS]; +} RSRP_report_t; struct CSI_Report { struct CRI_RI_LI_PMI_CQI cri_ri_li_pmi_cqi_report; - struct CRI_SSB_RSRP ssb_cri_report; + RSRP_report_t ssb_rsrp_report; + RSRP_report_t csirs_rsrp_report; }; #define MAX_SR_BITLEN 8 From 19c667fa80786a6f6ba18836764bbafb60b1f8b3 Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 14 Nov 2024 11:40:00 +0100 Subject: [PATCH 03/12] remove unused tci handling function --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 251 ------------------ 1 file changed, 251 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index f4c77a9442..796361f0bc 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -36,8 +36,6 @@ extern RAN_CONTEXT_t RC; - - static void nr_fill_nfapi_pucch(gNB_MAC_INST *nrmac, frame_t frame, sub_frame_t slot, @@ -97,13 +95,6 @@ static void nr_fill_nfapi_pucch(gNB_MAC_INST *nrmac, #define MIN_RSRP_VALUE -141 #define MAX_RSRP_VALUE -43 -#define MAX_NUM_SSB 128 -#define MAX_SSB_SCHED 8 -#define L1_RSRP_HYSTERIS 10 //considering 10 dBm as hysterisis for avoiding frequent SSB Beam Switching. !Fixme provide exact value if any -//#define L1_DIFF_RSRP_STEP_SIZE 2 - -static int ssb_index_sorted[MAX_NUM_SSB] = {0}; -static int ssb_rsrp_sorted[MAX_NUM_SSB] = {0}; //Measured RSRP Values Table 10.1.16.1-1 from 36.133 //Stored all the upper limits[Max RSRP Value of corresponding index] @@ -402,71 +393,6 @@ static void handle_dl_harq(NR_UE_info_t * UE, } } -static int checkTargetSSBInFirst64TCIStates_pdschConfig(int ssb_index_t, NR_UE_info_t *UE) -{ - const NR_PDSCH_Config_t *pdsch_Config = UE->current_DL_BWP.pdsch_Config; - int nb_tci_states = pdsch_Config ? pdsch_Config->tci_StatesToAddModList->list.count : 0; - NR_TCI_State_t *tci =NULL; - - for(int i=0; itci_StatesToAddModList->list.array[i]; - - if(tci != NULL) { - if(tci->qcl_Type1.referenceSignal.present == NR_QCL_Info__referenceSignal_PR_ssb) { - if(tci->qcl_Type1.referenceSignal.choice.ssb == ssb_index_t) - return tci->tci_StateId; // returned TCI state ID - } - // if type2 is configured - else if(tci->qcl_Type2 != NULL && tci->qcl_Type2->referenceSignal.present == NR_QCL_Info__referenceSignal_PR_ssb) { - if(tci->qcl_Type2->referenceSignal.choice.ssb == ssb_index_t) - return tci->tci_StateId; // returned TCI state ID - } else LOG_I(NR_MAC,"SSB index is not found in first 64 TCI states of TCI_statestoAddModList[%d]", i); - } - } - - // tci state not identified in first 64 TCI States of PDSCH Config - return -1; -} - -static int checkTargetSSBInTCIStates_pdcchConfig(int ssb_index_t, NR_UE_info_t *UE) -{ - NR_TCI_State_t *tci =NULL; - NR_TCI_StateId_t *tci_id = NULL; - NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_ControlResourceSet_t *coreset = sched_ctrl->coreset; - int flag = 0; - int tci_stateID = -1; - const NR_PDSCH_Config_t *pdsch_Config = UE->current_DL_BWP.pdsch_Config; - int nb_tci_states = pdsch_Config ? pdsch_Config->tci_StatesToAddModList->list.count : 0; - for(int i=0; itci_StatesToAddModList->list.array[i]; - - if(tci != NULL && tci->qcl_Type1.referenceSignal.present == NR_QCL_Info__referenceSignal_PR_ssb) { - if(tci->qcl_Type1.referenceSignal.choice.ssb == ssb_index_t) { - flag = 1; - tci_stateID = tci->tci_StateId; - break; - } else if(tci->qcl_Type2 != NULL && tci->qcl_Type2->referenceSignal.present == NR_QCL_Info__referenceSignal_PR_ssb) { - flag = 1; - tci_stateID = tci->tci_StateId; - break; - } - } - - if(flag != 0 && tci_stateID != -1 && coreset != NULL) { - for(i=0; i<64 && itci_StatesPDCCH_ToAddList->list.count; i++) { - tci_id = coreset->tci_StatesPDCCH_ToAddList->list.array[i]; - - if(tci_id != NULL && *tci_id == tci_stateID) - return tci_stateID; - } - } - } - - // Need to implement once configuration is received - return -1; -} - //returns the measured RSRP value (upper limit) static bool get_measured_rsrp(uint8_t index, int *rsrp) { @@ -489,181 +415,6 @@ static int get_diff_rsrp(uint8_t index, int strongest_rsrp) return MIN_RSRP_VALUE; } -//identifies the target SSB Beam index -//keeps the required date for PDCCH and PDSCH TCI state activation/deactivation CE consutruction globally -//handles triggering of PDCCH and PDSCH MAC CEs -static void tci_handling(NR_UE_info_t *UE, frame_t frame, slot_t slot) -{ - int cqi_idx = 0; - int curr_ssb_beam_index = 0; //ToDo: yet to know how to identify the serving ssb beam index - uint8_t target_ssb_beam_index = curr_ssb_beam_index; - uint8_t is_triggering_ssb_beam_switch =0; - int pdsch_bwp_id = 0; - int ssb_index[MAX_NUM_SSB] = {0}; - int ssb_rsrp[MAX_NUM_SSB] = {0}; - uint8_t idx = 0; - NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP; - NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - - uint8_t nb_of_csi_ssb_report = UE->csi_report_template[cqi_idx].nb_of_csi_ssb_report; - int better_rsrp_reported = -140-(-0); /*minimum_measured_RSRP_value - minimum_differntail_RSRP_value*///considering the minimum RSRP value as better RSRP initially - uint8_t i, j; - - //bwp indicator - int n_dl_bwp = UE->sc_info.n_dl_bwp; - const int bwp_id = dl_bwp->bwp_id; - if (n_dl_bwp < 4) - pdsch_bwp_id = bwp_id; - else - pdsch_bwp_id = bwp_id - 1; // as per table 7.3.1.1.2-1 in 38.212 - - /*Example: - CRI_SSBRI: 1 2 3 4| 5 6 7 8| 9 10 1 2| - nb_of_csi_ssb_report = 3 //3 sets as above - nr_ssbri_cri = 4 //each set has 4 elements - storing ssb indexes in ssb_index array as ssb_index[0] = 1 .. ssb_index[4] = 5 - ssb_rsrp[0] = strongest rsrp in first set, ssb_rsrp[4] = strongest rsrp in second set, .. - idx: resource set index - */ - - int nr_ssbri = sched_ctrl->CSI_report.ssb_rsrp_report.nr_reports; - //extracting the ssb indexes - for (int ssb_idx = 0; ssb_idx < nr_ssbri; ssb_idx++) { - ssb_index[idx * nb_of_csi_ssb_report + ssb_idx] = sched_ctrl->CSI_report.ssb_rsrp_report.resource_id[ssb_idx]; - } - - //if strongest measured RSRP is configured - int strongest_ssb_rsrp = sched_ctrl->CSI_report.ssb_rsrp_report.RSRP[0]; - ssb_rsrp[idx * nb_of_csi_ssb_report] = strongest_ssb_rsrp; - LOG_D(NR_MAC,"ssb_rsrp = %d\n", strongest_ssb_rsrp); - - //if current ssb rsrp is greater than better rsrp - if(ssb_rsrp[idx * nb_of_csi_ssb_report] > better_rsrp_reported) { - better_rsrp_reported = ssb_rsrp[idx * nb_of_csi_ssb_report]; - target_ssb_beam_index = idx * nb_of_csi_ssb_report; - } - - for(int diff_rsrp_idx = 1; diff_rsrp_idx < nr_ssbri; diff_rsrp_idx++) { - ssb_rsrp[idx * nb_of_csi_ssb_report + diff_rsrp_idx] = sched_ctrl->CSI_report.ssb_rsrp_report.RSRP[diff_rsrp_idx]; - - //if current reported rsrp is greater than better rsrp - if(ssb_rsrp[idx * nb_of_csi_ssb_report + diff_rsrp_idx] > better_rsrp_reported) { - better_rsrp_reported = ssb_rsrp[idx * nb_of_csi_ssb_report + diff_rsrp_idx]; - target_ssb_beam_index = idx * nb_of_csi_ssb_report + diff_rsrp_idx; - } - } - - if(ssb_index[target_ssb_beam_index] != ssb_index[curr_ssb_beam_index] && ssb_rsrp[target_ssb_beam_index] > ssb_rsrp[curr_ssb_beam_index]) { - if( ssb_rsrp[target_ssb_beam_index] - ssb_rsrp[curr_ssb_beam_index] > L1_RSRP_HYSTERIS) { - is_triggering_ssb_beam_switch = 1; - LOG_D(NR_MAC, "Triggering ssb beam switching using tci\n"); - } - } - - if(is_triggering_ssb_beam_switch) { - //filling pdcch tci state activativation mac ce structure fields - sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.is_scheduled = 1; - //OAI currently focusing on Non CA usecase hence 0 is considered as serving - //cell id - sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.servingCellId = 0; //0 for PCell as 38.331 v15.9.0 page 353 //serving cell id for which this MAC CE applies - sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.coresetId = 0; //coreset id for which the TCI State id is being indicated - - /* 38.321 v15.8.0 page 66 - TCI State ID: This field indicates the TCI state identified by TCI-StateId as specified in TS 38.331 [5] applicable - to the Control Resource Set identified by CORESET ID field. - If the field of CORESET ID is set to 0, - this field indicates a TCI-StateId for a TCI state of the first 64 TCI-states configured by tci-States-ToAddModList and tciStates-ToReleaseList in the PDSCH-Config in the active BWP. - If the field of CORESET ID is set to the other value than 0, - this field indicates a TCI-StateId configured by tci-StatesPDCCH-ToAddList and tciStatesPDCCH-ToReleaseList in the controlResourceSet identified by the indicated CORESET ID. - The length of the field is 7 bits - */ - if(sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.coresetId == 0) { - int tci_state_id = checkTargetSSBInFirst64TCIStates_pdschConfig(ssb_index[target_ssb_beam_index], UE); - - if( tci_state_id != -1) - sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.tciStateId = tci_state_id; - else { - //identify the best beam within first 64 TCI States of PDSCH - //Config TCI-states-to-addModList - int flag = 0; - - for(i =0; ssb_index_sorted[i]!=0; i++) { - tci_state_id = checkTargetSSBInFirst64TCIStates_pdschConfig(ssb_index_sorted[i],UE) ; - - if(tci_state_id != -1 && ssb_rsrp_sorted[i] > ssb_rsrp[curr_ssb_beam_index] && ssb_rsrp_sorted[i] - ssb_rsrp[curr_ssb_beam_index] > L1_RSRP_HYSTERIS) { - sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.tciStateId = tci_state_id; - flag = 1; - break; - } - } - - if(flag == 0 || ssb_rsrp_sorted[i] < ssb_rsrp[curr_ssb_beam_index] || ssb_rsrp_sorted[i] - ssb_rsrp[curr_ssb_beam_index] < L1_RSRP_HYSTERIS) { - sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.is_scheduled = 0; - } - } - } else { - int tci_state_id = checkTargetSSBInTCIStates_pdcchConfig(ssb_index[target_ssb_beam_index], UE); - - if (tci_state_id !=-1) - sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.tciStateId = tci_state_id; - else { - //identify the best beam within CORESET/PDCCH - ////Config TCI-states-to-addModList - int flag = 0; - - for(i =0; ssb_index_sorted[i]!=0; i++) { - tci_state_id = checkTargetSSBInTCIStates_pdcchConfig(ssb_index_sorted[i], UE); - - if( tci_state_id != -1 && ssb_rsrp_sorted[i] > ssb_rsrp[curr_ssb_beam_index] && ssb_rsrp_sorted[i] - ssb_rsrp[curr_ssb_beam_index] > L1_RSRP_HYSTERIS) { - sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.tciStateId = tci_state_id; - flag = 1; - break; - } - } - - if(flag == 0 || ssb_rsrp_sorted[i] < ssb_rsrp[curr_ssb_beam_index] || ssb_rsrp_sorted[i] - ssb_rsrp[curr_ssb_beam_index] < L1_RSRP_HYSTERIS) { - sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.is_scheduled = 0; - } - } - } - - sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.tci_present_inDCI = sched_ctrl->coreset ? - sched_ctrl->coreset->tci_PresentInDCI : NULL; - - //filling pdsch tci state activation deactivation mac ce structure fields - if(sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.tci_present_inDCI) { - sched_ctrl->UE_mac_ce_ctrl.pdsch_TCI_States_ActDeact.is_scheduled = 1; - /* - Serving Cell ID: This field indicates the identity of the Serving Cell for which the MAC CE applies - Considering only PCell exists. Serving cell index of PCell is always 0, hence configuring 0 - */ - sched_ctrl->UE_mac_ce_ctrl.pdsch_TCI_States_ActDeact.servingCellId = 0; - /* - BWP ID: This field indicates a DL BWP for which the MAC CE applies as the codepoint of the DCI bandwidth - part indicator field as specified in TS 38.212 - */ - sched_ctrl->UE_mac_ce_ctrl.pdsch_TCI_States_ActDeact.bwpId = pdsch_bwp_id; - - /* - * TODO ssb_rsrp_sort() API yet to code to find 8 best beams, rrc configuration - * is required - */ - for(i = 0; i<8; i++) { - sched_ctrl->UE_mac_ce_ctrl.pdsch_TCI_States_ActDeact.tciStateActDeact[i] = i; - } - - sched_ctrl->UE_mac_ce_ctrl.pdsch_TCI_States_ActDeact.highestTciStateActivated = 8; - - for(i = 0, j =0; iUE_mac_ce_ctrl.pdsch_TCI_States_ActDeact.tciStateActDeact[i]) { - sched_ctrl->UE_mac_ce_ctrl.pdsch_TCI_States_ActDeact.codepoint[j] = i; - j++; - } - } - }//tci_presentInDCI - }//is-triggering_beam_switch -} // tci handling - static uint8_t pickandreverse_bits(uint8_t *payload, uint16_t bitlen, uint8_t start_bit) { uint8_t rev_bits = 0; @@ -1116,8 +867,6 @@ void handle_nr_uci_pucch_2_3_4(module_id_t mod_id, if (uci_234->csi_part1.csi_part1_crc != 1) { // API to parse the csi report and store it into sched_ctrl extract_pucch_csi_report(csi_MeasConfig, uci_234, frame, slot, UE, nrmac->common_channels->ServingCellConfigCommon); - // TCI handling function - tci_handling(UE, frame, slot); } free(uci_234->csi_part1.csi_part1_payload); } From dc9a2cf1adf783607580a6fa9db6ebb2573a07a8 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 17 Sep 2024 15:43:19 +0200 Subject: [PATCH 04/12] simple beam switching procedure based on strongest reported SSB --- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 12 ++++++++++++ openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 17 ++++++++++------- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 2 +- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 69671e2a89..0e2f5cb5bf 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -3222,6 +3222,18 @@ void reset_beam_status(NR_beam_info_t *beam_info, int frame, int slot, int beam_ } } +void beam_selection_procedures(gNB_MAC_INST *mac, NR_UE_info_t *UE) +{ + RSRP_report_t *rsrp_report = &UE->UE_sched_ctrl.CSI_report.ssb_rsrp_report; + // simple beam switching algorithm -> we select beam with highest RSRP from CSI report + int new_bf_index = get_fapi_beamforming_index(mac, rsrp_report->resource_id[0]); + if (UE->UE_beam_index == new_bf_index) + return; // no beam change needed + + LOG_I(NR_MAC, "Switching to beam with ID %d corresponding to SSB %d\n", new_bf_index, rsrp_report->resource_id[0]); + UE->UE_beam_index = new_bf_index; +} + void send_initial_ul_rrc_message(int rnti, const uint8_t *sdu, sdu_size_t sdu_len, void *data) { gNB_MAC_INST *mac = RC.nrmac[0]; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 796361f0bc..170c3706fc 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -423,7 +423,8 @@ static uint8_t pickandreverse_bits(uint8_t *payload, uint16_t bitlen, uint8_t st return rev_bits; } -static void evaluate_rsrp_report(NR_UE_info_t *UE, +static void evaluate_rsrp_report(gNB_MAC_INST *nrmac, + NR_UE_info_t *UE, NR_UE_sched_ctrl_t *sched_ctrl, uint8_t csi_report_id, uint8_t *payload, @@ -463,6 +464,7 @@ static void evaluate_rsrp_report(NR_UE_info_t *UE, AssertFatal(false, "Invalid RSRP report type\n"); } + rsrp_report->nr_reports = csi_report->CSI_report_bitlen.nb_ssbri_cri; uint16_t curr_payload; for (int i = 0; i < rsrp_report->nr_reports; i++) { int bitlen = csi_report->CSI_report_bitlen.cri_ssbri_bitlen; @@ -613,7 +615,7 @@ static void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig, frame_t frame, slot_t slot, NR_UE_info_t *UE, - NR_ServingCellConfigCommon_t *scc) + gNB_MAC_INST *nrmac) { /** From Table 6.3.1.1.2-3: RI, LI, CQI, and CRI of codebookType=typeI-SinglePanel */ uint8_t *payload = uci_pdu->csi_part1.csi_part1_payload; @@ -643,12 +645,13 @@ static void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig, if ((n_slots_frame*frame + slot - offset)%period == 0) { reportQuantity_type = csi_report->reportQuantity_type; LOG_D(MAC,"SFN/SF:%d/%d reportQuantity type = %d\n",frame,slot,reportQuantity_type); - switch(reportQuantity_type){ + switch(reportQuantity_type) { case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP: - evaluate_rsrp_report(UE,sched_ctrl,csi_report_id,payload,&cumul_bits,reportQuantity_type); + evaluate_rsrp_report(nrmac, UE, sched_ctrl, csi_report_id, payload, &cumul_bits, reportQuantity_type); break; case NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP: - evaluate_rsrp_report(UE,sched_ctrl,csi_report_id,payload,&cumul_bits,reportQuantity_type); + evaluate_rsrp_report(nrmac, UE, sched_ctrl, csi_report_id, payload, &cumul_bits, reportQuantity_type); + beam_selection_procedures(nrmac, UE); break; case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI: sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report = true; @@ -818,7 +821,7 @@ void handle_nr_uci_pucch_2_3_4(module_id_t mod_id, gNB_MAC_INST *nrmac = RC.nrmac[mod_id]; NR_SCHED_LOCK(&nrmac->sched_lock); - NR_UE_info_t * UE = find_nr_UE(&nrmac->UE_info, uci_234->rnti); + NR_UE_info_t *UE = find_nr_UE(&nrmac->UE_info, uci_234->rnti); if (!UE) { NR_SCHED_UNLOCK(&nrmac->sched_lock); LOG_E(NR_MAC, "%s(): unknown RNTI %04x in PUCCH UCI\n", __func__, uci_234->rnti); @@ -866,7 +869,7 @@ void handle_nr_uci_pucch_2_3_4(module_id_t mod_id, LOG_D(NR_MAC, "CSI CRC %d\n", uci_234->csi_part1.csi_part1_crc); if (uci_234->csi_part1.csi_part1_crc != 1) { // API to parse the csi report and store it into sched_ctrl - extract_pucch_csi_report(csi_MeasConfig, uci_234, frame, slot, UE, nrmac->common_channels->ServingCellConfigCommon); + extract_pucch_csi_report(csi_MeasConfig, uci_234, frame, slot, UE, nrmac); } free(uci_234->csi_part1.csi_part1_payload); } diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 3e9f02d7ff..36c063bd32 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -447,7 +447,7 @@ void fapi_beam_index_allocation(NR_ServingCellConfigCommon_t *scc, gNB_MAC_INST int get_fapi_beamforming_index(gNB_MAC_INST *mac, int ssb_idx); NR_beam_alloc_t beam_allocation_procedure(NR_beam_info_t *beam_info, int frame, int slot, int beam_index, int slots_per_frame); void reset_beam_status(NR_beam_info_t *beam_info, int frame, int slot, int beam_index, int slots_per_frame, bool new_beam); - +void beam_selection_procedures(gNB_MAC_INST *mac, NR_UE_info_t *UE); void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t frameP, sub_frame_t slotP); size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset_rsrp); From 2940ee5edabffcd665fcdeffd248e5b24657d002 Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 19 Sep 2024 15:24:15 +0200 Subject: [PATCH 05/12] MAC beam allocation for periodic CSI measurements --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 170c3706fc..1d66c7df7d 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -155,9 +155,7 @@ static int get_pucch_index(int frame, int slot, int n_slots_frame, const NR_TDD_ } -void nr_schedule_pucch(gNB_MAC_INST *nrmac, - frame_t frameP, - sub_frame_t slotP) +void nr_schedule_pucch(gNB_MAC_INST *nrmac, frame_t frameP, sub_frame_t slotP) { /* already mutex protected: held in gNB_dlsch_ulsch_scheduler() */ NR_SCHED_ENSURE_LOCKED(&nrmac->sched_lock); @@ -198,9 +196,7 @@ void nr_schedule_pucch(gNB_MAC_INST *nrmac, } } -void nr_csi_meas_reporting(int Mod_idP, - frame_t frame, - sub_frame_t slot) +void nr_csi_meas_reporting(int Mod_idP,frame_t frame, sub_frame_t slot) { const int CC_id = 0; gNB_MAC_INST *nrmac = RC.nrmac[Mod_idP]; @@ -270,9 +266,10 @@ void nr_csi_meas_reporting(int Mod_idP, int bwp_start = ul_bwp->BWPStart; // going through the list of PUCCH resources to find the one indexed by resource_id - int beam_idx = 0; // TODO proper beam allocation + NR_beam_alloc_t beam = beam_allocation_procedure(&nrmac->beam_info, sched_frame, sched_slot, UE->UE_beam_index, n_slots_frame); + AssertFatal(beam.idx >= 0, "Cannot allocate CSI measurements on PUCCH in any available beam\n"); const int index = ul_buffer_index(sched_frame, sched_slot, ul_bwp->scs, nrmac->vrb_map_UL_size); - uint16_t *vrb_map_UL = &nrmac->common_channels[0].vrb_map_UL[beam_idx][index * MAX_BWP_SIZE]; + uint16_t *vrb_map_UL = &nrmac->common_channels[0].vrb_map_UL[beam.idx][index * MAX_BWP_SIZE]; const int m = pucch_Config->resourceToAddModList->list.count; for (int j = 0; j < m; j++) { NR_PUCCH_Resource_t *pucchres = pucch_Config->resourceToAddModList->list.array[j]; From 8de9d006f55ec8fde4df788e9085cc905d00ce69 Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 19 Sep 2024 16:00:14 +0200 Subject: [PATCH 06/12] MAC beam allocation for SRS --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c index 945e078e37..e6935db7ae 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c @@ -411,6 +411,7 @@ void nr_srs_ri_computation(const nfapi_nr_srs_normalized_channel_iq_matrix_t *nr } static void nr_configure_srs(nfapi_nr_srs_pdu_t *srs_pdu, + int frame, int slot, int module_id, int CC_id, @@ -469,9 +470,14 @@ static void nr_configure_srs(nfapi_nr_srs_pdu_t *srs_pdu, srs_pdu->beamforming.num_prgs = m_SRS[srs_pdu->config_index]; srs_pdu->beamforming.prg_size = 1; } - - // TODO properly use beam allocation - uint16_t *vrb_map_UL = &RC.nrmac[module_id]->common_channels[CC_id].vrb_map_UL[0][buffer_index * MAX_BWP_SIZE]; + srs_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = UE->UE_beam_index; + NR_beam_alloc_t beam = beam_allocation_procedure(&RC.nrmac[module_id]->beam_info, + frame, + slot, + UE->UE_beam_index, + nr_slots_per_frame[current_BWP->scs]); + AssertFatal(beam.idx >= 0, "Cannot allocate SRS in any available beam\n"); + uint16_t *vrb_map_UL = &RC.nrmac[module_id]->common_channels[CC_id].vrb_map_UL[beam.idx][buffer_index * MAX_BWP_SIZE]; uint64_t mask = SL_to_bitmap(srs_pdu->time_start_position, srs_pdu->num_symbols); for (int i = 0; i < srs_pdu->bwp_size; ++i) vrb_map_UL[i + srs_pdu->bwp_start] |= mask; @@ -497,7 +503,7 @@ static void nr_fill_nfapi_srs(int module_id, memset(srs_pdu, 0, sizeof(nfapi_nr_srs_pdu_t)); future_ul_tti_req->n_pdus += 1; index = ul_buffer_index(frame, slot, UE->current_UL_BWP.scs, RC.nrmac[module_id]->vrb_map_UL_size); - nr_configure_srs(srs_pdu, slot, module_id, CC_id, UE, srs_resource_set, srs_resource, index); + nr_configure_srs(srs_pdu, frame, slot, module_id, CC_id, UE, srs_resource_set, srs_resource, index); } /******************************************************************* From 912fec55efb69aa52d686e57b0a2a91be0398162 Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 19 Sep 2024 18:13:29 +0200 Subject: [PATCH 07/12] MAC beam allocation for scheduling request --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 1d66c7df7d..6b1eb4abbb 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -1145,10 +1145,10 @@ void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t SFN, sub_frame_t slot) int SR_period; int SR_offset; - find_period_offset_SR(SchedulingRequestResourceConfig,&SR_period,&SR_offset); + find_period_offset_SR(SchedulingRequestResourceConfig, &SR_period, &SR_offset); // convert to int to avoid underflow of uint int sfn_sf = SFN * n_slots_frame + slot; - LOG_D(NR_MAC,"SR_resource_id %d: SR_period %d, SR_offset %d\n",SR_resource_id,SR_period,SR_offset); + LOG_D(NR_MAC,"SR_resource_id %d: SR_period %d, SR_offset %d\n", SR_resource_id, SR_period, SR_offset); if ((sfn_sf - SR_offset) % SR_period != 0) continue; LOG_D(NR_MAC, "%4d.%2d Scheduling Request UE %04x identified\n", SFN, slot, UE->rnti); @@ -1161,7 +1161,7 @@ void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t SFN, sub_frame_t slot) if (*pucchresset->resourceList.list.array[i] == *PucchResourceId ) idx = i; } - AssertFatal(idx>-1,"SR resource not found among PUCCH resources"); + AssertFatal(idx > -1, "SR resource not found among PUCCH resources"); const NR_ServingCellConfigCommon_t *scc = nrmac->common_channels[CC_id].ServingCellConfigCommon; const NR_TDD_UL_DL_Pattern_t *tdd = scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL; @@ -1169,10 +1169,7 @@ void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t SFN, sub_frame_t slot) const int pucch_index = get_pucch_index(SFN, slot, n_slots_frame, tdd, sched_ctrl->sched_pucch_size); NR_sched_pucch_t *curr_pucch = &sched_ctrl->sched_pucch[pucch_index]; - if (curr_pucch->active && - curr_pucch->frame == SFN && - curr_pucch->ul_slot == slot && - curr_pucch->resource_indicator == idx) + if (curr_pucch->active && curr_pucch->frame == SFN && curr_pucch->ul_slot == slot && curr_pucch->resource_indicator == idx) curr_pucch->sr_flag = true; else if (curr_pucch->active) { LOG_E(NR_MAC, @@ -1185,9 +1182,10 @@ void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t SFN, sub_frame_t slot) continue; } else { - int beam_idx = 0; // TODO proper beam allocation + NR_beam_alloc_t beam = beam_allocation_procedure(&nrmac->beam_info, SFN, slot, UE->UE_beam_index, n_slots_frame); + AssertFatal(beam.idx >= 0, "Cannot allocate SR in any available beam\n"); const int index = ul_buffer_index(SFN, slot, ul_bwp->scs, nrmac->vrb_map_UL_size); - uint16_t *vrb_map_UL = &nrmac->common_channels[CC_id].vrb_map_UL[beam_idx][index * MAX_BWP_SIZE]; + uint16_t *vrb_map_UL = &nrmac->common_channels[CC_id].vrb_map_UL[beam.idx][index * MAX_BWP_SIZE]; const int bwp_start = ul_bwp->BWPStart; const int bwp_size = ul_bwp->BWPSize; set_pucch_allocation(ul_bwp, -1, bwp_size, curr_pucch); From f235b249bab70f274ab47bb8010bd07439e486ed Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 20 Sep 2024 10:45:41 +0200 Subject: [PATCH 08/12] remove FR1 in preprocessor name --- doc/SW_archi.md | 13 ++++--------- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 6 +++--- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 6 +++--- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 8 ++++---- openair2/LAYER2/NR_MAC_gNB/main.c | 4 ++-- 5 files changed, 16 insertions(+), 21 deletions(-) diff --git a/doc/SW_archi.md b/doc/SW_archi.md index 6ba78ad8f1..205da81b6b 100644 --- a/doc/SW_archi.md +++ b/doc/SW_archi.md @@ -220,14 +220,10 @@ Calls nr_schedule_ulsch(): It is divided into the "preprocessor" and the "postprocessor": the first makes the scheduling decisions, the second fills nFAPI structures to indicate to the PHY what it is supposed to do. To signal which users have how many resources, the preprocessor populates the -NR_sched_pusch_t (for values changing every TTI, e.g., frequency domain -allocation) and NR_sched_pusch_save_t (for values changing less frequently, at -least in FR1 [to my understanding], e.g., DMRS fields when the time domain -allocation stays between TTIs) structures. Furthermore, the preprocessor is an +NR_sched_pusch_t structures. Furthermore, the preprocessor is an exchangeable module that schedules differently based on a particular -use-case/deployment type, e.g., one user for phytest [in -nr_ul_preprocessor_phytest()], multiple users in FR1 -[nr_fr1_ulsch_preprocessor()], or maybe FR2 [does not exist yet]: +use-case/deployment type, e.g., one user for phytest in +[nr_ul_preprocessor_phytest()], multiple users in [nr_ulsch_preprocessor()]: * calls preprocessor via pre_processor_ul(): the preprocessor is responsible for allocating CCEs (using allocate_nr_CCEs()) and deciding on resource allocation for the UEs including TB size. Note that we do not yet have @@ -258,8 +254,7 @@ NR_UE_sched_ctrl_t structure of affected users. In particular, the field rbSize decides whether a user is to be allocated. Furthermore, the preprocessor is an exchangeable module that schedules differently based on a particular use-case/deployment type, e.g., one user for phytest [in -nr_preprocessor_phytest()], multiple users in FR1 -[nr_fr1_dlsch_preprocessor()], or maybe FR2 [does not exist yet]. +nr_preprocessor_phytest()], multiple users [nr_dlsch_preprocessor()]. * calls preprocessor via pre_processor_dl(): the preprocessor is responsible for allocating CCEs and PUCCH (using allocate_nr_CCEs() and nr_acknack_scheduling()) and deciding on the frequency/time domain diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 730e954f4b..69b06258dd 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -861,7 +861,7 @@ static void pf_dl(module_id_t module_id, } } -static void nr_fr1_dlsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t slot) +static void nr_dlsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t slot) { NR_UEs_t *UE_info = &RC.nrmac[module_id]->UE_info; @@ -889,7 +889,7 @@ static void nr_fr1_dlsch_preprocessor(module_id_t module_id, frame_t frame, sub_ bw); // we set the whole BW as max number } -nr_pp_impl_dl nr_init_fr1_dlsch_preprocessor(int CC_id) { +nr_pp_impl_dl nr_init_dlsch_preprocessor(int CC_id) { /* during initialization: no mutex needed */ /* in the PF algorithm, we have to use the TBsize to compute the coefficient. * This would include the number of DMRS symbols, which in turn depends on @@ -914,7 +914,7 @@ nr_pp_impl_dl nr_init_fr1_dlsch_preprocessor(int CC_id) { } } - return nr_fr1_dlsch_preprocessor; + return nr_dlsch_preprocessor; } void nr_schedule_ue_spec(module_id_t module_id, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 7f849253da..f754c88040 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -2147,7 +2147,7 @@ static void pf_ul(module_id_t module_id, } } -static bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t slot) +static bool nr_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t slot) { gNB_MAC_INST *nr_mac = RC.nrmac[module_id]; // no UEs @@ -2180,7 +2180,7 @@ static bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_ return true; } -nr_pp_impl_ul nr_init_fr1_ulsch_preprocessor(int CC_id) +nr_pp_impl_ul nr_init_ulsch_preprocessor(int CC_id) { /* during initialization: no mutex needed */ /* in the PF algorithm, we have to use the TBsize to compute the coefficient. @@ -2208,7 +2208,7 @@ nr_pp_impl_ul nr_init_fr1_ulsch_preprocessor(int CC_id) >> 3; } } - return nr_fr1_ulsch_preprocessor; + return nr_ulsch_preprocessor; } void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot, nfapi_nr_ul_dci_request_t *ul_dci_req) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 36c063bd32..d9be5572a7 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -82,8 +82,8 @@ void nr_schedule_ue_spec(module_id_t module_id, nfapi_nr_dl_tti_request_t *DL_req, nfapi_nr_tx_data_request_t *TX_req); -/* \brief default FR1 DL preprocessor init routine, returns preprocessor to call */ -nr_pp_impl_dl nr_init_fr1_dlsch_preprocessor(int CC_id); +/* \brief default DL preprocessor init routine, returns preprocessor to call */ +nr_pp_impl_dl nr_init_dlsch_preprocessor(int CC_id); void schedule_nr_sib1(module_id_t module_idP, frame_t frameP, @@ -108,8 +108,8 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP, * messages, statistics, HARQ handling, ... */ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot, nfapi_nr_ul_dci_request_t *ul_dci_req); -/* \brief default FR1 UL preprocessor init routine, returns preprocessor to call */ -nr_pp_impl_ul nr_init_fr1_ulsch_preprocessor(int CC_id); +/* \brief default UL preprocessor init routine, returns preprocessor to call */ +nr_pp_impl_ul nr_init_ulsch_preprocessor(int CC_id); /////// Random Access MAC-PHY interface functions and primitives /////// diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index f8e6d120de..809ab825aa 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -294,8 +294,8 @@ void mac_top_init_gNB(ngran_node_t node_type, RC.nrmac[i]->pre_processor_dl = nr_preprocessor_phytest; RC.nrmac[i]->pre_processor_ul = nr_ul_preprocessor_phytest; } else { - RC.nrmac[i]->pre_processor_dl = nr_init_fr1_dlsch_preprocessor(0); - RC.nrmac[i]->pre_processor_ul = nr_init_fr1_ulsch_preprocessor(0); + RC.nrmac[i]->pre_processor_dl = nr_init_dlsch_preprocessor(0); + RC.nrmac[i]->pre_processor_ul = nr_init_ulsch_preprocessor(0); } if (!IS_SOFTMODEM_NOSTATS_BIT) threadCreate(&RC.nrmac[i]->stats_thread, nrmac_stats_thread, (void*)RC.nrmac[i], "MAC_STATS", -1, sched_get_priority_min(SCHED_OAI)+1 ); From 5e930b0b727c7cfeb6d758fdaca777275b15ea85 Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 26 Sep 2024 16:36:08 +0200 Subject: [PATCH 09/12] MAC beam allocation for DLSCH --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 133 +++++++++++------- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 18 +-- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 6 +- 3 files changed, 87 insertions(+), 70 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 69b06258dd..ce5bbfe9fd 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -427,6 +427,7 @@ static bool allocate_dl_retransmission(module_id_t module_id, sub_frame_t slot, int *n_rb_sched, NR_UE_info_t *UE, + int beam_idx, int current_harq_pid) { @@ -447,7 +448,7 @@ static bool allocate_dl_retransmission(module_id_t module_id, const int coresetid = sched_ctrl->coreset->controlResourceSetId; const int tda = get_dl_tda(nr_mac, scc, slot); - AssertFatal(tda>=0,"Unable to find PDSCH time domain allocation in list\n"); + AssertFatal(tda >= 0,"Unable to find PDSCH time domain allocation in list\n"); /* Check first whether the old TDA can be reused * this helps allocate retransmission when TDA changes (e.g. new nrOfSymbols > old nrOfSymbols) */ @@ -468,8 +469,7 @@ static bool allocate_dl_retransmission(module_id_t module_id, reuse_old_tda ? "reuse" : "do not reuse", layers == retInfo->nrOfLayers ? "same" : "different"); - // TODO assuming beam 0 for now - uint16_t *rballoc_mask = nr_mac->common_channels[CC_id].vrb_map[0]; + uint16_t *rballoc_mask = nr_mac->common_channels[CC_id].vrb_map[beam_idx]; dl_bwp_info_t bwp_info = get_bwp_start_size(nr_mac, UE); int rbStart = bwp_info.bwpStart; @@ -541,16 +541,13 @@ static bool allocate_dl_retransmission(module_id_t module_id, retInfo->tda_info = temp_tda; } - // TODO properly set the beam index (currently only done for RA) - int beam = 0; - /* Find a free CCE */ int CCEIndex = get_cce_index(nr_mac, CC_id, slot, UE->rnti, &sched_ctrl->aggregation_level, - beam, + beam_idx, sched_ctrl->search_space, sched_ctrl->coreset, &sched_ctrl->sched_pdcch, @@ -566,7 +563,7 @@ static bool allocate_dl_retransmission(module_id_t module_id, int alloc = -1; if (!get_FeedbackDisabled(UE->sc_info.downlinkHARQ_FeedbackDisabled_r17, current_harq_pid)) { int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, ul_bwp->pucch_Config, CCEIndex); - alloc = nr_acknack_scheduling(nr_mac, UE, frame, slot, beam, r_pucch, 0); + alloc = nr_acknack_scheduling(nr_mac, UE, frame, slot, UE->UE_beam_index, r_pucch, 0); if (alloc < 0) { LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not find PUCCH for DL DCI retransmission\n", UE->rnti, frame, slot); return false; @@ -574,12 +571,7 @@ static bool allocate_dl_retransmission(module_id_t module_id, } sched_ctrl->cce_index = CCEIndex; - fill_pdcch_vrb_map(nr_mac, - CC_id, - &sched_ctrl->sched_pdcch, - CCEIndex, - sched_ctrl->aggregation_level, - beam); + fill_pdcch_vrb_map(nr_mac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, sched_ctrl->aggregation_level, beam_idx); /* just reuse from previous scheduling opportunity, set new start RB */ sched_ctrl->sched_pdsch = *retInfo; sched_ctrl->sched_pdsch.rbStart = rbStart - bwp_info.bwpStart; @@ -608,13 +600,16 @@ static void pf_dl(module_id_t module_id, sub_frame_t slot, NR_UE_info_t **UE_list, int max_num_ue, - int n_rb_sched) + int num_beams, + int n_rb_sched[num_beams]) { gNB_MAC_INST *mac = RC.nrmac[module_id]; NR_ServingCellConfigCommon_t *scc=mac->common_channels[0].ServingCellConfigCommon; // UEs that could be scheduled UEsched_t UE_sched[MAX_MOBILES_PER_GNB + 1] = {0}; - int remainUEs = max_num_ue; + int remainUEs[num_beams]; + for (int i = 0; i < num_beams; i++) + remainUEs[i] = max_num_ue; int curUE = 0; int CC_id = 0; @@ -638,23 +633,30 @@ static void pf_dl(module_id_t module_id, const uint32_t b = UE->mac_stats.dl.current_bytes; UE->dl_thr_ue = (1 - a) * UE->dl_thr_ue + a * b; - if (remainUEs == 0) + int total_rem_ues = 0; + for (int i = 0; i < num_beams; i++) + total_rem_ues += remainUEs[i]; + if (total_rem_ues == 0) continue; /* retransmission */ if (sched_pdsch->dl_harq_pid >= 0) { + NR_beam_alloc_t beam = beam_allocation_procedure(&mac->beam_info, + frame, + slot, + UE->UE_beam_index, + nr_slots_per_frame[current_BWP->scs]); + bool sch_ret = beam.idx >= 0; /* Allocate retransmission */ - bool r = allocate_dl_retransmission(module_id, frame, slot, &n_rb_sched, UE, sched_pdsch->dl_harq_pid); - - if (!r) { - LOG_D(NR_MAC, "[UE %04x][%4d.%2d] DL retransmission could not be allocated\n", - UE->rnti, - frame, - slot); + if (sch_ret) + sch_ret = allocate_dl_retransmission(module_id, frame, slot, &n_rb_sched[beam.idx], UE, beam.idx, sched_pdsch->dl_harq_pid); + if (!sch_ret) { + LOG_D(NR_MAC, "[UE %04x][%4d.%2d] DL retransmission could not be allocated\n", UE->rnti, frame, slot); + reset_beam_status(&mac->beam_info, frame, slot, UE->UE_beam_index, nr_slots_per_frame[current_BWP->scs], beam.new_beam); continue; } /* reduce max_num_ue once we are sure UE can be allocated, i.e., has CCE */ - remainUEs--; + remainUEs[beam.idx]--; } else { /* skip this UE if there are no free HARQ processes. This can happen e.g. @@ -716,7 +718,7 @@ static void pf_dl(module_id_t module_id, const int min_rbSize = 5; /* Loop UE_sched to find max coeff and allocate transmission */ - while (remainUEs> 0 && n_rb_sched >= min_rbSize && iterator->UE != NULL) { + while (iterator->UE != NULL) { NR_UE_sched_ctrl_t *sched_ctrl = &iterator->UE->UE_sched_ctrl; const uint16_t rnti = iterator->UE->rnti; @@ -732,6 +734,29 @@ static void pf_dl(module_id_t module_id, iterator++; continue; } + + NR_beam_alloc_t beam = beam_allocation_procedure(&mac->beam_info, + frame, + slot, + iterator->UE->UE_beam_index, + nr_slots_per_frame[dl_bwp->scs]); + + if (beam.idx < 0) { + // no available beam + iterator++; + continue; + } + if (remainUEs[beam.idx] == 0 || n_rb_sched[beam.idx] < min_rbSize) { + reset_beam_status(&mac->beam_info, + frame, + slot, + iterator->UE->UE_beam_index, + nr_slots_per_frame[dl_bwp->scs], + beam.new_beam); + iterator++; + continue; + } + NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch; sched_pdsch->dl_harq_pid = sched_ctrl->available_dl_harq.head; @@ -754,8 +779,7 @@ static void pf_dl(module_id_t module_id, const uint16_t slbitmap = SL_to_bitmap(tda_info->startSymbolIndex, tda_info->nrOfSymbols); - // TODO assuming beam 0 for now - uint16_t *rballoc_mask = mac->common_channels[CC_id].vrb_map[0]; + uint16_t *rballoc_mask = mac->common_channels[CC_id].vrb_map[beam.idx]; dl_bwp_info_t bwp_info = get_bwp_start_size(mac, iterator->UE); int rbStart = 0; // WRT BWP start int rbStop = bwp_info.bwpSize - 1; @@ -782,24 +806,24 @@ static void pf_dl(module_id_t module_id, continue; } - // TODO properly set the beam index (currently only done for RA) - int beam = 0; - int CCEIndex = get_cce_index(mac, CC_id, slot, iterator->UE->rnti, &sched_ctrl->aggregation_level, - beam, + beam.idx, sched_ctrl->search_space, sched_ctrl->coreset, &sched_ctrl->sched_pdcch, false); - if (CCEIndex<0) { - LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not find free CCE for DL DCI\n", - rnti, - frame, - slot); + if (CCEIndex < 0) { + LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not find free CCE for DL DCI\n", rnti, frame, slot); + reset_beam_status(&mac->beam_info, + frame, + slot, + iterator->UE->UE_beam_index, + nr_slots_per_frame[dl_bwp->scs], + beam.new_beam); iterator++; continue; } @@ -810,19 +834,22 @@ static void pf_dl(module_id_t module_id, int alloc = -1; if (!get_FeedbackDisabled(iterator->UE->sc_info.downlinkHARQ_FeedbackDisabled_r17, sched_pdsch->dl_harq_pid)) { int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, ul_bwp->pucch_Config, CCEIndex); - alloc = nr_acknack_scheduling(mac, iterator->UE, frame, slot, beam, r_pucch, 0); + alloc = nr_acknack_scheduling(mac, iterator->UE, frame, slot, iterator->UE->UE_beam_index, r_pucch, 0); if (alloc < 0) { - LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not find PUCCH for DL DCI\n", - rnti, - frame, - slot); + LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not find PUCCH for DL DCI\n", rnti, frame, slot); + reset_beam_status(&mac->beam_info, + frame, + slot, + iterator->UE->UE_beam_index, + nr_slots_per_frame[dl_bwp->scs], + beam.new_beam); iterator++; continue; } } sched_ctrl->cce_index = CCEIndex; - fill_pdcch_vrb_map(mac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, sched_ctrl->aggregation_level, beam); + fill_pdcch_vrb_map(mac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, sched_ctrl->aggregation_level, beam.idx); sched_pdsch->dmrs_parms = get_dl_dmrs_params(scc, dl_bwp, tda_info, sched_pdsch->nrOfLayers); sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, dl_bwp->mcsTableIdx); @@ -851,25 +878,30 @@ static void pf_dl(module_id_t module_id, sched_pdsch->rbStart = rbStart; sched_pdsch->tb_size = TBS; /* transmissions: directly allocate */ - n_rb_sched -= sched_pdsch->rbSize; + n_rb_sched[beam.idx] -= sched_pdsch->rbSize; for (int rb = bwp_start; rb < sched_pdsch->rbSize; rb++) rballoc_mask[rb + sched_pdsch->rbStart] |= slbitmap; - remainUEs--; + remainUEs[beam.idx]--; iterator++; } } static void nr_dlsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t slot) { - NR_UEs_t *UE_info = &RC.nrmac[module_id]->UE_info; + gNB_MAC_INST *mac = RC.nrmac[module_id]; + NR_UEs_t *UE_info = &mac->UE_info; if (UE_info->list[0] == NULL) return; - NR_ServingCellConfigCommon_t *scc = RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon; + NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon; int bw = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth; + int num_beams = mac->beam_info.beam_allocation ? mac->beam_info.beams_per_period : 1; + int n_rb_sched[num_beams]; + for (int i = 0; i < num_beams; i++) + n_rb_sched[i] = bw; /* Retrieve amount of data to send for this UE */ nr_store_dlsch_buffer(module_id, frame, slot); @@ -881,12 +913,7 @@ static void nr_dlsch_preprocessor(module_id_t module_id, frame_t frame, sub_fram max_sched_ues = min(max_sched_ues, MAX_DCI_CORESET); /* proportional fair scheduling algorithm */ - pf_dl(module_id, - frame, - slot, - UE_info->list, - max_sched_ues, - bw); // we set the whole BW as max number + pf_dl(module_id, frame, slot, UE_info->list, max_sched_ues, num_beams, n_rb_sched); } nr_pp_impl_dl nr_init_dlsch_preprocessor(int CC_id) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 0e2f5cb5bf..1b6998ed83 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -558,23 +558,13 @@ int get_cce_index(const gNB_MAC_INST *nrmac, const uint32_t Y = is_common ? 0 : get_Y(ss, slot, rnti); uint8_t nr_of_candidates; - for (int i=0; i<5; i++) { + for (int i = 0; i < 5; i++) { // for now taking the lowest value among the available aggregation levels - find_aggregation_candidates(aggregation_level, - &nr_of_candidates, - ss, - 1<0) + find_aggregation_candidates(aggregation_level, &nr_of_candidates, ss, 1 << i); + if(nr_of_candidates > 0) break; } - int CCEIndex = find_pdcch_candidate(nrmac, - CC_id, - *aggregation_level, - nr_of_candidates, - beam_idx, - sched_pdcch, - coreset, - Y); + int CCEIndex = find_pdcch_candidate(nrmac, CC_id, *aggregation_level, nr_of_candidates, beam_idx, sched_pdcch, coreset, Y); return CCEIndex; } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 6b1eb4abbb..64def07a9e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -983,7 +983,7 @@ int nr_acknack_scheduling(gNB_MAC_INST *mac, NR_UE_info_t *UE, frame_t frame, sub_frame_t slot, - int beam_index, + int ue_beam, int r_pucch, int is_common) { @@ -1073,7 +1073,7 @@ int nr_acknack_scheduling(gNB_MAC_INST *mac, else { // unoccupied occasion // checking if in ul_slot the resources potentially to be assigned to this PUCCH are available set_pucch_allocation(ul_bwp, r_pucch, bwp_size, curr_pucch); - NR_beam_alloc_t beam = beam_allocation_procedure(&mac->beam_info, pucch_frame, pucch_slot, beam_index, n_slots_frame); + NR_beam_alloc_t beam = beam_allocation_procedure(&mac->beam_info, pucch_frame, pucch_slot, ue_beam, n_slots_frame); if (beam.idx < 0) { LOG_D(NR_MAC, "DL %4d.%2d, UL_ACK %4d.%2d beam resources for this occasion are already occupied, move to the following occasion\n", @@ -1093,7 +1093,7 @@ int nr_acknack_scheduling(gNB_MAC_INST *mac, slot, pucch_frame, pucch_slot); - reset_beam_status(&mac->beam_info, pucch_frame, pucch_slot, beam_index, n_slots_frame, beam.new_beam); + reset_beam_status(&mac->beam_info, pucch_frame, pucch_slot, ue_beam, n_slots_frame, beam.new_beam); continue; } // allocating a new PUCCH structure for this occasion From 0cd0ec7a6727212ebf89b1893376374ab53c7907 Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 26 Sep 2024 17:47:39 +0200 Subject: [PATCH 10/12] MAC beam allocation for ULSCH --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 177 ++++++++++++------ 1 file changed, 115 insertions(+), 62 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index f754c88040..b92b83425e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1644,6 +1644,7 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, sub_frame_t slot, uint16_t *rballoc_mask, int *n_rb_sched, + int dci_beam_idx, NR_UE_info_t* UE, int harq_pid, const NR_ServingCellConfigCommon_t *scc, @@ -1733,7 +1734,7 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, slot, UE->rnti, &sched_ctrl->aggregation_level, - 0, // TODO use beam index + dci_beam_idx, sched_ctrl->search_space, sched_ctrl->coreset, &sched_ctrl->sched_pdcch, @@ -1744,12 +1745,7 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, } sched_ctrl->cce_index = CCEIndex; - fill_pdcch_vrb_map(nrmac, - CC_id, - &sched_ctrl->sched_pdcch, - CCEIndex, - sched_ctrl->aggregation_level, - 0); // TODO use beam index when implemented + fill_pdcch_vrb_map(nrmac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, sched_ctrl->aggregation_level, dci_beam_idx); retInfo->frame = (frame + (slot + tda_info.k2) / nr_slots_per_frame[ul_bwp->scs]) % MAX_FRAME_NUMBER; retInfo->slot = (slot + tda_info.k2) % nr_slots_per_frame[ul_bwp->scs]; @@ -1793,7 +1789,8 @@ static void pf_ul(module_id_t module_id, int sched_slot, NR_UE_info_t *UE_list[], int max_num_ue, - int n_rb_sched) + int num_beams, + int n_rb_sched[num_beams]) { const int CC_id = 0; gNB_MAC_INST *nrmac = RC.nrmac[module_id]; @@ -1802,7 +1799,9 @@ static void pf_ul(module_id_t module_id, const int min_rb = nrmac->min_grant_prb; // UEs that could be scheduled UEsched_t UE_sched[MAX_MOBILES_PER_GNB + 1] = {0}; - int remainUEs = max_num_ue; + int remainUEs[num_beams]; + for (int i = 0; i < num_beams; i++) + remainUEs[i] = max_num_ue; int curUE = 0; /* Loop UE_list to calculate throughput and coeff */ @@ -1823,42 +1822,66 @@ static void pf_ul(module_id_t module_id, const uint32_t b = stats->current_bytes; UE->ul_thr_ue = (1 - a) * UE->ul_thr_ue + a * b; - if(remainUEs == 0) + int total_rem_ues = 0; + for (int i = 0; i < num_beams; i++) + total_rem_ues += remainUEs[i]; + if (total_rem_ues == 0) continue; + int n_dl = nr_slots_per_frame[UE->current_DL_BWP.scs]; + NR_beam_alloc_t dci_beam = beam_allocation_procedure(&nrmac->beam_info, frame, slot, UE->UE_beam_index, n_dl); + if (dci_beam.idx < 0) { + LOG_D(NR_MAC, "[UE %04x][%4d.%2d] Beam could not be allocated\n", UE->rnti, frame, slot); + continue; + } + + int n = nr_slots_per_frame[current_BWP->scs]; + NR_beam_alloc_t beam = beam_allocation_procedure(&nrmac->beam_info, sched_pusch->frame, sched_pusch->slot, UE->UE_beam_index, n); + if (beam.idx < 0) { + LOG_D(NR_MAC, "[UE %04x][%4d.%2d] Beam could not be allocated\n", UE->rnti, frame, slot); + reset_beam_status(&nrmac->beam_info, frame, slot, UE->UE_beam_index, n_dl, dci_beam.new_beam); + continue; + } const int index = ul_buffer_index(sched_frame, sched_slot, current_BWP->scs, nrmac->vrb_map_UL_size); - // TODO improve handling of beam in vrb_map (for now just using 0) - uint16_t *rballoc_mask = &nrmac->common_channels[CC_id].vrb_map_UL[0][index * MAX_BWP_SIZE]; + uint16_t *rballoc_mask = &nrmac->common_channels[CC_id].vrb_map_UL[beam.idx][index * MAX_BWP_SIZE]; /* Check if retransmission is necessary */ sched_pusch->ul_harq_pid = sched_ctrl->retrans_ul_harq.head; - LOG_D(NR_MAC,"pf_ul: UE %04x harq_pid %d\n",UE->rnti,sched_pusch->ul_harq_pid); + LOG_D(NR_MAC,"pf_ul: UE %04x harq_pid %d\n", UE->rnti, sched_pusch->ul_harq_pid); if (sched_pusch->ul_harq_pid >= 0) { /* Allocate retransmission*/ const int tda = get_ul_tda(nrmac, scc, sched_frame, sched_slot); - bool r = allocate_ul_retransmission(nrmac, frame, slot, rballoc_mask, &n_rb_sched, UE, sched_pusch->ul_harq_pid, scc, tda); + bool r = allocate_ul_retransmission(nrmac, + frame, + slot, + rballoc_mask, + &n_rb_sched[beam.idx], + dci_beam.idx, + UE, + sched_pusch->ul_harq_pid, + scc, + tda); if (!r) { - LOG_D(NR_MAC, "[UE %04x][%4d.%2d] UL retransmission could not be allocated\n", - UE->rnti, - frame, - slot); + LOG_D(NR_MAC, "[UE %04x][%4d.%2d] UL retransmission could not be allocated\n", UE->rnti, frame, slot); + reset_beam_status(&nrmac->beam_info, sched_pusch->frame, sched_pusch->slot, UE->UE_beam_index, n, beam.new_beam); + reset_beam_status(&nrmac->beam_info, frame, slot, UE->UE_beam_index, n_dl, dci_beam.new_beam); continue; } - else LOG_D(NR_MAC,"%4d.%2d UL Retransmission UE RNTI %04x to be allocated, max_num_ue %d\n",frame,slot,UE->rnti,max_num_ue); + else + LOG_D(NR_MAC,"%4d.%2d UL Retransmission UE RNTI %04x to be allocated, max_num_ue %d\n", frame, slot, UE->rnti,max_num_ue); /* reduce max_num_ue once we are sure UE can be allocated, i.e., has CCE */ - remainUEs--; + remainUEs[beam.idx]--; continue; - } + } /* skip this UE if there are no free HARQ processes. This can happen e.g. * if the UE disconnected in L2sim, in which case the gNB is not notified * (this can be considered a design flaw) */ if (sched_ctrl->available_ul_harq.head < 0) { - LOG_D(NR_MAC, "[UE %04x][%4d.%2d] has no free UL HARQ process, skipping\n", - UE->rnti, - frame, - slot); + reset_beam_status(&nrmac->beam_info, sched_pusch->frame, sched_pusch->slot, UE->UE_beam_index, n, beam.new_beam); + reset_beam_status(&nrmac->beam_info, frame, slot, UE->UE_beam_index, n_dl, dci_beam.new_beam); + LOG_D(NR_MAC, "[UE %04x][%4d.%2d] has no free UL HARQ process, skipping\n", UE->rnti, frame, slot); continue; } @@ -1866,8 +1889,10 @@ static void pf_ul(module_id_t module_id, /* preprocessor computed sched_frame/sched_slot */ const bool do_sched = nr_UE_is_to_be_scheduled(scc, 0, UE, sched_frame, sched_slot, nrmac->ulsch_max_frame_inactivity); - LOG_D(NR_MAC,"pf_ul: do_sched UE %04x => %s\n",UE->rnti,do_sched ? "yes" : "no"); + LOG_D(NR_MAC,"pf_ul: do_sched UE %04x => %s\n", UE->rnti, do_sched ? "yes" : "no"); if ((B == 0 && !do_sched) || nr_timer_is_active(&sched_ctrl->transm_interrupt)) { + reset_beam_status(&nrmac->beam_info, sched_pusch->frame, sched_pusch->slot, UE->UE_beam_index, n, beam.new_beam); + reset_beam_status(&nrmac->beam_info, frame, slot, UE->UE_beam_index, n_dl, dci_beam.new_beam); continue; } @@ -1879,7 +1904,7 @@ static void pf_ul(module_id_t module_id, sched_ctrl->ul_bler_stats.mcs = sched_pusch->mcs; } else { sched_pusch->mcs = get_mcs_from_bler(bo, stats, &sched_ctrl->ul_bler_stats, max_mcs, frame); - LOG_D(NR_MAC,"%d.%d starting mcs %d bleri %f\n",frame,slot,sched_pusch->mcs,sched_ctrl->ul_bler_stats.bler); + LOG_D(NR_MAC,"%d.%d starting mcs %d bleri %f\n", frame, slot, sched_pusch->mcs, sched_ctrl->ul_bler_stats.bler); } /* Schedule UE on SR or UL inactivity and no data (otherwise, will be scheduled * based on data to transmit) */ @@ -1889,16 +1914,15 @@ static void pf_ul(module_id_t module_id, int CCEIndex = get_cce_index(nrmac, CC_id, slot, UE->rnti, &sched_ctrl->aggregation_level, - 0, // TODO use beam index + dci_beam.idx, sched_ctrl->search_space, sched_ctrl->coreset, &sched_ctrl->sched_pdcch, false); - if (CCEIndex<0) { - LOG_D(NR_MAC, "[UE %04x][%4d.%2d] no free CCE for UL DCI (BSR 0)\n", - UE->rnti, - frame, - slot); + if (CCEIndex < 0) { + LOG_D(NR_MAC, "[UE %04x][%4d.%2d] no free CCE for UL DCI (BSR 0)\n", UE->rnti, frame, slot); + reset_beam_status(&nrmac->beam_info, sched_pusch->frame, sched_pusch->slot, UE->UE_beam_index, n, beam.new_beam); + reset_beam_status(&nrmac->beam_info, frame, slot, UE->UE_beam_index, n_dl, dci_beam.new_beam); continue; } @@ -1910,10 +1934,7 @@ static void pf_ul(module_id_t module_id, TYPE_C_RNTI_, sched_pusch->time_domain_allocation); AssertFatal(sched_pusch->tda_info.valid_tda, "Invalid TDA from get_ul_tda_info\n"); - sched_pusch->dmrs_info = get_ul_dmrs_params(scc, - current_BWP, - &sched_pusch->tda_info, - sched_pusch->nrOfLayers); + sched_pusch->dmrs_info = get_ul_dmrs_params(scc, current_BWP, &sched_pusch->tda_info, sched_pusch->nrOfLayers); int rbStart = 0; // wrt BWP start LOG_D(NR_MAC, @@ -1935,11 +1956,13 @@ static void pf_ul(module_id_t module_id, rbStart, min_rb, bwpSize); + reset_beam_status(&nrmac->beam_info, sched_pusch->frame, sched_pusch->slot, UE->UE_beam_index, n, beam.new_beam); + reset_beam_status(&nrmac->beam_info, frame, slot, UE->UE_beam_index, n_dl, dci_beam.new_beam); continue; } sched_ctrl->cce_index = CCEIndex; - fill_pdcch_vrb_map(nrmac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, sched_ctrl->aggregation_level, 0); // TODO use beam index + fill_pdcch_vrb_map(nrmac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, sched_ctrl->aggregation_level, dci_beam.idx); NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; sched_pusch->mcs = min(nrmac->min_grant_mcs, sched_pusch->mcs); @@ -1977,11 +2000,11 @@ static void pf_ul(module_id_t module_id, sched_pusch->phr_txpower_calc); /* Mark the corresponding RBs as used */ - n_rb_sched -= sched_pusch->rbSize; + n_rb_sched[beam.idx] -= sched_pusch->rbSize; for (int rb = bwpStart; rb < sched_ctrl->sched_pusch.rbSize; rb++) rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] |= slbitmap; - remainUEs--; + remainUEs[beam.idx]--; continue; } @@ -2006,31 +2029,59 @@ static void pf_ul(module_id_t module_id, UEsched_t *iterator=UE_sched; /* Loop UE_sched to find max coeff and allocate transmission */ - while (remainUEs > 0 && n_rb_sched >= min_rb && iterator->UE != NULL) { - + while (iterator->UE != NULL) { + NR_UE_UL_BWP_t *current_BWP = &iterator->UE->current_UL_BWP; + NR_UE_DL_BWP_t *dl_BWP = &iterator->UE->current_DL_BWP; NR_UE_sched_ctrl_t *sched_ctrl = &iterator->UE->UE_sched_ctrl; + NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; + + int n = nr_slots_per_frame[current_BWP->scs]; + NR_beam_alloc_t beam = beam_allocation_procedure(&nrmac->beam_info, + sched_pusch->frame, + sched_pusch->slot, + iterator->UE->UE_beam_index, + n); + if (beam.idx < 0) { + LOG_D(NR_MAC, "[UE %04x][%4d.%2d] Beam could not be allocated\n", iterator->UE->rnti, frame, slot); + iterator++; + continue; + } + + if (remainUEs[beam.idx] == 0 || n_rb_sched[beam.idx] < min_rb) { + reset_beam_status(&nrmac->beam_info, sched_pusch->frame, sched_pusch->slot, iterator->UE->UE_beam_index, n, beam.new_beam); + iterator++; + continue; + } + + int n_dl = nr_slots_per_frame[dl_BWP->scs]; + NR_beam_alloc_t dci_beam = beam_allocation_procedure(&nrmac->beam_info, frame, slot, iterator->UE->UE_beam_index, n_dl); + if (dci_beam.idx < 0) { + LOG_D(NR_MAC, "[UE %04x][%4d.%2d] Beam could not be allocated\n", iterator->UE->rnti, frame, slot); + reset_beam_status(&nrmac->beam_info, sched_pusch->frame, sched_pusch->slot, iterator->UE->UE_beam_index, n, beam.new_beam); + iterator++; + continue; + } + int CCEIndex = get_cce_index(nrmac, CC_id, slot, iterator->UE->rnti, &sched_ctrl->aggregation_level, - 0, // TODO use beam index + dci_beam.idx, sched_ctrl->search_space, sched_ctrl->coreset, &sched_ctrl->sched_pdcch, false); - if (CCEIndex<0) { - LOG_D(NR_MAC, "[UE %04x][%4d.%2d] no free CCE for UL DCI\n", - iterator->UE->rnti, - frame, - slot); + if (CCEIndex < 0) { + reset_beam_status(&nrmac->beam_info, frame, slot, iterator->UE->UE_beam_index, n_dl, dci_beam.new_beam); + reset_beam_status(&nrmac->beam_info, sched_pusch->frame, sched_pusch->slot, iterator->UE->UE_beam_index, n, beam.new_beam); + LOG_D(NR_MAC, "[UE %04x][%4d.%2d] no free CCE for UL DCI\n", iterator->UE->rnti, frame, slot); iterator++; continue; } - else LOG_D(NR_MAC, "%4d.%2d free CCE for UL DCI UE %04x\n",frame,slot, iterator->UE->rnti); + else + LOG_D(NR_MAC, "%4d.%2d free CCE for UL DCI UE %04x\n", frame, slot, iterator->UE->rnti); - NR_UE_UL_BWP_t *current_BWP = &iterator->UE->current_UL_BWP; - NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; sched_pusch->nrOfLayers = sched_ctrl->srs_feedback.ul_ri + 1; sched_pusch->time_domain_allocation = get_ul_tda(nrmac, scc, sched_frame, sched_slot); @@ -2040,14 +2091,10 @@ static void pf_ul(module_id_t module_id, TYPE_C_RNTI_, sched_pusch->time_domain_allocation); AssertFatal(sched_pusch->tda_info.valid_tda, "Invalid TDA from get_ul_tda_info\n"); - sched_pusch->dmrs_info = get_ul_dmrs_params(scc, - current_BWP, - &sched_pusch->tda_info, - sched_pusch->nrOfLayers); + sched_pusch->dmrs_info = get_ul_dmrs_params(scc, current_BWP, &sched_pusch->tda_info, sched_pusch->nrOfLayers); const int index = ul_buffer_index(sched_frame, sched_slot, current_BWP->scs, nrmac->vrb_map_UL_size); - // TODO improve handling of beam in vrb_map (for now just using 0) - uint16_t *rballoc_mask = &nrmac->common_channels[CC_id].vrb_map_UL[0][index * MAX_BWP_SIZE]; + uint16_t *rballoc_mask = &nrmac->common_channels[CC_id].vrb_map_UL[beam.idx][index * MAX_BWP_SIZE]; int rbStart = 0; const uint16_t slbitmap = SL_to_bitmap(sched_pusch->tda_info.startSymbolIndex, sched_pusch->tda_info.nrOfSymbols); @@ -2061,6 +2108,8 @@ static void pf_ul(module_id_t module_id, max_rbSize++; if (rbStart + min_rb >= bwpSize || max_rbSize < min_rb) { + reset_beam_status(&nrmac->beam_info, frame, slot, iterator->UE->UE_beam_index, n_dl, dci_beam.new_beam); + reset_beam_status(&nrmac->beam_info, sched_pusch->frame, sched_pusch->slot, iterator->UE->UE_beam_index, n, beam.new_beam); LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not allocate UL data: no resources (rbStart %d, min_rb %d, bwpSize %d)\n", iterator->UE->rnti, frame, @@ -2135,14 +2184,14 @@ static void pf_ul(module_id_t module_id, /* Mark the corresponding RBs as used */ sched_ctrl->cce_index = CCEIndex; - fill_pdcch_vrb_map(nrmac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, sched_ctrl->aggregation_level, 0); // TODO use beam index + fill_pdcch_vrb_map(nrmac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, sched_ctrl->aggregation_level, dci_beam.idx); - n_rb_sched -= sched_pusch->rbSize; + n_rb_sched[beam.idx] -= sched_pusch->rbSize; for (int rb = bwpStart; rb < sched_ctrl->sched_pusch.rbSize; rb++) rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] |= slbitmap; /* reduce max_num_ue once we are sure UE can be allocated, i.e., has CCE */ - remainUEs--; + remainUEs[beam.idx]--; iterator++; } } @@ -2167,8 +2216,12 @@ static bool nr_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_fram if (!is_xlsch_in_slot(nr_mac->ulsch_slot_bitmap[sched_slot / 64], sched_slot)) return false; + int num_beams = nr_mac->beam_info.beam_allocation ? nr_mac->beam_info.beams_per_period : 1; int bw = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth; - + int len[num_beams]; + for (int i = 0; i < num_beams; i++) + len[i] = bw; + int average_agg_level = 4; // TODO find a better estimation int max_sched_ues = bw / (average_agg_level * NR_NB_REG_PER_CCE); @@ -2176,7 +2229,7 @@ static bool nr_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_fram max_sched_ues = min(max_sched_ues, MAX_DCI_CORESET); /* proportional fair scheduling algorithm */ - pf_ul(module_id, frame, slot, sched_frame, sched_slot, nr_mac->UE_info.list, max_sched_ues, bw); + pf_ul(module_id, frame, slot, sched_frame, sched_slot, nr_mac->UE_info.list, max_sched_ues, num_beams, len); return true; } From a9c72222dd7bf2e833ed833eef6216c2c92126ae Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 3 Oct 2024 12:25:13 +0200 Subject: [PATCH 11/12] minor: adding two logs for debugging --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c | 1 + openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index bcd5cfb26c..80bb00cfac 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -116,6 +116,7 @@ void clear_beam_information(NR_beam_info_t *beam_info, int frame, int slot, int idx_to_clear = (idx_to_clear + beam_info->beam_allocation_size - 1) % beam_info->beam_allocation_size; if (slot % beam_info->beam_duration == 0) { // resetting previous period allocation + LOG_D(NR_MAC, "%d.%d Clear beam information for index %d\n", frame, slot, idx_to_clear); for (int i = 0; i < beam_info->beams_per_period; i++) beam_info->beam_allocation[i][idx_to_clear] = -1; } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 1b6998ed83..004a0394f6 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -3194,8 +3194,10 @@ NR_beam_alloc_t beam_allocation_procedure(NR_beam_info_t *beam_info, int frame, beam_struct.new_beam = true; *beam = beam_index; } - if (*beam == beam_index) + if (*beam == beam_index) { + LOG_D(NR_MAC, "%d.%d Using beam structure with index %d for beam %d (%s)\n", frame, slot, beam_struct.idx, beam_index, beam_struct.new_beam ? "new beam" : "old beam"); return beam_struct; + } } return (NR_beam_alloc_t) {.new_beam = false, .idx = -1}; @@ -3220,7 +3222,7 @@ void beam_selection_procedures(gNB_MAC_INST *mac, NR_UE_info_t *UE) if (UE->UE_beam_index == new_bf_index) return; // no beam change needed - LOG_I(NR_MAC, "Switching to beam with ID %d corresponding to SSB %d\n", new_bf_index, rsrp_report->resource_id[0]); + LOG_I(NR_MAC, "[UE %x] Switching to beam with ID %d (SSB number %d)\n", UE->rnti, new_bf_index, rsrp_report->resource_id[0]); UE->UE_beam_index = new_bf_index; } From cb6eaa1deb6434b157d00a38234c4757f9dca28b Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 2 Jan 2025 14:00:04 +0100 Subject: [PATCH 12/12] documentation for analog beamforming implementation --- doc/MAC/mac-usage.md | 6 +++--- doc/README.md | 1 + doc/analog_beamforming.md | 30 ++++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 doc/analog_beamforming.md diff --git a/doc/MAC/mac-usage.md b/doc/MAC/mac-usage.md index 4c7bf4df8e..cf69f7cd71 100644 --- a/doc/MAC/mac-usage.md +++ b/doc/MAC/mac-usage.md @@ -192,10 +192,10 @@ In the `MACRLCs` section of the gNB/DU configuration file: * `identity_precoding_matrix` (default 0=false): flag to enable to use only the identity precoding matrix in DL precoding * `set_analog_beamforming` (default 0=false): flag to enable analog - beamforming -* `beam_duration`: duration/number of consecutive slots for a given set of + beamforming (for more information [`analog_beamforming.md`](../analog_beamforming.md)) +* `beam_duration` (default 1): duration/number of consecutive slots for a given set of beams, depending on hardware switching performance -* `beams_per_period`: set of beams that can be simultaneously allocated in a +* `beams_per_period` (default 1): set of beams that can be simultaneously allocated in a period (`beam_duration`) In the `gNBs` section of the gNB/DU configuration file: some of the parameters diff --git a/doc/README.md b/doc/README.md index b703397e3a..c4b24f39ec 100644 --- a/doc/README.md +++ b/doc/README.md @@ -84,6 +84,7 @@ Legacy unmaintained files: - [L1 threads in NR-UE](./nr-ue-design.md) - [Information on gNB MAC](./MAC/mac-usage.md) - [Information on gNB RRC](./RRC/rrc-usage.md) +- [Information on analog beamforming implementation](./analog_beamforming.md) Legacy unmaintained files: - [`5Gnas.md`](./5Gnas.md) diff --git a/doc/analog_beamforming.md b/doc/analog_beamforming.md new file mode 100644 index 0000000000..6d9e5bf71c --- /dev/null +++ b/doc/analog_beamforming.md @@ -0,0 +1,30 @@ +This document explains the implementation of analog beamforming in OAI codebase. + +[[_TOC_]] + +# Introduction to analog beamforming + +Beamforming is a technique applied to antenna arrays to create a directional radiation pattern. This often consists in providing a different phase shift to each element of the array such that signals with a different angle of arrival/departure experience a change in radiation pattern because of constructive or destructive interference. + +There are three main beamforming techinques: analog, digital and hybrid. The names refer to the phase shift application before or after the digital to analog conversion (or analog to digital in reception). When we speak about analog beamforming we generally refer to a techinique where the phase shifts that produce the beam stearing are applied by the radio unit (RU) choosing from a finite set of steering directions. The advantage of analog beamforming is a simplified analog circuitry and therefore reduced costs. + +The presence of a limited number of predefined beams at RU poses constraints to the scheduler at gNB. As a matter of fact, the scheduler can serve only a limited number of beams, depending on the RU characteristics (possibly only 1), in a given time scale, that also depends on the RU characteristics (e.g. 1 slot or 1 symbol). This limitation doesn't exist for digital beamforming. + +# Configuration file fields for analog beamforming + +A set of parameters in configuration files controls the implementation of analog beamforming and instructs the scheduler on how to behave in such scenarios. Since most notably this technique in 5G is employed in FR2, the configuration file example currently available is a RFsim one for band 261. [Config file example](../ci-scripts/conf_files/gnb.sa.band261.u3.32prb.rfsim.conf) + +In the `MACRLC` section of configuration files, there are three new parameters: `set_analog_beamforming`, `beam_duration` and `beams_per_period`. The explanation of these parameters is here provided: +- `set_analog_beamforming` can be set to 1 or 0 to activate or desactivate analog beamforming (default value is 0) +- `beam_duration` is the number of slots (currently minimum duration of a beam) the scheduler is tied to a beam (default value is 1) +- `beams_per_period` is the number of concurrent beams the RU can handle in the beam duration (default value is 1) + +In the `gNBs` section of the configuration file, under the phyisical parameters, a vector field containing the set of beam indices to be provided by the OAI L1 to the RU is also required. This field is called `beam_weights`. In current implementation, the number of beam indices should be equal to the number of SSBs transmitted. + +# Implementation in OAI scheduler + +A new MAC structure `NR_beam_info_t` controls the behavior of the scheduler in presence of analog beamforming. Besides the already mentioned parameters `beam_duration` and `beams_per_period`, the structure also holds a matrix `beam_allocation[i][j]`, whose indices `i` and `j` stands respectively for the number of beams in the period and the slot index (the size of the latter depends on the frame characteristics). +This matrix contains the beams already allocated in a given slot, to flag the scheduler to use one of these to schedule a UE in one of these beams. If the matrix is full (all the beams in the given period, e.g. slot) are already allocated, the scheduler can't allocate a UE in a new beam. +To this goal, we extended the virtual resource block (VRB) map by one dimension to also contain information per allocated beam. As said, the scheduler can independently schedule users in a number of beams up to `beams_per_period` concurrently. + +It is important to note that in current implementation, there are several periodical channels, e.g. PRACH or PUCCH for CSI et cetera, that have the precendence in being assigned a beam, that is because the scheduling is automatic, set in RRC configuration, and not up to the scheduler. For these instances, we assume the beam is available (if not there are assertions to stop the process). For data channels, the currently implemented PF scheduler is used. The only modification is that a UE can be served only if there is a free beam available or the one of the beams already in use correspond to that UE beam.