/* * 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 */ /************************************************************************ * * MODULE : PUCCH Packed Uplink Control Channel for UE NR * PUCCH is used to transmit Uplink Control Information UCI * which is composed of: * - SR Scheduling Request * - HARQ ACK/NACK * - CSI Channel State Information * UCI can also be transmitted on a PUSCH if it schedules. * * DESCRIPTION : functions related to PUCCH UCI management * TS 38.213 9 UE procedure for reporting control information * **************************************************************************/ #include "PHY/NR_REFSIG/ss_pbch_nr.h" #include "PHY/defs_nr_UE.h" #ifndef NO_RAT_NR #include "SCHED_NR_UE/harq_nr.h" #include "SCHED_NR_UE/pucch_power_control_ue_nr.h" #define DEFINE_VARIABLES_PUCCH_UE_NR_H #include "SCHED_NR_UE/pucch_uci_ue_nr.h" #undef DEFINE_VARIABLES_PUCCH_UE_NR_H #endif int8_t nr_ue_get_SR(module_id_t module_idP, int CC_id, frame_t frameP, uint8_t eNB_id, uint16_t rnti, sub_frame_t subframe); uint8_t is_cqi_TXOp(PHY_VARS_NR_UE *ue,UE_nr_rxtx_proc_t *proc,uint8_t gNB_id); uint8_t is_ri_TXOp(PHY_VARS_NR_UE *ue,UE_nr_rxtx_proc_t *proc,uint8_t gNB_id); /* void nr_generate_pucch0(int32_t **txdataF, NR_DL_FRAME_PARMS *frame_parms, PUCCH_CONFIG_DEDICATED *pucch_config_dedicated, int16_t amp, int nr_tti_tx, uint8_t mcs, uint8_t nrofSymbols, uint8_t startingSymbolIndex, uint16_t startingPRB); void nr_generate_pucch1(int32_t **txdataF, NR_DL_FRAME_PARMS *frame_parms, PUCCH_CONFIG_DEDICATED *pucch_config_dedicated, uint64_t payload, int16_t amp, int nr_tti_tx, uint8_t nrofSymbols, uint8_t startingSymbolIndex, uint16_t startingPRB, uint16_t startingPRB_intraSlotHopping, uint8_t timeDomainOCC, uint8_t nr_bit); void nr_generate_pucch2(int32_t **txdataF, NR_DL_FRAME_PARMS *frame_parms, PUCCH_CONFIG_DEDICATED *pucch_config_dedicated, uint64_t payload, int16_t amp, int nr_tti_tx, uint8_t nrofSymbols, uint8_t startingSymbolIndex, uint8_t nrofPRB, uint16_t startingPRB, uint8_t nr_bit); void nr_generate_pucch3_4(int32_t **txdataF, NR_DL_FRAME_PARMS *frame_parms, pucch_format_nr_t fmt, PUCCH_CONFIG_DEDICATED *pucch_config_dedicated, uint64_t payload, int16_t amp, int nr_tti_tx, uint8_t nrofSymbols, uint8_t startingSymbolIndex, uint8_t nrofPRB, uint16_t startingPRB, uint8_t nr_bit, uint8_t occ_length_format4, uint8_t occ_index_format4); */ /**************** variables **************************************/ /**************** functions **************************************/ //extern uint8_t is_cqi_TXOp(PHY_VARS_NR_UE *ue,UE_nr_rxtx_proc_t *proc,uint8_t eNB_id); //extern uint8_t is_ri_TXOp(PHY_VARS_NR_UE *ue,UE_nr_rxtx_proc_t *proc,uint8_t eNB_id); /******************************************************************* * * NAME : pucch_procedures_ue_nr * * PARAMETERS : ue context * processing slots of reception/transmission * gNB_id identifier * * RETURN : bool TRUE PUCCH will be transmitted * FALSE No PUCCH to transmit * * DESCRIPTION : determines UCI (uplink Control Information) payload * and PUCCH format and its parameters. * PUCCH is no transmitted if: * - there is no valid data to transmit * - Pucch parameters are not valid * * Below information is scanned in order to know what information should be transmitted to network. * * (SR Scheduling Request) (HARQ ACK/NACK) (CSI Channel State Information) * | | - CQI Channel Quality Indicator * | | - RI Rank Indicator * | | - PMI Primary Matrux Indicator * | | - LI Layer Indicator * | | - L1-RSRP * | | - CSI-RS resource idicator * | V | * +-------------------- -> + <------------------ * | * +--------------------------------+ * | UCI Uplink Control Information | * +--------------------------------+ * V PUCCH Configuration * +----------------------------------------+ +--------------------------+ * | Determine PUCCH payload and its | | PUCCH Resource Set | * +----------------------------------------+ | PUCCH Resource | * V | Format parameters | * +-----------------------------------------+ | | * | Select PUCCH format with its parameters | <----------------+--------------------------+ * +-----------------------------------------+ * V * +-----------------+ * | Generate PUCCH | * +-----------------+ * * TS 38.213 9 UE procedure for reporting control information * *********************************************************************/ bool pucch_procedures_ue_nr(PHY_VARS_NR_UE *ue, uint8_t gNB_id, UE_nr_rxtx_proc_t *proc, bool reset_harq) { uint8_t sr_payload = 0; uint32_t pucch_ack_payload = 0; /* maximum number of bits for pucch payload is supposed to be 32 */ uint64_t pucch_payload = 0; uint32_t csi_payload = 0; int frame_tx = proc->frame_tx; int nr_tti_tx = proc->nr_tti_tx; int Mod_id = ue->Mod_id; int CC_id = ue->CC_id; int O_SR = 0; int O_ACK = 0; int O_CSI = 0; /* channel state information */ int N_UCI = 0; /* size in bits for Uplink Control Information */ int cqi_status = 0; int ri_status = 0; int csi_status = 0; int initial_pucch_id = NB_INITIAL_PUCCH_RESOURCE; int pucch_resource_set = MAX_NB_OF_PUCCH_RESOURCE_SETS; int pucch_resource_id = MAX_NB_OF_PUCCH_RESOURCES; int pucch_resource_indicator = MAX_PUCCH_RESOURCE_INDICATOR; int n_HARQ_ACK; /* update current context */ int subframe_number = (proc->nr_tti_rx)/(ue->frame_parms.ttis_per_subframe); nb_pucch_format_4_in_subframes[subframe_number] = 0; /* reset pucch format 4 counter at current rx position */ int dl_harq_pid = ue->dlsch[ue->current_thread_id[proc->nr_tti_rx]][gNB_id][0]->current_harq_pid; if (dl_harq_pid < ue->dlsch[ue->current_thread_id[proc->nr_tti_rx]][gNB_id][0]->number_harq_processes_for_pdsch) { /* pucch indicator can be reseted in function get_downlink_ack so it should be get now */ pucch_resource_indicator = ue->dlsch[ue->current_thread_id[proc->nr_tti_rx]][gNB_id][0]->harq_processes[dl_harq_pid].harq_ack.pucch_resource_indicator; } /* Part - I * Collect feedback that should be transmitted at this nr_tti_tx : * - ACK/NACK, SR, CSI (CQI, RI, ...) */ sr_payload = 0; if (trigger_periodic_scheduling_request( ue, gNB_id, proc ) == 1) { O_SR = 1; /* sr should be transmitted */ if (ue->mac_enabled == 1) { /* sr_payload = 1 means that this is a positive SR, sr_payload = 0 means that it is a negative SR */ sr_payload = nr_ue_get_SR(Mod_id, CC_id, frame_tx, gNB_id, ue->pdcch_vars[ue->current_thread_id[proc->nr_tti_rx]][gNB_id]->crnti, nr_tti_tx); // nr_tti_rx used for meas gap } else { sr_payload = 1; } } O_ACK = get_downlink_ack( ue, gNB_id, proc, &pucch_ack_payload, &n_HARQ_ACK, reset_harq); // 1 to reset ACK/NACK status : 0 otherwise cqi_status = ((ue->cqi_report_config[gNB_id].CQI_ReportPeriodic.cqi_PMI_ConfigIndex>0) && (is_cqi_TXOp(ue,proc,gNB_id) == 1)); ri_status = ((ue->cqi_report_config[gNB_id].CQI_ReportPeriodic.ri_ConfigIndex>0) && (is_ri_TXOp(ue,proc,gNB_id) == 1)); csi_status = get_csi_nr(ue, gNB_id, &csi_payload); O_CSI = cqi_status + ri_status + csi_status; /* Part - II */ /* if payload is empty or only negative SR -> no pucch transmission */ if(O_ACK == 0) { N_UCI = O_SR + O_CSI; if ((N_UCI == 0) || ((O_CSI == 0) && (sr_payload == 0))) { /* TS 38.213 9.2.4 UE procedure for reporting SR */ NR_TST_PHY_PRINTF("PUCCH No feedback AbsSubframe %d.%d \n", frame_tx%1024, nr_tti_tx); LOG_D(PHY,"PUCCH No feedback AbsSubframe %d.%d \n", frame_tx%1024, nr_tti_tx); return (FALSE); } else { /* a resource set and a resource should be find according to payload size */ pucch_resource_set = find_pucch_resource_set( ue, gNB_id, N_UCI); if (pucch_resource_set != MAX_NB_OF_PUCCH_RESOURCE_SETS) { pucch_resource_indicator = 0; pucch_resource_id = ue->pucch_config_dedicated_nr[gNB_id].PUCCH_ResourceSet[pucch_resource_set]->pucch_resource_id[pucch_resource_indicator]; /* get the first resource of the set */ } else { LOG_W(PHY,"PUCCH no resource set found for CSI at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); O_CSI = 0; csi_payload = 0; } if (O_CSI == 0) { /* only SR has to be send */ /* in this case there is no DCI related to PUCCH parameters so pucch resource should be get from sr configuration */ /* TS 38.213 9.2.4 UE procedure for reporting SR */ pucch_resource_set = 0; /* force it to a valid value */ if (ue->scheduling_request_config_nr[gNB_id].sr_ResourceConfig[ue->scheduling_request_config_nr[gNB_id].active_sr_id] != NULL) { pucch_resource_id = ue->scheduling_request_config_nr[gNB_id].sr_ResourceConfig[ue->scheduling_request_config_nr[gNB_id].active_sr_id]->resource; } else { LOG_E(PHY,"PUCCH No scheduling request configuration : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return(FALSE); } } } } else { N_UCI = O_SR + O_ACK + O_CSI; } /* Part - III */ /* Choice PUCCH format and its related parameters */ pucch_format_nr_t format = pucch_format0_nr; uint8_t starting_symbol_index; uint8_t nb_symbols_total = 0; uint8_t nb_symbols = 0; uint16_t starting_prb = 0;; /* it can be considered as first hop on case of pucch hopping */ uint16_t second_hop = 0; /* second part for pucch for hopping */ uint8_t nb_of_prbs = 0; int m_0 = 0; /* format 0 only */ int m_CS = 0; /* for all format except for format 0 */ int index_additional_dmrs = I_PUCCH_NO_ADDITIONAL_DMRS; int index_hopping = I_PUCCH_NO_HOPPING; int time_domain_occ = 0; int occ_length = 0; int occ_Index = 0; NR_UE_HARQ_STATUS_t *harq_status = &ue->dlsch[ue->current_thread_id[proc->nr_tti_rx]][gNB_id][0]->harq_processes[dl_harq_pid].harq_ack; if (select_pucch_resource(ue, gNB_id, N_UCI, pucch_resource_indicator, &initial_pucch_id, &pucch_resource_set, &pucch_resource_id, harq_status) == TRUE) { /* use of initial pucch configuration provided by system information 1 */ /***********************************************************************/ if (initial_pucch_id != NB_INITIAL_PUCCH_RESOURCE) { format = initial_pucch_resource[initial_pucch_id].format; starting_symbol_index = initial_pucch_resource[initial_pucch_id].startingSymbolIndex; nb_symbols_total = initial_pucch_resource[initial_pucch_id].nrofSymbols; int N_CS = initial_pucch_resource[initial_pucch_id].nb_CS_indexes; /* see TS 38213 Table 9.2.1-1: PUCCH resource sets before dedicated PUCCH resource configuration */ int RB_BWP_offset; if (initial_pucch_id == 15) { RB_BWP_offset = ue->systemInformationBlockType1_nr.N_BWP_SIZE/4; } else { RB_BWP_offset = initial_pucch_resource[initial_pucch_id].PRB_offset; } if (initial_pucch_id/8 == 0) { starting_prb = RB_BWP_offset + (initial_pucch_id/N_CS); second_hop = ue->systemInformationBlockType1_nr.N_BWP_SIZE - 1 - RB_BWP_offset - (initial_pucch_id/N_CS); m_0 = initial_pucch_resource[initial_pucch_id].initial_CS_indexes[initial_pucch_id%N_CS]; } else if (initial_pucch_id/8 == 1) { starting_prb = RB_BWP_offset + (initial_pucch_id/N_CS); second_hop = ue->systemInformationBlockType1_nr.N_BWP_SIZE - 1 - RB_BWP_offset - ((initial_pucch_id - 8)/N_CS); m_0 = initial_pucch_resource[initial_pucch_id].initial_CS_indexes[(initial_pucch_id - 8)%N_CS]; } if ((ue->UE_mode[gNB_id] != PUSCH) && (O_ACK > 1)) { O_ACK = 1; pucch_ack_payload &= 0x1; /* take only first ack */ LOG_W(PHY,"PUCCH ue is not expected to generate more than one HARQ-ACK at AbsSubframe %d.%d \n", frame_tx%1024, nr_tti_tx); } NR_TST_PHY_PRINTF("PUCCH common configuration with index %d \n", initial_pucch_id); } /* use dedicated pucch resource configuration */ /**********************************************/ else if ((pucch_resource_set != MAX_NB_OF_PUCCH_RESOURCE_SETS) && (pucch_resource_id != MAX_NB_OF_PUCCH_RESOURCES)) { /* check that current configuration is supported */ if ((ue->cell_group_config.physicalCellGroupConfig.harq_ACK_SpatialBundlingPUCCH != FALSE) || (ue->cell_group_config.physicalCellGroupConfig.pdsch_HARQ_ACK_Codebook != dynamic)) { LOG_E(PHY,"PUCCH Unsupported cell group configuration : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return(FALSE); } else if (ue->PDSCH_ServingCellConfig.codeBlockGroupTransmission != NULL) { LOG_E(PHY,"PUCCH Unsupported code block group for serving cell config : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return(FALSE); } format = ue->pucch_config_dedicated_nr[gNB_id].PUCCH_Resource[pucch_resource_id]->format_parameters.format; nb_symbols_total = ue->pucch_config_dedicated_nr[gNB_id].PUCCH_Resource[pucch_resource_id]->format_parameters.nrofSymbols; starting_symbol_index = ue->pucch_config_dedicated_nr[gNB_id].PUCCH_Resource[pucch_resource_id]->format_parameters.startingSymbolIndex; starting_prb = ue->pucch_config_dedicated_nr[gNB_id].PUCCH_Resource[pucch_resource_id]->startingPRB; second_hop = starting_prb; time_domain_occ = ue->pucch_config_dedicated_nr[gNB_id].PUCCH_Resource[pucch_resource_id]->format_parameters.timeDomainOCC; /* format 1 only */ occ_length = ue->pucch_config_dedicated_nr[gNB_id].PUCCH_Resource[pucch_resource_id]->format_parameters.occ_length; /* format 4 only */ occ_Index = ue->pucch_config_dedicated_nr[gNB_id].PUCCH_Resource[pucch_resource_id]->format_parameters.occ_Index; /* format 4 only */ if ((format == pucch_format0_nr) || (format == pucch_format1_nr)) { m_0 = ue->pucch_config_dedicated_nr[gNB_id].PUCCH_Resource[pucch_resource_id]->format_parameters.initialCyclicShift; } else if ((format == pucch_format3_nr) || (format == pucch_format4_nr)) { if (ue->pucch_config_dedicated_nr[gNB_id].formatConfig[format-1]->additionalDMRS == enable_feature) { index_additional_dmrs = I_PUCCH_ADDITIONAL_DMRS; } if (ue->pucch_config_dedicated_nr[gNB_id].PUCCH_Resource[pucch_resource_id]->intraSlotFrequencyHopping == feature_enabled) { index_hopping = I_PUCCH_HOPING; } } NR_TST_PHY_PRINTF("PUCCH dedicated configuration with resource index %d \n", pucch_resource_id); } } else { LOG_W(PHY,"PUCCH No PUCCH resource found at AbsSubframe %d.%d \n", frame_tx%1024, nr_tti_tx); return (FALSE); } int max_code_rate = 0; int Q_m = BITS_PER_SYMBOL_QPSK; /* default pucch modulation type is QPSK with 2 bits per symbol */ int N_sc_ctrl_RB = 0; int O_CRC = 0; nb_symbols = nb_symbols_total; /* by default, it can be reduced due to symbols reserved for dmrs */ switch(format) { case pucch_format0_nr: { nb_of_prbs = 1; N_sc_ctrl_RB = N_SC_RB; break; } case pucch_format1_nr: { nb_of_prbs = 1; N_sc_ctrl_RB = N_SC_RB; break; } case pucch_format2_nr: { nb_of_prbs = ue->pucch_config_dedicated_nr[gNB_id].PUCCH_Resource[pucch_resource_id]->format_parameters.nrofPRBs; N_sc_ctrl_RB = N_SC_RB - 4; break; } case pucch_format3_nr: { nb_of_prbs = ue->pucch_config_dedicated_nr[gNB_id].PUCCH_Resource[pucch_resource_id]->format_parameters.nrofPRBs; if (ue->pucch_config_dedicated_nr[gNB_id].formatConfig[format-1]->pi2PBSK == feature_enabled) { Q_m = BITS_PER_SYMBOL_BPSK; /* set bpsk modulation type with 1 bit per modulation symbol */ } N_sc_ctrl_RB = N_SC_RB; nb_symbols = nb_symbols_excluding_dmrs[nb_symbols_total-4][index_additional_dmrs][index_hopping]; break; } case pucch_format4_nr: { if (ue->pucch_config_dedicated_nr[gNB_id].formatConfig[format-1]->pi2PBSK == feature_enabled) { Q_m = BITS_PER_SYMBOL_BPSK; /* set bpsk modulation type with 1 bit per modulation symbol */ } nb_symbols = nb_symbols_excluding_dmrs[nb_symbols_total-4][index_additional_dmrs][index_hopping]; nb_of_prbs = 1; subframe_number = nr_tti_tx/(ue->frame_parms.ttis_per_subframe); nb_pucch_format_4_in_subframes[subframe_number]++; /* increment number of transmit pucch 4 in current subframe */ NR_TST_PHY_PRINTF("PUCCH Number of pucch format 4 in subframe %d is %d \n", subframe_number, nb_pucch_format_4_in_subframes[subframe_number]); N_sc_ctrl_RB = N_SC_RB/(nb_pucch_format_4_in_subframes[subframe_number]); break; } } /* TS 38.213 9.2.5.2 UE procedure for multiplexing HARQ-ACK/SR and CSI */ /* drop CSI report if simultaneous HARQ-ACK/SR and periodic/semi-periodic CSI cannot be transmitted at the same time */ if (format != pucch_format0_nr) { if (ue->pucch_config_dedicated_nr[gNB_id].formatConfig[format-1] != NULL) { max_code_rate = code_rate_r_time_100[ue->pucch_config_dedicated_nr[gNB_id].formatConfig[format-1]->maxCodeRate]; /* it is code rate * 10 */ if ((O_ACK != 0) && (ue->pucch_config_dedicated_nr[gNB_id].formatConfig[format-1]->simultaneousHARQ_ACK_CSI == disable_feature)) { N_UCI = N_UCI - O_CSI; O_CSI = cqi_status = ri_status = 0; csi_payload = 0; /* csi should be dropped in this case */ } } /* TS 38.212 6.3.1.2 Code block segmentation and CRC attachment */ /* crc attachment can be done depending of payload size */ if (N_UCI < 11) { O_CRC = 0; /* no additional crc bits */ } else if ((N_UCI >= 12) && (N_UCI <= 19)) { O_CRC = 6; /* number of additional crc bits */ } else if (N_UCI >= 20) { O_CRC = 11; /* number of additional crc bits */ } N_UCI = N_UCI + O_CRC; /* for format 2 and 3, number of prb should be adjusted to minimum value which cope to information size */ if (nb_of_prbs > 1 ) { int nb_prb_min = 0; int payload_in_bits; do { nb_prb_min++; payload_in_bits = (nb_prb_min * N_sc_ctrl_RB * nb_symbols * Q_m * max_code_rate)/100; /* code rate has been multiplied by 100 */ NR_TST_PHY_PRINTF("PUCCH Adjust number of prb : (N_UCI : %d ) (payload_in_bits : %d) (N_sc_ctrl_RB : %d) (nb_symbols : %d) (Q_m : %d) (max_code_rate*100 : %d) \n", N_UCI, payload_in_bits, N_sc_ctrl_RB, nb_symbols, Q_m, max_code_rate); } while (N_UCI > payload_in_bits); if (nb_prb_min > nb_of_prbs) { LOG_E(PHY,"PUCCH Number of prbs too small for current pucch bits to transmit : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return (FALSE); } else { nb_of_prbs = nb_prb_min; } } /* TS 38.213 9.2.4 for a positive SR transmission, payload b(0) = 0 */ if ((O_SR == 1) && (format == pucch_format1_nr)) { sr_payload = 0; } } else { /* only format 0 here */ if ((O_SR == 0) && (O_CSI == 0)) { /* only ack is transmitted TS 36.213 9.2.3 UE procedure for reporting HARQ-ACK */ if (O_ACK == 1) { m_CS = sequence_cyclic_shift_1_harq_ack_bit[pucch_ack_payload & 0x1]; /* only harq of 1 bit */ } else { m_CS = sequence_cyclic_shift_2_harq_ack_bits[pucch_ack_payload & 0x3]; /* only harq with 2 bits */ } } else if ((O_SR == 1) && (O_CSI == 0)) { /* SR + eventually ack are transmitted TS 36.213 9.2.5.1 UE procedure for multiplexing HARQ-ACK or CSI and SR */ if (sr_payload == 1) { /* positive scheduling request */ if (O_ACK == 1) { m_CS = sequence_cyclic_shift_1_harq_ack_bit_positive_sr[pucch_ack_payload & 0x1]; /* positive SR and harq of 1 bit */ } else if (O_ACK == 2) { m_CS = sequence_cyclic_shift_2_harq_ack_bits_positive_sr[pucch_ack_payload & 0x3]; /* positive SR and harq with 2 bits */ } else { m_CS = 0; /* only positive SR */ } } } N_UCI = O_SR = O_ACK = 0; pucch_payload = sr_payload = pucch_ack_payload = 0; /* no data for format 0 */ } /* TS 38.212 6.3.1 Uplink control information on PUCCH */ /* information concatenation of payload */ /* CSI SR HARQ-ACK */ /* bit order of payload of size n : a(n)....................................a(0) */ /* a(0) is the LSB and a(n) the MSB <--------><--------------><------------><----------> */ /* O_CRC O_CSI O_SR O_ACK */ /* */ /* remark: crc is not part of payload, it is later added by block coding. */ if (N_UCI > (sizeof(uint64_t)*8)) { LOG_E(PHY,"PUCCH number of UCI bits exceeds payload size : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return(0); } pucch_payload = pucch_payload | (csi_payload << (O_ACK + O_SR)) | (sr_payload << O_ACK) | pucch_ack_payload; NR_TST_PHY_PRINTF("PUCCH ( AbsSubframe : %d.%d ) ( total payload size %d data 0x%02x ) ( ack length %d data 0x%02x ) ( sr length %d value %d ) ( csi length %d data : 0x%02x ) \n", frame_tx%1024, nr_tti_tx, N_UCI, pucch_payload, O_ACK, pucch_ack_payload, O_SR, sr_payload, csi_status, csi_payload); NR_TST_PHY_PRINTF("PUCCH ( format : %d ) ( modulation : %s ) ( nb prb : %d ) ( nb symbols total: %d ) ( nb symbols : %d ) ( max code rate*100 : %d ) ( starting_symbol_index : %d ) \n", format, (Q_m == BITS_PER_SYMBOL_QPSK ? " QPSK " : " BPSK "), nb_of_prbs, nb_symbols_total, nb_symbols, max_code_rate, starting_symbol_index); NR_TST_PHY_PRINTF("PUCCH ( starting_prb : %d ) ( second_hop : %d ) ( m_0 : %d ) ( m_CS : %d ) ( time_domain_occ %d ) (occ_length : %d ) ( occ_Index : %d ) \n", starting_prb, second_hop, m_0, m_CS, time_domain_occ, occ_length, occ_Index); /* Part - IV */ /* Generate PUCCH signal according to its format and parameters */ ue->generate_ul_signal[gNB_id] = 1; int16_t pucch_tx_power = get_pucch_tx_power_ue( ue, gNB_id, proc, format, nb_of_prbs, N_sc_ctrl_RB, nb_symbols, N_UCI, O_SR, O_CSI, O_ACK, O_CRC, n_HARQ_ACK); /* set tx power */ ue->tx_power_dBm[nr_tti_tx] = pucch_tx_power; ue->tx_total_RE[nr_tti_tx] = nb_of_prbs*N_SC_RB; int tx_amp; #if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706) tx_amp = get_tx_amp(pucch_tx_power, ue->tx_power_max_dBm, ue->frame_parms.N_RB_UL, nb_of_prbs); #else tx_amp = AMP; #endif switch(format) { case pucch_format0_nr: { nr_generate_pucch0(ue,ue->common_vars.txdataF, &ue->frame_parms, &ue->pucch_config_dedicated_nr[gNB_id], tx_amp, nr_tti_tx, (uint8_t)m_0, (uint8_t)m_CS, nb_symbols_total, starting_symbol_index, starting_prb); break; } case pucch_format1_nr: { nr_generate_pucch1(ue,ue->common_vars.txdataF, &ue->frame_parms, &ue->pucch_config_dedicated_nr[gNB_id], pucch_payload, tx_amp, nr_tti_tx, (uint8_t)m_0, nb_symbols_total, starting_symbol_index, starting_prb, second_hop, (uint8_t)time_domain_occ, (uint8_t)N_UCI); break; } case pucch_format2_nr: { nr_generate_pucch2(ue, ue->pdcch_vars[ue->current_thread_id[proc->nr_tti_rx]][gNB_id]->crnti, ue->common_vars.txdataF, &ue->frame_parms, &ue->pucch_config_dedicated_nr[gNB_id], pucch_payload, tx_amp, nr_tti_tx, nb_symbols_total, starting_symbol_index, nb_of_prbs, starting_prb, (uint8_t)N_UCI); break; } case pucch_format3_nr: case pucch_format4_nr: { nr_generate_pucch3_4(ue, ue->pdcch_vars[ue->current_thread_id[proc->nr_tti_rx]][gNB_id]->crnti, ue->common_vars.txdataF, &ue->frame_parms, format, &ue->pucch_config_dedicated_nr[gNB_id], pucch_payload, tx_amp, nr_tti_tx, nb_symbols_total, starting_symbol_index, nb_of_prbs, starting_prb, second_hop, (uint8_t)N_UCI, (uint8_t)occ_length, (uint8_t)occ_Index); break; } } return (TRUE); } /******************************************************************* * * NAME : get_downlink_ack * * PARAMETERS : ue context * processing slots of reception/transmission * gNB_id identifier * * RETURN : o_ACK acknowledgment data * o_ACK_number_bits number of bits for acknowledgment * * DESCRIPTION : return acknowledgment value * TS 38.213 9.1.3 Type-2 HARQ-ACK codebook determination * * --+--------+-------+--------+-------+--- ---+-------+-- * | PDCCH1 | | PDCCH2 |PDCCH3 | | PUCCH | * --+--------+-------+--------+-------+--- ---+-------+-- * DAI_DL 1 2 3 ACK for * V V V PDCCH1, PDDCH2 and PCCH3 * | | | ^ * +-----------------+-------+---------------+ * * PDCCH1, PDCCH2 and PDCCH3 are PDCCH monitoring occasions * M is the total of monitoring occasions * *********************************************************************/ uint8_t get_downlink_ack(PHY_VARS_NR_UE *ue, uint8_t gNB_id, UE_nr_rxtx_proc_t *proc, uint32_t *o_ACK, int *n_HARQ_ACK, bool do_reset) // 1 to reset ACK/NACK status : 0 otherwise { NR_UE_HARQ_STATUS_t *harq_status; uint32_t ack_data[NR_DL_MAX_NB_CW][NR_DL_MAX_DAI] = {{0},{0}}; uint32_t dai[NR_DL_MAX_NB_CW][NR_DL_MAX_DAI] = {{0},{0}}; /* for serving cell */ uint32_t dai_total[NR_DL_MAX_NB_CW][NR_DL_MAX_DAI] = {{0},{0}}; /* for multiple cells */ int number_harq_feedback = 0; uint32_t dai_current = 0; uint32_t dai_max = 0; int number_pid_dl = ue->dlsch[ue->current_thread_id[proc->nr_tti_rx]][gNB_id][0]->number_harq_processes_for_pdsch; bool two_transport_blocks = FALSE; int number_of_code_word = 1; int U_DAI_c = 0; int N_m_c_rx = 0; int V_DAI_m_DL = 0; if (ue->PDSCH_Config.maxNrofCodeWordsScheduledByDCI == nb_code_n2) { two_transport_blocks = TRUE; number_of_code_word = 2; } else { number_of_code_word = 1; } if (ue->n_connected_eNB > 1) { LOG_E(PHY,"PUCCH ACK feedback is not implemented for mutiple gNB cells : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return (0); } /* look for dl acknowledgment which should be done on current uplink slot */ for (int code_word = 0; code_word < number_of_code_word; code_word++) { for (int dl_harq_pid = 0; dl_harq_pid < number_pid_dl; dl_harq_pid++) { harq_status = &ue->dlsch[ue->current_thread_id[proc->nr_tti_rx]][gNB_id][code_word]->harq_processes[dl_harq_pid].harq_ack; /* check if current tx slot should transmit downlink acknowlegment */ if (harq_status->slot_for_feedback_ack == proc->nr_tti_tx) { if (harq_status->ack == DL_ACKNACK_NO_SET) { LOG_E(PHY,"PUCCH Downlink acknowledgment has not been set : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return (0); } else if (harq_status->vDAI_DL == DL_DAI_NO_SET) { LOG_E(PHY,"PUCCH Downlink DAI has not been set : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return (0); } else if (harq_status->vDAI_DL > NR_DL_MAX_DAI) { LOG_E(PHY,"PUCCH Downlink DAI has an invalid value : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return (0); } else if (harq_status->send_harq_status == 0) { LOG_E(PHY,"PUCCH Downlink ack can not be transmitted : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return(0); } else { dai_current = harq_status->vDAI_DL; if (dai_current == 0) { LOG_E(PHY,"PUCCH Downlink dai is invalid : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return(0); } else if (dai_current > dai_max) { dai_max = dai_current; } number_harq_feedback++; ack_data[code_word][dai_current - 1] = harq_status->ack; dai[code_word][dai_current - 1] = dai_current; } } if (do_reset == TRUE) { init_downlink_harq_status(&ue->dlsch[ue->current_thread_id[proc->nr_tti_rx]][gNB_id][code_word]->harq_processes[dl_harq_pid]); } } } /* no any ack to transmit */ if (number_harq_feedback == 0) { *n_HARQ_ACK = 0; return(0); } else if (number_harq_feedback > (sizeof(uint32_t)*8)) { LOG_E(PHY,"PUCCH number of ack bits exceeds payload size : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return(0); } /* for computing n_HARQ_ACK for power */ V_DAI_m_DL = dai_max; U_DAI_c = number_harq_feedback/number_of_code_word; N_m_c_rx = number_harq_feedback; int N_SPS_c = 0; /* FFS TODO_NR multicells and SPS are not supported at the moment */ if (ue->cell_group_config.physicalCellGroupConfig.harq_ACK_SpatialBundlingPUCCH == FALSE) { int N_TB_max_DL = ue->PDSCH_Config.maxNrofCodeWordsScheduledByDCI; *n_HARQ_ACK = (((V_DAI_m_DL - U_DAI_c)%4) * N_TB_max_DL) + N_m_c_rx + N_SPS_c; NR_TST_PHY_PRINTF("PUCCH power n(%d) = ( V(%d) - U(%d) )mod4 * N_TB(%d) + N(%d) \n", *n_HARQ_ACK, V_DAI_m_DL, U_DAI_c, N_TB_max_DL, N_m_c_rx); } /* * For a monitoring occasion of a PDCCH with DCI format 1_0 or DCI format 1_1 in at least one serving cell, * when a UE receives a PDSCH with one transport block and the value of higher layer parameter maxNrofCodeWordsScheduledByDCI is 2, * the HARQ-ACK response is associated with the first transport block and the UE generates a NACK for the second transport block * if spatial bundling is not applied (HARQ-ACK-spatial-bundling-PUCCH = FALSE) and generates HARQ-ACK value of ACK for the second * transport block if spatial bundling is applied. */ for (int code_word = 0; code_word < number_of_code_word; code_word++) { for (uint32_t i = 0; i < dai_max ; i++ ) { if (dai[code_word][i] != i + 1) { /* fill table with consistent value for each dai */ dai[code_word][i] = i + 1; /* it covers case for which PDCCH DCI has not been successfully decoded and so it has been missed */ ack_data[code_word][i] = 0; /* nack data transport block which has been missed */ number_harq_feedback++; } if (two_transport_blocks == TRUE) { dai_total[code_word][i] = dai[code_word][i]; /* for a single cell, dai_total is the same as dai of first cell */ } } } int M = dai_max; int j = 0; uint32_t V_temp = 0; uint32_t V_temp2 = 0; int O_ACK = 0; int O_bit_number_cw0 = 0; int O_bit_number_cw1 = 0; for (int m = 0; m < M ; m++) { if (dai[0][m] <= V_temp) { j = j + 1; } V_temp = dai[0][m]; /* value of the counter DAI for format 1_0 and format 1_1 on serving cell c */ if (dai_total[0][m] == 0) { V_temp2 = dai[0][m]; } else { V_temp2 = dai[1][m]; /* second code word has been received */ O_bit_number_cw1 = (8 * j) + 2*(V_temp - 1) + 1; *o_ACK = *o_ACK | (ack_data[1][m] << O_bit_number_cw1); } if (two_transport_blocks == TRUE) { O_bit_number_cw0 = (8 * j) + 2*(V_temp - 1); } else { O_bit_number_cw0 = (4 * j) + (V_temp - 1); } *o_ACK = *o_ACK | (ack_data[0][m] << O_bit_number_cw0); } if (V_temp2 < V_temp) { j = j + 1; } if (two_transport_blocks == TRUE) { O_ACK = 2 * ( 4 * j + V_temp2); /* for two transport blocks */ } else { O_ACK = 4 * j + V_temp2; /* only one transport block */ } if (number_harq_feedback != O_ACK) { LOG_E(PHY,"PUCCH Error for number of bits for acknowledgment : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return (0); } return(number_harq_feedback); } /******************************************************************* * * NAME : select_pucch_format * * PARAMETERS : ue context * processing slots of reception/transmission * gNB_id identifier * * RETURN : TRUE a valid resource has been found * * DESCRIPTION : return tx harq process identifier for given transmission slot * TS 38.213 9.2.1 PUCCH Resource Sets * TS 38.213 9.2.2 PUCCH Formats for UCI transmission * In the case of pucch for scheduling request only, resource is already get from scheduling request configuration * *********************************************************************/ boolean_t select_pucch_resource(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int uci_size, int pucch_resource_indicator, int *initial_pucch_id, int *resource_set_id, int *resource_id, NR_UE_HARQ_STATUS_t *harq_status) { boolean_t resource_set_found = FALSE; int nb_symbols_for_tx = 0; int current_resource_id = MAX_NB_OF_PUCCH_RESOURCES; pucch_format_nr_t format_pucch; int ready_pucch_resource_id = FALSE; /* in the case that it is already given */ /* ini values to unset */ *initial_pucch_id = NB_INITIAL_PUCCH_RESOURCE; //*resource_set_id = MAX_NB_OF_PUCCH_RESOURCE_SETS; //*resource_id = MAX_NB_OF_PUCCH_RESOURCES; if (ue->pucch_config_dedicated_nr[gNB_id].PUCCH_ResourceSet[0] == NULL) { /* No resource set has been already configured so pucch_configCommon from Sib1 should be used in this case */ if (ue->UE_mode[gNB_id] != PUSCH) { *initial_pucch_id = ue->pucch_config_common_nr[gNB_id].pucch_ResourceCommon; if (*initial_pucch_id >= NB_INITIAL_PUCCH_RESOURCE) { LOG_E(PHY,"PUCCH Invalid initial resource index : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); *initial_pucch_id = NB_INITIAL_PUCCH_RESOURCE; return (FALSE); } } else { /* see TS 38.213 9.2.1 PUCCH Resource Sets */ int delta_PRI = harq_status->pucch_resource_indicator; // n_CCE can be obtained from ue->dci_ind.dci_list[i].n_CCE. FIXME!!! // N_CCE can be obtained from ue->dci_ind.dci_list[i].N_CCE. FIXME!!! //int n_CCE = ue->dci_ind.dci_list[0].n_CCE; //int N_CCE = ue->dci_ind.dci_list[0].N_CCE; int n_CCE_0 = harq_status->n_CCE; int N_CCE_0 = harq_status->N_CCE; if (N_CCE_0 == 0) { LOG_E(PHY,"PUCCH No compatible pucch format found : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return (FALSE); } int r_PUCCH = ((2 * n_CCE_0)/N_CCE_0) + (2 * delta_PRI); *initial_pucch_id = r_PUCCH; } nb_symbols_for_tx = initial_pucch_resource[*initial_pucch_id].nrofSymbols; format_pucch = initial_pucch_resource[*initial_pucch_id].format; if (check_pucch_format(ue, gNB_id, format_pucch, nb_symbols_for_tx, uci_size) == TRUE) { return (TRUE); } else { LOG_E(PHY,"PUCCH No compatible pucch format found : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return (FALSE); } } else { /* dedicated resources have been configured */ int pucch_resource_set_id = 0; if (*resource_set_id == MAX_NB_OF_PUCCH_RESOURCE_SETS) { /* from TS 38.331 field maxPayloadMinus1 -- Maximum number of payload bits minus 1 that the UE may transmit using this PUCCH resource set. In a PUCCH occurrence, the UE -- chooses the first of its PUCCH-ResourceSet which supports the number of bits that the UE wants to transmit. -- The field is not present in the first set (Set0) since the maximum Size of Set0 is specified to be 3 bit. -- The field is not present in the last configured set since the UE derives its maximum payload size as specified in 38.213. -- This field can take integer values that are multiples of 4. Corresponds to L1 parameter 'N_2' or 'N_3' (see 38.213, section 9.2) */ /* look for the first resource set which supports uci_size number of bits for payload */ pucch_resource_set_id = find_pucch_resource_set( ue, gNB_id, uci_size); if (pucch_resource_set_id != MAX_NB_OF_PUCCH_RESOURCE_SETS) { resource_set_found = TRUE; } } else { /* a valid resource has already be found outside this function */ resource_set_found = TRUE; ready_pucch_resource_id = TRUE; pucch_resource_indicator = pucch_resource_indicator; } if (resource_set_found == TRUE) { if (pucch_resource_indicator < MAX_PUCCH_RESOURCE_INDICATOR) { /* check if resource indexing by pucch_resource_indicator of this set is compatible */ if ((ready_pucch_resource_id == TRUE) || (ue->pucch_config_dedicated_nr[gNB_id].PUCCH_ResourceSet[pucch_resource_set_id]->pucch_resource_id[pucch_resource_indicator] != MAX_NB_OF_PUCCH_RESOURCES)) { if (ready_pucch_resource_id == TRUE) { current_resource_id = *resource_id; } else { int R_PUCCH = ue->pucch_config_dedicated_nr[gNB_id].PUCCH_ResourceSet[pucch_resource_set_id]->first_resources_set_R_PUCCH; /* is it the first resource and its size exceeds 8 */ if ((pucch_resource_set_id == 0) && (R_PUCCH > MAX_NB_OF_PUCCH_RESOURCES_PER_SET_NOT_0)) { /* see TS 38.213 9.2.3 UE procedure for reporting HARQ-ACK */ int delta_PRI = pucch_resource_indicator; int n_CCE_p = harq_status->n_CCE; int N_CCE_p = harq_status->N_CCE; int r_PUCCH; if (N_CCE_p == 0) { LOG_E(PHY,"PUCCH No compatible pucch format found : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return (FALSE); } if (pucch_resource_set_id < (R_PUCCH%8)) { r_PUCCH = ((n_CCE_p * (R_PUCCH/8))/N_CCE_p) + (delta_PRI*(R_PUCCH/8)); } else { r_PUCCH = ((n_CCE_p * (R_PUCCH/8))/N_CCE_p) + (delta_PRI*(R_PUCCH/8)) + (R_PUCCH%8); } current_resource_id = r_PUCCH; } else { current_resource_id = ue->pucch_config_dedicated_nr[gNB_id].PUCCH_ResourceSet[pucch_resource_set_id]->pucch_resource_id[pucch_resource_indicator]; } } if (ue->pucch_config_dedicated_nr[gNB_id].PUCCH_Resource[current_resource_id] != NULL) { nb_symbols_for_tx = ue->pucch_config_dedicated_nr[gNB_id].PUCCH_Resource[current_resource_id]->format_parameters.nrofSymbols; format_pucch = ue->pucch_config_dedicated_nr[gNB_id].PUCCH_Resource[current_resource_id]->format_parameters.format; if (check_pucch_format(ue, gNB_id, format_pucch, nb_symbols_for_tx, uci_size) == TRUE) { *resource_set_id = pucch_resource_set_id; *resource_id = current_resource_id; return (TRUE); } else { LOG_E(PHY,"PUCCH Found format no compatible with payload size and symbol length : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return (FALSE); } } } else { LOG_E(PHY,"PUCCH Undefined Resource related to pucch resource indicator: at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return (FALSE); } } else { LOG_E(PHY,"PUCCH Invalid pucch resource indicator: at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return (FALSE); } } /* check that a resource has been found */ if (*resource_set_id == MAX_NB_OF_PUCCH_RESOURCES) { LOG_E(PHY,"PUCCH No compatible pucch format found : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return (FALSE); } } return (FALSE); } /******************************************************************* * * NAME : find_pucch_resource_set * * PARAMETERS : ue context * gNB_id identifier * * * RETURN : harq process identifier * * DESCRIPTION : return tx harq process identifier for given transmission slot * YS 38.213 9.2.2 PUCCH Formats for UCI transmission * *********************************************************************/ int find_pucch_resource_set(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int uci_size) { int pucch_resource_set_id = 0; /* from TS 38.331 field maxPayloadMinus1 -- Maximum number of payload bits minus 1 that the UE may transmit using this PUCCH resource set. In a PUCCH occurrence, the UE -- chooses the first of its PUCCH-ResourceSet which supports the number of bits that the UE wants to transmit. -- The field is not present in the first set (Set0) since the maximum Size of Set0 is specified to be 3 bit. -- The field is not present in the last configured set since the UE derives its maximum payload size as specified in 38.213. -- This field can take integer values that are multiples of 4. Corresponds to L1 parameter 'N_2' or 'N_3' (see 38.213, section 9.2) */ /* look for the first resource set which supports uci_size number of bits for payload */ while (pucch_resource_set_id < MAX_NB_OF_PUCCH_RESOURCE_SETS) { if (ue->pucch_config_dedicated_nr[gNB_id].PUCCH_ResourceSet[pucch_resource_set_id] != NULL) { if (uci_size <= ue->pucch_config_dedicated_nr[gNB_id].PUCCH_ResourceSet[pucch_resource_set_id]->maxPayloadMinus1 + 1) { NR_TST_PHY_PRINTF("PUCCH found resource set %d \n", pucch_resource_set_id); return (pucch_resource_set_id); break; } } pucch_resource_set_id++; } pucch_resource_set_id = MAX_NB_OF_PUCCH_RESOURCE_SETS; return (pucch_resource_set_id); } /******************************************************************* * * NAME : check_pucch_format * * PARAMETERS : ue context * processing slots of reception/transmission * gNB_id identifier * * RETURN : harq process identifier * * DESCRIPTION : return tx harq process identifier for given transmission slot * YS 38.213 9.2.2 PUCCH Formats for UCI transmission * *********************************************************************/ boolean_t check_pucch_format(PHY_VARS_NR_UE *ue, uint8_t gNB_id, pucch_format_nr_t format_pucch, int nb_symbols_for_tx, int uci_size) { pucch_format_nr_t selected_pucch_format; pucch_format_nr_t selected_pucch_format_second; if (format_pucch != pucch_format0_nr) { if (ue->pucch_config_dedicated_nr[gNB_id].formatConfig[format_pucch-1] != NULL) { if (ue->pucch_config_dedicated_nr[gNB_id].formatConfig[format_pucch-1]->nrofSlots != 1) { LOG_E(PHY,"PUCCH not implemented multislots transmission : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return (FALSE); } } } if (nb_symbols_for_tx <= 2) { if (uci_size <= 2) { selected_pucch_format = pucch_format0_nr; selected_pucch_format_second = selected_pucch_format; } else { selected_pucch_format = pucch_format2_nr; selected_pucch_format_second = selected_pucch_format; } } else { if (nb_symbols_for_tx >= 4) { if (uci_size <= 2) { selected_pucch_format = pucch_format1_nr; selected_pucch_format_second = selected_pucch_format; } else { selected_pucch_format = pucch_format3_nr; /* in this case choice can be done between two formats */ selected_pucch_format_second = pucch_format4_nr; } } else { LOG_D(PHY,"PUCCH Undefined PUCCH format : set PUCCH to format 4 : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return (FALSE); } } NR_TST_PHY_PRINTF("PUCCH format %d nb symbols total %d uci size %d selected format %d \n", format_pucch, nb_symbols_for_tx, uci_size, selected_pucch_format); if (format_pucch != selected_pucch_format) { if (format_pucch != selected_pucch_format_second) { NR_TST_PHY_PRINTF("PUCCH mismatched of selected format: at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); LOG_D(PHY,"PUCCH format mismatched of selected format: at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return (FALSE); } else { return (TRUE); } } else { return (TRUE); } } /******************************************************************* * * NAME : trigger_periodic_scheduling_request * * PARAMETERS : pointer to resource set * * RETURN : 1 if peridic scheduling request is triggered * 0 no periodic scheduling request * * DESCRIPTION : TS 38.213 9.2.4 UE procedure for reporting SR * *********************************************************************/ int trigger_periodic_scheduling_request(PHY_VARS_NR_UE *ue, uint8_t gNB_id, UE_nr_rxtx_proc_t *proc) { const int max_sr_periodicity[NB_NUMEROLOGIES_NR] = { 80, 160, 320, 640, 640 }; int active_scheduling_request = ue->scheduling_request_config_nr[gNB_id].active_sr_id; /* is there any valid scheduling request configuration */ if (ue->scheduling_request_config_nr[gNB_id].sr_ResourceConfig[active_scheduling_request] == NULL) { return (0); } if (ue->scheduling_request_config_nr[gNB_id].sr_ResourceConfig[active_scheduling_request]->periodicity < 2) { LOG_W(PHY,"PUCCH Not supported scheduling request period smaller than 1 slot : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return (0); } int16_t SR_periodicity = scheduling_request_periodicity[ue->scheduling_request_config_nr[gNB_id].sr_ResourceConfig[active_scheduling_request]->periodicity]; uint16_t SR_offset = ue->scheduling_request_config_nr[gNB_id].sr_ResourceConfig[active_scheduling_request]->offset; if (SR_periodicity > max_sr_periodicity[ue->frame_parms.numerology_index]) { LOG_W(PHY,"PUCCH Invalid scheduling request period : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); return (0); } if (SR_offset > SR_periodicity) { LOG_E(PHY,"PUCCH SR offset %d is greater than SR periodicity %d : at line %d in function %s of file %s \n", SR_offset, SR_periodicity, LINE_FILE , __func__, FILE_NAME); return (0); } else if (SR_periodicity == 1) { return (1); /* period is slot */ } int16_t N_slot_frame = NR_NUMBER_OF_SUBFRAMES_PER_FRAME * ue->frame_parms.ttis_per_subframe; if (((proc->frame_tx * N_slot_frame) + proc->nr_tti_tx - SR_offset)%SR_periodicity == 0) { return (1); } else { return (0); } } /******************************************************************* * * NAME : get_csi_nr * PARAMETERS : ue context * processing slots of reception/transmission * gNB_id identifier * * RETURN : size of csi payload * * DESCRIPTION : CSI management is not already implemented * so it has been simulated thank to two functions: * - set_csi_nr * - get_csi_nr * *********************************************************************/ int dummy_csi_status = 0; uint32_t dummy_csi_payload = 0; /* FFS TODO_NR code that should be developed */ int get_csi_nr(PHY_VARS_NR_UE *ue, uint8_t gNB_id, uint32_t *csi_payload) { VOID_PARAMETER ue; VOID_PARAMETER gNB_id; if (dummy_csi_status == 0) { *csi_payload = 0; } else { *csi_payload = dummy_csi_payload; } return (dummy_csi_status); } /* FFS TODO_NR code that should be removed */ void set_csi_nr(int csi_status, uint32_t csi_payload) { dummy_csi_status = csi_status; if (dummy_csi_status == 0) { dummy_csi_payload = 0; } else { dummy_csi_payload = csi_payload; } }