From 82c4380a4e6af719d18a9bde1e71a7d00a2c2ab2 Mon Sep 17 00:00:00 2001 From: Francesco Mani <francesco.mani@eurecom.fr> Date: Fri, 20 Nov 2020 10:22:10 +0100 Subject: [PATCH] uci mac functions in a new file --- cmake_targets/CMakeLists.txt | 1 + openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c | 55 -- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 94 --- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 396 ------------ .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 581 ++++++++++++++++++ openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 3 + 6 files changed, 585 insertions(+), 545 deletions(-) create mode 100644 openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 900d4c8324..de9915a68b 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -2031,6 +2031,7 @@ set (MAC_NR_SRC ${NR_GNB_MAC_DIR}/gNB_scheduler_ulsch.c ${NR_GNB_MAC_DIR}/gNB_scheduler_primitives.c ${NR_GNB_MAC_DIR}/gNB_scheduler_phytest.c + ${NR_GNB_MAC_DIR}/gNB_scheduler_uci.c ${NR_GNB_MAC_DIR}/gNB_scheduler_RA.c ) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index 5d701bf5b8..e4c2e11d7d 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -337,61 +337,6 @@ void nr_schedule_pusch(int Mod_idP, } } - -void nr_schedule_pucch(int Mod_idP, - int UE_id, - int nr_ulmix_slots, - frame_t frameP, - sub_frame_t slotP) { - - uint16_t O_csi, O_ack, O_uci; - uint8_t O_sr = 0; // no SR in PUCCH implemented for now - NR_ServingCellConfigCommon_t *scc = RC.nrmac[Mod_idP]->common_channels->ServingCellConfigCommon; - NR_UE_info_t *UE_info = &RC.nrmac[Mod_idP]->UE_info; - AssertFatal(UE_info->active[UE_id],"Cannot find UE_id %d is not active\n",UE_id); - - NR_CellGroupConfig_t *secondaryCellGroup = UE_info->secondaryCellGroup[UE_id]; - int bwp_id=1; - NR_BWP_Uplink_t *ubwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1]; - nfapi_nr_ul_tti_request_t *UL_tti_req = &RC.nrmac[Mod_idP]->UL_tti_req[0]; - - NR_sched_pucch *curr_pucch; - - for (int k=0; k<nr_ulmix_slots; k++) { - for (int l=0; l<2; l++) { - curr_pucch = &UE_info->UE_sched_ctrl[UE_id].sched_pucch[k][l]; - O_ack = curr_pucch->dai_c; - O_csi = curr_pucch->csi_bits; - O_uci = O_ack + O_csi + O_sr; - if ((O_uci>0) && (frameP == curr_pucch->frame) && (slotP == curr_pucch->ul_slot)) { - UL_tti_req->SFN = curr_pucch->frame; - UL_tti_req->Slot = curr_pucch->ul_slot; - UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE; - UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_pucch_pdu_t); - nfapi_nr_pucch_pdu_t *pucch_pdu = &UL_tti_req->pdus_list[UL_tti_req->n_pdus].pucch_pdu; - memset(pucch_pdu,0,sizeof(nfapi_nr_pucch_pdu_t)); - UL_tti_req->n_pdus+=1; - - LOG_D(MAC,"Scheduling pucch reception for frame %d slot %d with (%d, %d, %d) (SR ACK, CSI) bits\n", - frameP,slotP,O_sr,O_ack,curr_pucch->csi_bits); - - nr_configure_pucch(pucch_pdu, - scc, - ubwp, - UE_info->rnti[UE_id], - curr_pucch->resource_indicator, - O_csi, - O_ack, - O_sr); - - memset((void *) &UE_info->UE_sched_ctrl[UE_id].sched_pucch[k][l], - 0, - sizeof(NR_sched_pucch)); - } - } - } -} - bool is_xlsch_in_slot(uint64_t bitmap, sub_frame_t slot) { return (bitmap >> slot) & 0x01; } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 7a7fe1288c..2902617c23 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -343,100 +343,6 @@ int nr_generate_dlsch_pdu(module_id_t module_idP, return offset; } -void nr_rx_acknack(nfapi_nr_uci_pusch_pdu_t *uci_pusch, - nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_01, - nfapi_nr_uci_pucch_pdu_format_2_3_4_t *uci_234, - NR_UL_IND_t *UL_info, NR_UE_sched_ctrl_t *sched_ctrl, NR_mac_stats_t *stats) { - - // TODO - int max_harq_rounds = 4; // TODO define macro - - if (uci_01 != NULL) { - // handle harq - int harq_idx_s = 0; - - // iterate over received harq bits - for (int harq_bit = 0; harq_bit < uci_01->harq->num_harq; harq_bit++) { - // search for the right harq process - for (int harq_idx = harq_idx_s; harq_idx < NR_MAX_NB_HARQ_PROCESSES; harq_idx++) { - // if the gNB received ack with a good confidence - if ((UL_info->slot-1) == sched_ctrl->harq_processes[harq_idx].feedback_slot) { - if ((uci_01->harq->harq_list[harq_bit].harq_value == 1) && - (uci_01->harq->harq_confidence_level == 0)) { - // toggle NDI and reset round - sched_ctrl->harq_processes[harq_idx].ndi ^= 1; - sched_ctrl->harq_processes[harq_idx].round = 0; - } - else - sched_ctrl->harq_processes[harq_idx].round++; - sched_ctrl->harq_processes[harq_idx].is_waiting = 0; - harq_idx_s = harq_idx + 1; - // if the max harq rounds was reached - if (sched_ctrl->harq_processes[harq_idx].round == max_harq_rounds) { - sched_ctrl->harq_processes[harq_idx].ndi ^= 1; - sched_ctrl->harq_processes[harq_idx].round = 0; - stats->dlsch_errors++; - } - break; - } - // if feedback slot processing is aborted - else if (((UL_info->slot-1) > sched_ctrl->harq_processes[harq_idx].feedback_slot) && - (sched_ctrl->harq_processes[harq_idx].is_waiting)) { - sched_ctrl->harq_processes[harq_idx].round++; - if (sched_ctrl->harq_processes[harq_idx].round == max_harq_rounds) { - sched_ctrl->harq_processes[harq_idx].ndi ^= 1; - sched_ctrl->harq_processes[harq_idx].round = 0; - } - sched_ctrl->harq_processes[harq_idx].is_waiting = 0; - } - } - } - } - - - if (uci_234 != NULL) { - int harq_idx_s = 0; - int acknack; - - // iterate over received harq bits - for (int harq_bit = 0; harq_bit < uci_234->harq.harq_bit_len; harq_bit++) { - acknack = ((uci_234->harq.harq_payload[harq_bit>>3])>>harq_bit)&0x01; - for (int harq_idx = harq_idx_s; harq_idx < NR_MAX_NB_HARQ_PROCESSES-1; harq_idx++) { - // if the gNB received ack with a good confidence or if the max harq rounds was reached - if ((UL_info->slot-1) == sched_ctrl->harq_processes[harq_idx].feedback_slot) { - // TODO add some confidence level for when there is no CRC - if ((uci_234->harq.harq_crc != 1) && acknack) { - // toggle NDI and reset round - sched_ctrl->harq_processes[harq_idx].ndi ^= 1; - sched_ctrl->harq_processes[harq_idx].round = 0; - } - else - sched_ctrl->harq_processes[harq_idx].round++; - sched_ctrl->harq_processes[harq_idx].is_waiting = 0; - harq_idx_s = harq_idx + 1; - // if the max harq rounds was reached - if (sched_ctrl->harq_processes[harq_idx].round == max_harq_rounds) { - sched_ctrl->harq_processes[harq_idx].ndi ^= 1; - sched_ctrl->harq_processes[harq_idx].round = 0; - stats->dlsch_errors++; - } - break; - } - // if feedback slot processing is aborted - else if (((UL_info->slot-1) > sched_ctrl->harq_processes[harq_idx].feedback_slot) && - (sched_ctrl->harq_processes[harq_idx].is_waiting)) { - sched_ctrl->harq_processes[harq_idx].round++; - if (sched_ctrl->harq_processes[harq_idx].round == max_harq_rounds) { - sched_ctrl->harq_processes[harq_idx].ndi ^= 1; - sched_ctrl->harq_processes[harq_idx].round = 0; - } - sched_ctrl->harq_processes[harq_idx].is_waiting = 0; - } - } - } - } -} - int getNrOfSymbols(NR_BWP_Downlink_t *bwp, int tda) { struct NR_PDSCH_TimeDomainResourceAllocationList *tdaList = bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index c6d9a86fce..11d9e9d897 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -915,84 +915,6 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, } -uint16_t compute_pucch_prb_size(uint8_t format, - uint8_t nr_prbs, - uint16_t O_tot, - uint16_t O_csi, - NR_PUCCH_MaxCodeRate_t *maxCodeRate, - uint8_t Qm, - uint8_t n_symb, - uint8_t n_re_ctrl) { - - uint16_t O_crc; - - if (O_tot<12) - O_crc = 0; - else{ - if (O_tot<20) - O_crc = 6; - else { - if (O_tot<360) - O_crc = 11; - else - AssertFatal(1==0,"Case for segmented PUCCH not yet implemented"); - } - } - - int rtimes100; - switch(*maxCodeRate){ - case NR_PUCCH_MaxCodeRate_zeroDot08 : - rtimes100 = 8; - break; - case NR_PUCCH_MaxCodeRate_zeroDot15 : - rtimes100 = 15; - break; - case NR_PUCCH_MaxCodeRate_zeroDot25 : - rtimes100 = 25; - break; - case NR_PUCCH_MaxCodeRate_zeroDot35 : - rtimes100 = 35; - break; - case NR_PUCCH_MaxCodeRate_zeroDot45 : - rtimes100 = 45; - break; - case NR_PUCCH_MaxCodeRate_zeroDot60 : - rtimes100 = 60; - break; - case NR_PUCCH_MaxCodeRate_zeroDot80 : - rtimes100 = 80; - break; - default : - AssertFatal(1==0,"Invalid MaxCodeRate"); - } - - float r = (float)rtimes100/100; - - if (O_csi == O_tot) { - if ((O_tot+O_csi)>(nr_prbs*n_re_ctrl*n_symb*Qm*r)) - AssertFatal(1==0,"MaxCodeRate %.2f can't support %d UCI bits and %d CRC bits with %d PRBs", - r,O_tot,O_crc,nr_prbs); - else - return nr_prbs; - } - - if (format==2){ - // TODO fix this for multiple CSI reports - for (int i=1; i<=nr_prbs; i++){ - if((O_tot+O_crc)<=(i*n_symb*Qm*n_re_ctrl*r) && - (O_tot+O_crc)>((i-1)*n_symb*Qm*n_re_ctrl*r)) - return i; - } - AssertFatal(1==0,"MaxCodeRate %.2f can't support %d UCI bits and %d CRC bits with at most %d PRBs", - r,O_tot,O_crc,nr_prbs); - } - else{ - AssertFatal(1==0,"Not yet implemented"); - } - -} - - void prepare_dci(NR_CellGroupConfig_t *secondaryCellGroup, dci_pdu_rel15_t *dci_pdu_rel15, nr_dci_format_t format, @@ -1917,324 +1839,6 @@ void get_pdsch_to_harq_feedback(int Mod_idP, } -uint16_t nr_get_csi_bitlen(int Mod_idP, - int UE_id, - uint8_t csi_report_id) { - - uint16_t csi_bitlen =0; - NR_UE_info_t *UE_info = &RC.nrmac[Mod_idP]->UE_info; - CRI_SSBRI_RSRP_bitlen_t * CSI_report_bitlen = NULL; - - CSI_report_bitlen = &(UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0]); - csi_bitlen = ((CSI_report_bitlen->cri_ssbri_bitlen * CSI_report_bitlen->nb_ssbri_cri) + - CSI_report_bitlen->rsrp_bitlen +(CSI_report_bitlen->diff_rsrp_bitlen * - (CSI_report_bitlen->nb_ssbri_cri -1 )) *UE_info->csi_report_template[UE_id][csi_report_id].nb_of_csi_ssb_report); - - return csi_bitlen; -} - - -void csi_period_offset(NR_CSI_ReportConfig_t *csirep, - int *period, int *offset) { - - NR_CSI_ReportPeriodicityAndOffset_PR p_and_o = csirep->reportConfigType.choice.periodic->reportSlotConfig.present; - - switch(p_and_o){ - case NR_CSI_ReportPeriodicityAndOffset_PR_slots4: - *period = 4; - *offset = csirep->reportConfigType.choice.periodic->reportSlotConfig.choice.slots4; - break; - case NR_CSI_ReportPeriodicityAndOffset_PR_slots5: - *period = 5; - *offset = csirep->reportConfigType.choice.periodic->reportSlotConfig.choice.slots5; - break; - case NR_CSI_ReportPeriodicityAndOffset_PR_slots8: - *period = 8; - *offset = csirep->reportConfigType.choice.periodic->reportSlotConfig.choice.slots8; - break; - case NR_CSI_ReportPeriodicityAndOffset_PR_slots10: - *period = 10; - *offset = csirep->reportConfigType.choice.periodic->reportSlotConfig.choice.slots10; - break; - case NR_CSI_ReportPeriodicityAndOffset_PR_slots16: - *period = 16; - *offset = csirep->reportConfigType.choice.periodic->reportSlotConfig.choice.slots16; - break; - case NR_CSI_ReportPeriodicityAndOffset_PR_slots20: - *period = 20; - *offset = csirep->reportConfigType.choice.periodic->reportSlotConfig.choice.slots20; - break; - case NR_CSI_ReportPeriodicityAndOffset_PR_slots40: - *period = 40; - *offset = csirep->reportConfigType.choice.periodic->reportSlotConfig.choice.slots40; - break; - case NR_CSI_ReportPeriodicityAndOffset_PR_slots80: - *period = 80; - *offset = csirep->reportConfigType.choice.periodic->reportSlotConfig.choice.slots80; - break; - case NR_CSI_ReportPeriodicityAndOffset_PR_slots160: - *period = 160; - *offset = csirep->reportConfigType.choice.periodic->reportSlotConfig.choice.slots160; - break; - case NR_CSI_ReportPeriodicityAndOffset_PR_slots320: - *period = 320; - *offset = csirep->reportConfigType.choice.periodic->reportSlotConfig.choice.slots320; - break; - default: - AssertFatal(1==0,"No periodicity and offset resource found in CSI report"); - } -} - - -//!TODO : same function can be written to handle csi_resources -void compute_csi_bitlen (NR_CellGroupConfig_t *secondaryCellGroup, NR_UE_info_t *UE_info, int UE_id) { - uint8_t csi_report_id = 0; - uint8_t csi_resourceidx =0; - uint8_t csi_ssb_idx =0; - - NR_CSI_MeasConfig_t *csi_MeasConfig = secondaryCellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup; - NR_CSI_ResourceConfigId_t csi_ResourceConfigId; - for (csi_report_id=0; csi_report_id < csi_MeasConfig->csi_ReportConfigToAddModList->list.count; csi_report_id++){ - csi_ResourceConfigId=csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]->resourcesForChannelMeasurement; - UE_info->csi_report_template[UE_id][csi_report_id].reportQuantity_type = csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]->reportQuantity.present; - - for ( csi_resourceidx = 0; csi_resourceidx < csi_MeasConfig->csi_ResourceConfigToAddModList->list.count; csi_resourceidx++) { - if ( csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[csi_resourceidx]->csi_ResourceConfigId != csi_ResourceConfigId) - continue; - else { - //Finding the CSI_RS or SSB Resources - UE_info->csi_report_template[UE_id][csi_report_id].CSI_Resource_type= csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[csi_resourceidx]->csi_RS_ResourceSetList.present; - if (NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_nzp_CSI_RS_SSB ==UE_info->csi_report_template[UE_id][csi_report_id].CSI_Resource_type){ - struct NR_CSI_ResourceConfig__csi_RS_ResourceSetList__nzp_CSI_RS_SSB * nzp_CSI_RS_SSB = csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[csi_resourceidx]->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB; - - UE_info->csi_report_template[UE_id][csi_report_id].nb_of_nzp_csi_report = nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList!=NULL ? nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList->list.count:0; - UE_info->csi_report_template[UE_id][csi_report_id].nb_of_csi_ssb_report = nzp_CSI_RS_SSB->csi_SSB_ResourceSetList!=NULL ? nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list.count:0; - } - - if (0 != UE_info->csi_report_template[UE_id][csi_report_id].nb_of_csi_ssb_report){ - uint8_t nb_ssb_resources =0; - for ( csi_ssb_idx = 0; csi_ssb_idx < csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.count; csi_ssb_idx++) { - if (csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceSetId == - *(csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[csi_resourceidx]->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list.array[0])) { ///We can configure only one SSB resource set from spec 38.331 IE CSI-ResourceConfig - if (NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled == - csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]->groupBasedBeamReporting.present ) { - if (NULL != csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]->groupBasedBeamReporting.choice.disabled->nrofReportedRS) - UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].nb_ssbri_cri = *(csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]->groupBasedBeamReporting.choice.disabled->nrofReportedRS)+1; - else - /*! From Spec 38.331 - * nrofReportedRS - * The number (N) of measured RS resources to be reported per report setting in a non-group-based report. N <= N_max, where N_max is either 2 or 4 depending on UE - * capability. FFS: The signaling mechanism for the gNB to select a subset of N beams for the UE to measure and report. - * When the field is absent the UE applies the value 1 - */ - UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].nb_ssbri_cri= 1; - }else - UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].nb_ssbri_cri= 2; - - nb_ssb_resources= csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceList.list.count; - if (nb_ssb_resources){ - UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].cri_ssbri_bitlen =ceil(log2 (nb_ssb_resources)); - UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].rsrp_bitlen = 7; //From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP - UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].diff_rsrp_bitlen =4; //From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP - } - else{ - UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].cri_ssbri_bitlen =0; - UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].rsrp_bitlen = 0; - UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].diff_rsrp_bitlen =0; - } - - LOG_I (MAC, "UCI: CSI_bit len : ssbri %d, rsrp: %d, diff_rsrp: %d", - UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].cri_ssbri_bitlen, - UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].rsrp_bitlen, - UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].diff_rsrp_bitlen); - break ; - } - } - } - if (0 != UE_info->csi_report_template[UE_id][csi_report_id].nb_of_nzp_csi_report){ - AssertFatal(1==0,"Currently configuring only SSB beamreporting."); - } - break; - } - } - } -} - -void nr_csi_meas_reporting(int Mod_idP, - int UE_id, - frame_t frame, - sub_frame_t slot, - int slots_per_tdd, - int ul_slots, - int n_slots_frame) { - - NR_UE_info_t *UE_info = &RC.nrmac[Mod_idP]->UE_info; - NR_sched_pucch *curr_pucch; - NR_PUCCH_ResourceSet_t *pucchresset; - NR_CSI_ReportConfig_t *csirep; - NR_CellGroupConfig_t *secondaryCellGroup = UE_info->secondaryCellGroup[UE_id]; - NR_CSI_MeasConfig_t *csi_measconfig = secondaryCellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup; - NR_BWP_Uplink_t *ubwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[0]; - NR_PUCCH_Config_t *pucch_Config = ubwp->bwp_Dedicated->pucch_Config->choice.setup; - - AssertFatal(csi_measconfig->csi_ReportConfigToAddModList->list.count>0,"NO CSI report configuration available"); - - for (int csi_report_id = 0; csi_report_id < csi_measconfig->csi_ReportConfigToAddModList->list.count; csi_report_id++){ - - csirep = csi_measconfig->csi_ReportConfigToAddModList->list.array[csi_report_id]; - - AssertFatal(csirep->reportConfigType.choice.periodic!=NULL,"Only periodic CSI reporting is implemented currently"); - int period, offset, sched_slot; - csi_period_offset(csirep,&period,&offset); - sched_slot = (period+offset)%n_slots_frame; - // prepare to schedule csi measurement reception according to 5.2.1.4 in 38.214 - // preparation is done in first slot of tdd period - if ( (frame%(period/n_slots_frame)==(offset/n_slots_frame)) && (slot==((sched_slot/slots_per_tdd)*slots_per_tdd))) { - - // we are scheduling pucch for csi in the first pucch occasion (this comes before ack/nack) - curr_pucch = &UE_info->UE_sched_ctrl[UE_id].sched_pucch[sched_slot-slots_per_tdd+ul_slots][0]; - - NR_PUCCH_CSI_Resource_t *pucchcsires = csirep->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list.array[0]; - - int found = -1; - pucchresset = pucch_Config->resourceSetToAddModList->list.array[1]; // set with formats >1 - int n_list = pucchresset->resourceList.list.count; - for (int i=0; i<n_list; i++) { - if (*pucchresset->resourceList.list.array[i] == pucchcsires->pucch_Resource) - found = i; - } - AssertFatal(found>-1,"CSI resource not found among PUCCH resources"); - - curr_pucch->resource_indicator = found; - - n_list = pucch_Config->resourceToAddModList->list.count; - - // going through the list of PUCCH resources to find the one indexed by resource_id - for (int i=0; i<n_list; i++) { - NR_PUCCH_Resource_t *pucchres = pucch_Config->resourceToAddModList->list.array[i]; - if (pucchres->pucch_ResourceId == *pucchresset->resourceList.list.array[found]) { - switch(pucchres->format.present){ - case NR_PUCCH_Resource__format_PR_format2: - if (pucch_Config->format2->choice.setup->simultaneousHARQ_ACK_CSI == NULL) - curr_pucch->simultaneous_harqcsi = false; - else - curr_pucch->simultaneous_harqcsi = true; - break; - case NR_PUCCH_Resource__format_PR_format3: - if (pucch_Config->format3->choice.setup->simultaneousHARQ_ACK_CSI == NULL) - curr_pucch->simultaneous_harqcsi = false; - else - curr_pucch->simultaneous_harqcsi = true; - break; - case NR_PUCCH_Resource__format_PR_format4: - if (pucch_Config->format4->choice.setup->simultaneousHARQ_ACK_CSI == NULL) - curr_pucch->simultaneous_harqcsi = false; - else - curr_pucch->simultaneous_harqcsi = true; - break; - default: - AssertFatal(1==0,"Invalid PUCCH format type"); - } - } - } - curr_pucch->csi_bits += nr_get_csi_bitlen(Mod_idP,UE_id,csi_report_id); // TODO function to compute CSI meas report bit size - curr_pucch->frame = frame; - curr_pucch->ul_slot = sched_slot; - } - } -} - - -// function to update pucch scheduling parameters in UE list when a USS DL is scheduled -void nr_acknack_scheduling(int Mod_idP, - int UE_id, - frame_t frameP, - sub_frame_t slotP, - int slots_per_tdd, - int *pucch_id, - int *pucch_occ) { - - NR_ServingCellConfigCommon_t *scc = RC.nrmac[Mod_idP]->common_channels->ServingCellConfigCommon; - NR_UE_info_t *UE_info = &RC.nrmac[Mod_idP]->UE_info; - NR_sched_pucch *curr_pucch; - int max_acknacks,pucch_res,first_ul_slot_tdd,k,i,l; - uint8_t pdsch_to_harq_feedback[8]; - int found = 0; - int nr_ulmix_slots = scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots; - if (scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols!=0) - nr_ulmix_slots++; - - bool csi_pres=false; - for (k=0; k<nr_ulmix_slots; k++) { - if(UE_info->UE_sched_ctrl[UE_id].sched_pucch[k][0].csi_bits>0) - csi_pres=true; - } - - // As a preference always schedule ack nacks in PUCCH0 (max 2 per slots) - // Unless there is CSI meas reporting scheduled in the period to avoid conflicts in the same slot - if (csi_pres) - max_acknacks=10; - else - max_acknacks=2; - - // this is hardcoded for now as ue specific - NR_SearchSpace__searchSpaceType_PR ss_type = NR_SearchSpace__searchSpaceType_PR_ue_Specific; - get_pdsch_to_harq_feedback(Mod_idP,UE_id,ss_type,pdsch_to_harq_feedback); - - // for each possible ul or mixed slot - for (k=0; k<nr_ulmix_slots; k++) { - for (l=0; l<1; l++) { // scheduling 2 PUCCH in a single slot does not work with the phone, currently - curr_pucch = &UE_info->UE_sched_ctrl[UE_id].sched_pucch[k][l]; - //if it is possible to schedule acknack in current pucch (no exclusive csi pucch) - if ((curr_pucch->csi_bits == 0) || (curr_pucch->simultaneous_harqcsi==true)) { - // if there is free room in current pucch structure - if (curr_pucch->dai_c<max_acknacks) { - pucch_res = get_pucch_resource(UE_info,UE_id,k,l); - if (pucch_res>-1){ - curr_pucch->resource_indicator = pucch_res; - curr_pucch->frame = frameP; - // first pucch occasion in first UL or MIXED slot - first_ul_slot_tdd = scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofDownlinkSlots; - i = 0; - while (i<8 && found == 0) { // look if timing indicator is among allowed values - if (pdsch_to_harq_feedback[i]==(first_ul_slot_tdd+k)-(slotP % slots_per_tdd)) - found = 1; - if (found == 0) i++; - } - if (found == 1) { - // computing slot in which pucch is scheduled - curr_pucch->dai_c++; - curr_pucch->ul_slot = first_ul_slot_tdd + k + (slotP - (slotP % slots_per_tdd)); - curr_pucch->timing_indicator = i; // index in the list of timing indicators - *pucch_id = k; - *pucch_occ = l; - return; - } - } - } - } - } - } - AssertFatal(1==0,"No Uplink slot available in accordance to allowed timing indicator\n"); -} - - -int get_pucch_resource(NR_UE_info_t *UE_info,int UE_id,int k,int l) { - - // to be updated later, for now simple implementation - // use the second allocation just in case there is csi in the first - // in that case use second resource (for a different symbol) see 9.2 in 38.213 - if (l==1) { - if (UE_info->UE_sched_ctrl[UE_id].sched_pucch[k][0].csi_bits==0) - return -1; - else - return 1; - } - else - return 0; - -} - void find_aggregation_candidates(uint8_t *aggregation_level, uint8_t *nr_of_candidates, NR_SearchSpace_t *ss) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c new file mode 100644 index 0000000000..4f298795b4 --- /dev/null +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -0,0 +1,581 @@ +/* + * 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 gNB_scheduler_uci.c + * \brief MAC procedures related to UCI + * \date 2020 + * \version 1.0 + * \company Eurecom + */ + +#include "LAYER2/MAC/mac.h" +#include "NR_MAC_gNB/nr_mac_gNB.h" +#include "NR_MAC_COMMON/nr_mac_extern.h" +#include "NR_MAC_gNB/mac_proto.h" +#include "common/ran_context.h" + +extern RAN_CONTEXT_t RC; + +void nr_schedule_pucch(int Mod_idP, + int UE_id, + int nr_ulmix_slots, + frame_t frameP, + sub_frame_t slotP) { + + uint16_t O_csi, O_ack, O_uci; + uint8_t O_sr = 0; // no SR in PUCCH implemented for now + NR_ServingCellConfigCommon_t *scc = RC.nrmac[Mod_idP]->common_channels->ServingCellConfigCommon; + NR_UE_info_t *UE_info = &RC.nrmac[Mod_idP]->UE_info; + AssertFatal(UE_info->active[UE_id],"Cannot find UE_id %d is not active\n",UE_id); + + NR_CellGroupConfig_t *secondaryCellGroup = UE_info->secondaryCellGroup[UE_id]; + int bwp_id=1; + NR_BWP_Uplink_t *ubwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1]; + nfapi_nr_ul_tti_request_t *UL_tti_req = &RC.nrmac[Mod_idP]->UL_tti_req[0]; + + NR_sched_pucch *curr_pucch; + + for (int k=0; k<nr_ulmix_slots; k++) { + for (int l=0; l<2; l++) { + curr_pucch = &UE_info->UE_sched_ctrl[UE_id].sched_pucch[k][l]; + O_ack = curr_pucch->dai_c; + O_csi = curr_pucch->csi_bits; + O_uci = O_ack + O_csi + O_sr; + if ((O_uci>0) && (frameP == curr_pucch->frame) && (slotP == curr_pucch->ul_slot)) { + UL_tti_req->SFN = curr_pucch->frame; + UL_tti_req->Slot = curr_pucch->ul_slot; + UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE; + UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_pucch_pdu_t); + nfapi_nr_pucch_pdu_t *pucch_pdu = &UL_tti_req->pdus_list[UL_tti_req->n_pdus].pucch_pdu; + memset(pucch_pdu,0,sizeof(nfapi_nr_pucch_pdu_t)); + UL_tti_req->n_pdus+=1; + + LOG_D(MAC,"Scheduling pucch reception for frame %d slot %d with (%d, %d, %d) (SR ACK, CSI) bits\n", + frameP,slotP,O_sr,O_ack,curr_pucch->csi_bits); + + nr_configure_pucch(pucch_pdu, + scc, + ubwp, + UE_info->rnti[UE_id], + curr_pucch->resource_indicator, + O_csi, + O_ack, + O_sr); + + memset((void *) &UE_info->UE_sched_ctrl[UE_id].sched_pucch[k][l], + 0, + sizeof(NR_sched_pucch)); + } + } + } +} + + +//!TODO : same function can be written to handle csi_resources +void compute_csi_bitlen (NR_CellGroupConfig_t *secondaryCellGroup, NR_UE_info_t *UE_info, int UE_id) { + uint8_t csi_report_id = 0; + uint8_t csi_resourceidx =0; + uint8_t csi_ssb_idx =0; + + NR_CSI_MeasConfig_t *csi_MeasConfig = secondaryCellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup; + NR_CSI_ResourceConfigId_t csi_ResourceConfigId; + for (csi_report_id=0; csi_report_id < csi_MeasConfig->csi_ReportConfigToAddModList->list.count; csi_report_id++){ + csi_ResourceConfigId=csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]->resourcesForChannelMeasurement; + UE_info->csi_report_template[UE_id][csi_report_id].reportQuantity_type = csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]->reportQuantity.present; + + for ( csi_resourceidx = 0; csi_resourceidx < csi_MeasConfig->csi_ResourceConfigToAddModList->list.count; csi_resourceidx++) { + if ( csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[csi_resourceidx]->csi_ResourceConfigId != csi_ResourceConfigId) + continue; + else { + //Finding the CSI_RS or SSB Resources + UE_info->csi_report_template[UE_id][csi_report_id].CSI_Resource_type= csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[csi_resourceidx]->csi_RS_ResourceSetList.present; + if (NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_nzp_CSI_RS_SSB ==UE_info->csi_report_template[UE_id][csi_report_id].CSI_Resource_type){ + struct NR_CSI_ResourceConfig__csi_RS_ResourceSetList__nzp_CSI_RS_SSB * nzp_CSI_RS_SSB = csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[csi_resourceidx]->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB; + + UE_info->csi_report_template[UE_id][csi_report_id].nb_of_nzp_csi_report = nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList!=NULL ? nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList->list.count:0; + UE_info->csi_report_template[UE_id][csi_report_id].nb_of_csi_ssb_report = nzp_CSI_RS_SSB->csi_SSB_ResourceSetList!=NULL ? nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list.count:0; + } + + if (0 != UE_info->csi_report_template[UE_id][csi_report_id].nb_of_csi_ssb_report){ + uint8_t nb_ssb_resources =0; + for ( csi_ssb_idx = 0; csi_ssb_idx < csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.count; csi_ssb_idx++) { + if (csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceSetId == + *(csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[csi_resourceidx]->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list.array[0])) { + ///We can configure only one SSB resource set from spec 38.331 IE CSI-ResourceConfig + if (NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled == + csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]->groupBasedBeamReporting.present ) { + if (NULL != csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]->groupBasedBeamReporting.choice.disabled->nrofReportedRS) + UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].nb_ssbri_cri = *(csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]->groupBasedBeamReporting.choice.disabled->nrofReportedRS)+1; + else + /*! From Spec 38.331 + * nrofReportedRS + * The number (N) of measured RS resources to be reported per report setting in a non-group-based report. N <= N_max, where N_max is either 2 or 4 depending on UE + * capability. FFS: The signaling mechanism for the gNB to select a subset of N beams for the UE to measure and report. + * When the field is absent the UE applies the value 1 + */ + UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].nb_ssbri_cri= 1; + } else + UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].nb_ssbri_cri= 2; + + nb_ssb_resources= csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceList.list.count; + if (nb_ssb_resources){ + UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].cri_ssbri_bitlen =ceil(log2 (nb_ssb_resources)); + UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].rsrp_bitlen = 7; //From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP + UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].diff_rsrp_bitlen =4; //From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP + } + else{ + UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].cri_ssbri_bitlen =0; + UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].rsrp_bitlen = 0; + UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].diff_rsrp_bitlen =0; + } + + LOG_I (MAC, "UCI: CSI_bit len : ssbri %d, rsrp: %d, diff_rsrp: %d", + UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].cri_ssbri_bitlen, + UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].rsrp_bitlen, + UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].diff_rsrp_bitlen); + break ; + } + } + } + if (0 != UE_info->csi_report_template[UE_id][csi_report_id].nb_of_nzp_csi_report) + AssertFatal(1==0,"Currently configuring only SSB beamreporting."); + break; + } + } + } +} + + +uint16_t nr_get_csi_bitlen(int Mod_idP, + int UE_id, + uint8_t csi_report_id) { + + uint16_t csi_bitlen =0; + NR_UE_info_t *UE_info = &RC.nrmac[Mod_idP]->UE_info; + CRI_SSBRI_RSRP_bitlen_t * CSI_report_bitlen = NULL; + + CSI_report_bitlen = &(UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0]); + csi_bitlen = ((CSI_report_bitlen->cri_ssbri_bitlen * CSI_report_bitlen->nb_ssbri_cri) + + CSI_report_bitlen->rsrp_bitlen +(CSI_report_bitlen->diff_rsrp_bitlen * + (CSI_report_bitlen->nb_ssbri_cri -1 )) *UE_info->csi_report_template[UE_id][csi_report_id].nb_of_csi_ssb_report); + + return csi_bitlen; +} + + +void nr_csi_meas_reporting(int Mod_idP, + int UE_id, + frame_t frame, + sub_frame_t slot, + int slots_per_tdd, + int ul_slots, + int n_slots_frame) { + + NR_UE_info_t *UE_info = &RC.nrmac[Mod_idP]->UE_info; + NR_sched_pucch *curr_pucch; + NR_PUCCH_ResourceSet_t *pucchresset; + NR_CSI_ReportConfig_t *csirep; + NR_CellGroupConfig_t *secondaryCellGroup = UE_info->secondaryCellGroup[UE_id]; + NR_CSI_MeasConfig_t *csi_measconfig = secondaryCellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup; + NR_BWP_Uplink_t *ubwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[0]; + NR_PUCCH_Config_t *pucch_Config = ubwp->bwp_Dedicated->pucch_Config->choice.setup; + + AssertFatal(csi_measconfig->csi_ReportConfigToAddModList->list.count>0,"NO CSI report configuration available"); + + for (int csi_report_id = 0; csi_report_id < csi_measconfig->csi_ReportConfigToAddModList->list.count; csi_report_id++){ + + csirep = csi_measconfig->csi_ReportConfigToAddModList->list.array[csi_report_id]; + + AssertFatal(csirep->reportConfigType.choice.periodic!=NULL,"Only periodic CSI reporting is implemented currently"); + int period, offset, sched_slot; + csi_period_offset(csirep,&period,&offset); + sched_slot = (period+offset)%n_slots_frame; + // prepare to schedule csi measurement reception according to 5.2.1.4 in 38.214 + // preparation is done in first slot of tdd period + if ( (frame%(period/n_slots_frame)==(offset/n_slots_frame)) && (slot==((sched_slot/slots_per_tdd)*slots_per_tdd))) { + + // we are scheduling pucch for csi in the first pucch occasion (this comes before ack/nack) + curr_pucch = &UE_info->UE_sched_ctrl[UE_id].sched_pucch[sched_slot-slots_per_tdd+ul_slots][0]; + + NR_PUCCH_CSI_Resource_t *pucchcsires = csirep->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list.array[0]; + + int found = -1; + pucchresset = pucch_Config->resourceSetToAddModList->list.array[1]; // set with formats >1 + int n_list = pucchresset->resourceList.list.count; + for (int i=0; i<n_list; i++) { + if (*pucchresset->resourceList.list.array[i] == pucchcsires->pucch_Resource) + found = i; + } + AssertFatal(found>-1,"CSI resource not found among PUCCH resources"); + + curr_pucch->resource_indicator = found; + + n_list = pucch_Config->resourceToAddModList->list.count; + + // going through the list of PUCCH resources to find the one indexed by resource_id + for (int i=0; i<n_list; i++) { + NR_PUCCH_Resource_t *pucchres = pucch_Config->resourceToAddModList->list.array[i]; + if (pucchres->pucch_ResourceId == *pucchresset->resourceList.list.array[found]) { + switch(pucchres->format.present){ + case NR_PUCCH_Resource__format_PR_format2: + if (pucch_Config->format2->choice.setup->simultaneousHARQ_ACK_CSI == NULL) + curr_pucch->simultaneous_harqcsi = false; + else + curr_pucch->simultaneous_harqcsi = true; + break; + case NR_PUCCH_Resource__format_PR_format3: + if (pucch_Config->format3->choice.setup->simultaneousHARQ_ACK_CSI == NULL) + curr_pucch->simultaneous_harqcsi = false; + else + curr_pucch->simultaneous_harqcsi = true; + break; + case NR_PUCCH_Resource__format_PR_format4: + if (pucch_Config->format4->choice.setup->simultaneousHARQ_ACK_CSI == NULL) + curr_pucch->simultaneous_harqcsi = false; + else + curr_pucch->simultaneous_harqcsi = true; + break; + default: + AssertFatal(1==0,"Invalid PUCCH format type"); + } + } + } + curr_pucch->csi_bits += nr_get_csi_bitlen(Mod_idP,UE_id,csi_report_id); // TODO function to compute CSI meas report bit size + curr_pucch->frame = frame; + curr_pucch->ul_slot = sched_slot; + } + } +} + + +void nr_rx_acknack(nfapi_nr_uci_pusch_pdu_t *uci_pusch, + nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_01, + nfapi_nr_uci_pucch_pdu_format_2_3_4_t *uci_234, + NR_UL_IND_t *UL_info, NR_UE_sched_ctrl_t *sched_ctrl, NR_mac_stats_t *stats) { + + // TODO + int max_harq_rounds = 4; // TODO define macro + + if (uci_01 != NULL) { + // handle harq + int harq_idx_s = 0; + + // iterate over received harq bits + for (int harq_bit = 0; harq_bit < uci_01->harq->num_harq; harq_bit++) { + // search for the right harq process + for (int harq_idx = harq_idx_s; harq_idx < NR_MAX_NB_HARQ_PROCESSES; harq_idx++) { + // if the gNB received ack with a good confidence + if ((UL_info->slot-1) == sched_ctrl->harq_processes[harq_idx].feedback_slot) { + if ((uci_01->harq->harq_list[harq_bit].harq_value == 1) && + (uci_01->harq->harq_confidence_level == 0)) { + // toggle NDI and reset round + sched_ctrl->harq_processes[harq_idx].ndi ^= 1; + sched_ctrl->harq_processes[harq_idx].round = 0; + } + else + sched_ctrl->harq_processes[harq_idx].round++; + sched_ctrl->harq_processes[harq_idx].is_waiting = 0; + harq_idx_s = harq_idx + 1; + // if the max harq rounds was reached + if (sched_ctrl->harq_processes[harq_idx].round == max_harq_rounds) { + sched_ctrl->harq_processes[harq_idx].ndi ^= 1; + sched_ctrl->harq_processes[harq_idx].round = 0; + stats->dlsch_errors++; + } + break; + } + // if feedback slot processing is aborted + else if (((UL_info->slot-1) > sched_ctrl->harq_processes[harq_idx].feedback_slot) && + (sched_ctrl->harq_processes[harq_idx].is_waiting)) { + sched_ctrl->harq_processes[harq_idx].round++; + if (sched_ctrl->harq_processes[harq_idx].round == max_harq_rounds) { + sched_ctrl->harq_processes[harq_idx].ndi ^= 1; + sched_ctrl->harq_processes[harq_idx].round = 0; + } + sched_ctrl->harq_processes[harq_idx].is_waiting = 0; + } + } + } + } + + if (uci_234 != NULL) { + int harq_idx_s = 0; + int acknack; + + // iterate over received harq bits + for (int harq_bit = 0; harq_bit < uci_234->harq.harq_bit_len; harq_bit++) { + acknack = ((uci_234->harq.harq_payload[harq_bit>>3])>>harq_bit)&0x01; + for (int harq_idx = harq_idx_s; harq_idx < NR_MAX_NB_HARQ_PROCESSES-1; harq_idx++) { + // if the gNB received ack with a good confidence or if the max harq rounds was reached + if ((UL_info->slot-1) == sched_ctrl->harq_processes[harq_idx].feedback_slot) { + // TODO add some confidence level for when there is no CRC + if ((uci_234->harq.harq_crc != 1) && acknack) { + // toggle NDI and reset round + sched_ctrl->harq_processes[harq_idx].ndi ^= 1; + sched_ctrl->harq_processes[harq_idx].round = 0; + } + else + sched_ctrl->harq_processes[harq_idx].round++; + sched_ctrl->harq_processes[harq_idx].is_waiting = 0; + harq_idx_s = harq_idx + 1; + // if the max harq rounds was reached + if (sched_ctrl->harq_processes[harq_idx].round == max_harq_rounds) { + sched_ctrl->harq_processes[harq_idx].ndi ^= 1; + sched_ctrl->harq_processes[harq_idx].round = 0; + stats->dlsch_errors++; + } + break; + } + // if feedback slot processing is aborted + else if (((UL_info->slot-1) > sched_ctrl->harq_processes[harq_idx].feedback_slot) && + (sched_ctrl->harq_processes[harq_idx].is_waiting)) { + sched_ctrl->harq_processes[harq_idx].round++; + if (sched_ctrl->harq_processes[harq_idx].round == max_harq_rounds) { + sched_ctrl->harq_processes[harq_idx].ndi ^= 1; + sched_ctrl->harq_processes[harq_idx].round = 0; + } + sched_ctrl->harq_processes[harq_idx].is_waiting = 0; + } + } + } + } +} + + +// function to update pucch scheduling parameters in UE list when a USS DL is scheduled +void nr_acknack_scheduling(int Mod_idP, + int UE_id, + frame_t frameP, + sub_frame_t slotP, + int slots_per_tdd, + int *pucch_id, + int *pucch_occ) { + + NR_ServingCellConfigCommon_t *scc = RC.nrmac[Mod_idP]->common_channels->ServingCellConfigCommon; + NR_UE_info_t *UE_info = &RC.nrmac[Mod_idP]->UE_info; + NR_sched_pucch *curr_pucch; + int max_acknacks,pucch_res,first_ul_slot_tdd,k,i,l; + uint8_t pdsch_to_harq_feedback[8]; + int found = 0; + int nr_ulmix_slots = scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots; + if (scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols!=0) + nr_ulmix_slots++; + + bool csi_pres=false; + for (k=0; k<nr_ulmix_slots; k++) { + if(UE_info->UE_sched_ctrl[UE_id].sched_pucch[k][0].csi_bits>0) + csi_pres=true; + } + + // As a preference always schedule ack nacks in PUCCH0 (max 2 per slots) + // Unless there is CSI meas reporting scheduled in the period to avoid conflicts in the same slot + if (csi_pres) + max_acknacks=10; + else + max_acknacks=2; + + // this is hardcoded for now as ue specific + NR_SearchSpace__searchSpaceType_PR ss_type = NR_SearchSpace__searchSpaceType_PR_ue_Specific; + get_pdsch_to_harq_feedback(Mod_idP,UE_id,ss_type,pdsch_to_harq_feedback); + + // for each possible ul or mixed slot + for (k=0; k<nr_ulmix_slots; k++) { + for (l=0; l<1; l++) { // scheduling 2 PUCCH in a single slot does not work with the phone, currently + curr_pucch = &UE_info->UE_sched_ctrl[UE_id].sched_pucch[k][l]; + //if it is possible to schedule acknack in current pucch (no exclusive csi pucch) + if ((curr_pucch->csi_bits == 0) || (curr_pucch->simultaneous_harqcsi==true)) { + // if there is free room in current pucch structure + if (curr_pucch->dai_c<max_acknacks) { + pucch_res = get_pucch_resource(UE_info,UE_id,k,l); + if (pucch_res>-1){ + curr_pucch->resource_indicator = pucch_res; + curr_pucch->frame = frameP; + // first pucch occasion in first UL or MIXED slot + first_ul_slot_tdd = scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofDownlinkSlots; + i = 0; + while (i<8 && found == 0) { // look if timing indicator is among allowed values + if (pdsch_to_harq_feedback[i]==(first_ul_slot_tdd+k)-(slotP % slots_per_tdd)) + found = 1; + if (found == 0) i++; + } + if (found == 1) { + // computing slot in which pucch is scheduled + curr_pucch->dai_c++; + curr_pucch->ul_slot = first_ul_slot_tdd + k + (slotP - (slotP % slots_per_tdd)); + curr_pucch->timing_indicator = i; // index in the list of timing indicators + *pucch_id = k; + *pucch_occ = l; + return; + } + } + } + } + } + } + AssertFatal(1==0,"No Uplink slot available in accordance to allowed timing indicator\n"); +} + + +void csi_period_offset(NR_CSI_ReportConfig_t *csirep, + int *period, int *offset) { + + NR_CSI_ReportPeriodicityAndOffset_PR p_and_o = csirep->reportConfigType.choice.periodic->reportSlotConfig.present; + + switch(p_and_o){ + case NR_CSI_ReportPeriodicityAndOffset_PR_slots4: + *period = 4; + *offset = csirep->reportConfigType.choice.periodic->reportSlotConfig.choice.slots4; + break; + case NR_CSI_ReportPeriodicityAndOffset_PR_slots5: + *period = 5; + *offset = csirep->reportConfigType.choice.periodic->reportSlotConfig.choice.slots5; + break; + case NR_CSI_ReportPeriodicityAndOffset_PR_slots8: + *period = 8; + *offset = csirep->reportConfigType.choice.periodic->reportSlotConfig.choice.slots8; + break; + case NR_CSI_ReportPeriodicityAndOffset_PR_slots10: + *period = 10; + *offset = csirep->reportConfigType.choice.periodic->reportSlotConfig.choice.slots10; + break; + case NR_CSI_ReportPeriodicityAndOffset_PR_slots16: + *period = 16; + *offset = csirep->reportConfigType.choice.periodic->reportSlotConfig.choice.slots16; + break; + case NR_CSI_ReportPeriodicityAndOffset_PR_slots20: + *period = 20; + *offset = csirep->reportConfigType.choice.periodic->reportSlotConfig.choice.slots20; + break; + case NR_CSI_ReportPeriodicityAndOffset_PR_slots40: + *period = 40; + *offset = csirep->reportConfigType.choice.periodic->reportSlotConfig.choice.slots40; + break; + case NR_CSI_ReportPeriodicityAndOffset_PR_slots80: + *period = 80; + *offset = csirep->reportConfigType.choice.periodic->reportSlotConfig.choice.slots80; + break; + case NR_CSI_ReportPeriodicityAndOffset_PR_slots160: + *period = 160; + *offset = csirep->reportConfigType.choice.periodic->reportSlotConfig.choice.slots160; + break; + case NR_CSI_ReportPeriodicityAndOffset_PR_slots320: + *period = 320; + *offset = csirep->reportConfigType.choice.periodic->reportSlotConfig.choice.slots320; + break; + default: + AssertFatal(1==0,"No periodicity and offset resource found in CSI report"); + } +} + + +int get_pucch_resource(NR_UE_info_t *UE_info,int UE_id,int k,int l) { + + // to be updated later, for now simple implementation + // use the second allocation just in case there is csi in the first + // in that case use second resource (for a different symbol) see 9.2 in 38.213 + if (l==1) { + if (UE_info->UE_sched_ctrl[UE_id].sched_pucch[k][0].csi_bits==0) + return -1; + else + return 1; + } + else + return 0; + +} + + +uint16_t compute_pucch_prb_size(uint8_t format, + uint8_t nr_prbs, + uint16_t O_tot, + uint16_t O_csi, + NR_PUCCH_MaxCodeRate_t *maxCodeRate, + uint8_t Qm, + uint8_t n_symb, + uint8_t n_re_ctrl) { + + uint16_t O_crc; + + if (O_tot<12) + O_crc = 0; + else{ + if (O_tot<20) + O_crc = 6; + else { + if (O_tot<360) + O_crc = 11; + else + AssertFatal(1==0,"Case for segmented PUCCH not yet implemented"); + } + } + + int rtimes100; + switch(*maxCodeRate){ + case NR_PUCCH_MaxCodeRate_zeroDot08 : + rtimes100 = 8; + break; + case NR_PUCCH_MaxCodeRate_zeroDot15 : + rtimes100 = 15; + break; + case NR_PUCCH_MaxCodeRate_zeroDot25 : + rtimes100 = 25; + break; + case NR_PUCCH_MaxCodeRate_zeroDot35 : + rtimes100 = 35; + break; + case NR_PUCCH_MaxCodeRate_zeroDot45 : + rtimes100 = 45; + break; + case NR_PUCCH_MaxCodeRate_zeroDot60 : + rtimes100 = 60; + break; + case NR_PUCCH_MaxCodeRate_zeroDot80 : + rtimes100 = 80; + break; + default : + AssertFatal(1==0,"Invalid MaxCodeRate"); + } + + float r = (float)rtimes100/100; + + if (O_csi == O_tot) { + if ((O_tot+O_csi)>(nr_prbs*n_re_ctrl*n_symb*Qm*r)) + AssertFatal(1==0,"MaxCodeRate %.2f can't support %d UCI bits and %d CRC bits with %d PRBs", + r,O_tot,O_crc,nr_prbs); + else + return nr_prbs; + } + + if (format==2){ + // TODO fix this for multiple CSI reports + for (int i=1; i<=nr_prbs; i++){ + if((O_tot+O_crc)<=(i*n_symb*Qm*n_re_ctrl*r) && + (O_tot+O_crc)>((i-1)*n_symb*Qm*n_re_ctrl*r)) + return i; + } + AssertFatal(1==0,"MaxCodeRate %.2f can't support %d UCI bits and %d CRC bits with at most %d PRBs", + r,O_tot,O_crc,nr_prbs); + } + else{ + AssertFatal(1==0,"Not yet implemented"); + } + +} diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index b3cd91fd01..7bb08e4f04 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -183,6 +183,9 @@ void nr_schedule_pucch(int Mod_idP, frame_t frameP, sub_frame_t slotP); +void csi_period_offset(NR_CSI_ReportConfig_t *csirep, + int *period, int *offset); + void nr_csi_meas_reporting(int Mod_idP, int UE_id, frame_t frameP, -- 2.26.2