diff --git a/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf b/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf index 259a2466ad862387335d729315b5c5580011002e..258618e7f0644e9e8a983350b9d9b93099b8b8aa 100644 --- a/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf +++ b/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf @@ -1,7 +1,6 @@ Active_gNBs = ( "gNB-Eurecom-5GNRBox"); # Asn1_verbosity, choice in: none, info, annoying Asn1_verbosity = "none"; -Num_Threads_PUSCH = 8 gNBs = @@ -251,6 +250,7 @@ L1s = ( { num_cc = 1; tr_n_preference = "local_mac"; + pusch_proc_threads = 8; } ); diff --git a/ci-scripts/xml_files/gnb_nr_ue_usrp_run.xml b/ci-scripts/xml_files/gnb_nr_ue_usrp_run.xml index ed134f478c56bbe460b8e3fe8829954427fc3fd1..b1e9697be2f0e9cba104a7d15ceef8041ec4df8c 100644 --- a/ci-scripts/xml_files/gnb_nr_ue_usrp_run.xml +++ b/ci-scripts/xml_files/gnb_nr_ue_usrp_run.xml @@ -52,7 +52,7 @@ <testCase id="090102"> <class>Initialize_OAI_UE</class> <desc>Initialize NR UE USRP</desc> - <Initialize_OAI_UE_args>--phy-test --usrp-args "addr=192.168.30.2,second_addr=192.168.50.2,clock_source=external,time_source=external" --ue-rxgain 75 --rrc_config_path . --dlsch-parallel 4 </Initialize_OAI_UE_args> + <Initialize_OAI_UE_args>--phy-test --usrp-args "addr=192.168.30.2,second_addr=192.168.50.2,clock_source=external,time_source=external" --ue-rxgain 50 --rrc_config_path . --dlsch-parallel 4 </Initialize_OAI_UE_args> <air_interface>NR</air_interface> </testCase> diff --git a/doc/SW_archi.md b/doc/SW_archi.md index 412dad402d90816ad53c5f48428824f6407052dd..d92f8021488fb30b6a2b3fb7d209fc733b92347d 100644 --- a/doc/SW_archi.md +++ b/doc/SW_archi.md @@ -186,7 +186,7 @@ development], for FR2 does not exist yet. 3) allocate a CCE for the UE (and return if it is not possible) 4) Calculate DMRS stuff (nr_save_pusch_fields()) and the TBS. 5) Mark used resources in vrb_map_UL. -* loop through all users: get a free HARQ PID using select_ul_harq_pid() and +* loop through all users: get a free HARQ PID and update statistics. Fill nFAPI structures directly for PUSCH, and call config_uldci() and fill_dci_pdu_rel15() for DCI filling and PDCCH messages. diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 7966c5b6ce358f5ce06cd07216f1cebf48d06c08..e4b644e1a3677747a5b6b1c96e48897c6bedb19b 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -873,10 +873,7 @@ void init_gNB_proc(int inst) { gNB->threadPool = (tpool_t*)malloc(sizeof(tpool_t)); gNB->respDecode = (notifiedFIFO_t*) malloc(sizeof(notifiedFIFO_t)); int numCPU = sysconf(_SC_NPROCESSORS_ONLN); - uint32_t num_threads_pusch; - paramdef_t PUSCHThreads[] = NUM_THREADS_DESC; - config_get( PUSCHThreads,sizeof(PUSCHThreads)/sizeof(paramdef_t),NULL); - int threadCnt = min(numCPU, num_threads_pusch); + int threadCnt = min(numCPU, gNB->pusch_proc_threads); char ul_pool[80]; sprintf(ul_pool,"-1"); int s_offset = 0; diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 6833f2fed3fc000eb06f9025bf36adce553b7e5e..6be23582b18983c76ef2bc954bb8dd6eb01e1000 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -642,8 +642,7 @@ void *UE_thread(void *arg) { UE->rx_offset_diff = computeSamplesShift(UE); readBlockSize=get_readBlockSize(slot_nr, &UE->frame_parms) - UE->rx_offset_diff; - writeBlockSize=UE->frame_parms.get_samples_per_slot((slot_nr + DURATION_RX_TO_TX - RX_NB_TH) % nb_slot_frame, &UE->frame_parms)- - UE->rx_offset_diff; + writeBlockSize=UE->frame_parms.get_samples_per_slot((slot_nr + DURATION_RX_TO_TX - RX_NB_TH) % nb_slot_frame, &UE->frame_parms)- UE->rx_offset_diff; } AssertFatal(readBlockSize == @@ -702,14 +701,28 @@ void *UE_thread(void *arg) { timing_advance = UE->timing_advance; } - AssertFatal( writeBlockSize == + int flags = 0; + int slot_tx_usrp = slot_nr + DURATION_RX_TO_TX - RX_NB_TH; + uint8_t tdd_period = mac->phy_config.config_req.tdd_table.tdd_period_in_slots; + uint8_t num_UL_slots = mac->scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots + + (mac->scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols!=0); + uint8_t first_tx_slot = tdd_period - num_UL_slots; + if (slot_tx_usrp%tdd_period==first_tx_slot) + flags=2; + else if (slot_tx_usrp%tdd_period==first_tx_slot+num_UL_slots-1) + flags = 3; + else if (slot_tx_usrp%tdd_period>first_tx_slot) + flags = 1; + + if (flags || IS_SOFTMODEM_RFSIM) + AssertFatal( writeBlockSize == UE->rfdevice.trx_write_func(&UE->rfdevice, - writeTimestamp, - txp, - writeBlockSize, - UE->frame_parms.nb_antennas_tx, - 1),""); - + writeTimestamp, + txp, + writeBlockSize, + UE->frame_parms.nb_antennas_tx, + flags),""); + for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++) memset(txp[i], 0, writeBlockSize); @@ -717,7 +730,7 @@ void *UE_thread(void *arg) { msgToPush->key=slot_nr; pushTpool(&(get_nrUE_params()->Tpool), msgToPush); - if ( IS_SOFTMODEM_RFSIM || IS_SOFTMODEM_NOS1) { //getenv("RFSIMULATOR") + if (IS_SOFTMODEM_RFSIM) { //getenv("RFSIMULATOR") // FixMe: Wait previous thread is done, because race conditions seems too bad // in case of actual RF board, the overlap between threads mitigate the issue // We must receive one message, that proves the slot processing is done diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index da8490160211f17ef2a94f976628c13e9ee7fcc2..9df9be4cbd4b656be44f4fb282a06cb8dff5148e 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -1019,6 +1019,7 @@ typedef struct typedef struct { uint8_t tdd_period;//DL UL Transmission Periodicity. Value:0: ms0p5 1: ms0p625 2: ms1 3: ms1p25 4: ms2 5: ms2p5 6: ms5 7: ms10 8: ms3 9: ms4 + uint8_t tdd_period_in_slots; fapi_nr_max_tdd_periodicity_t* max_tdd_periodicity_list; } fapi_nr_tdd_table_t; diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h index c254e1a0282c0971038a83aeabc7c60f1f41a213..12748b7a9efc86f02dac31cae851e078bb99f91a 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h @@ -630,30 +630,30 @@ typedef struct { typedef struct { // The RNTI used for identifying the UE when receiving the PDU Value: 1 -> 65535. - uint16_t RNTI[MAX_DCI_CORESET]; + uint16_t RNTI; // For a UE-specific search space it equals the higher-layer parameter PDCCH-DMRSScrambling-ID if configured, // otherwise it should be set to the phy cell ID. [TS38.211, sec 7.3.2.3] Value: 0->65535 - uint16_t ScramblingId[MAX_DCI_CORESET]; + uint16_t ScramblingId; // For a UE-specific search space where PDCCH-DMRSScrambling- ID is configured This param equals the CRNTI. // Otherwise, it should be set to 0. [TS38.211, sec 7.3.2.3] Value: 0 -> 65535 - uint16_t ScramblingRNTI[MAX_DCI_CORESET]; + uint16_t ScramblingRNTI; // CCE start Index used to send the DCI Value: 0->135 - uint8_t CceIndex[MAX_DCI_CORESET]; + uint8_t CceIndex; // Aggregation level used [TS38.211, sec 7.3.2.1] Value: 1,2,4,8,16 - uint8_t AggregationLevel[MAX_DCI_CORESET]; + uint8_t AggregationLevel; // Precoding and Beamforming structure See Table 3-43 - nfapi_nr_tx_precoding_and_beamforming_t precodingAndBeamforming[MAX_DCI_CORESET]; + nfapi_nr_tx_precoding_and_beamforming_t precodingAndBeamforming; // PDCCH power value used for PDCCH Format 1_0 with CRC scrambled by SI-RNTI, PI-RNTI or RA-RNTI. // This is ratio of SSB/PBCH EPRE to PDCCH and PDCCH DMRS EPRE [TS38.213, sec 4.1] // Value :0->17 Report title: 5G FAPI: PHY API Specification Issue date: 29 June 2019 Version: 222.10.17 68 Field Type Description representing -8 to 8 dB in 1dB steps - uint8_t beta_PDCCH_1_0[MAX_DCI_CORESET]; + uint8_t beta_PDCCH_1_0; // PDCCH power value used for all other PDCCH Formats. // This is ratio of SSB/PBCH block EPRE to PDCCH and PDCCH DMRS EPRE [TS38.214, sec 4.1] Values: 0: -3dB,1: 0dB,2: 3dB,3: 6dB - uint8_t powerControlOffsetSS[MAX_DCI_CORESET]; + uint8_t powerControlOffsetSS; // The total DCI length (in bits) including padding bits [TS38.212 sec 7.3.1] Range 0->DCI_PAYLOAD_BYTE_LEN*8 - uint16_t PayloadSizeBits[MAX_DCI_CORESET]; + uint16_t PayloadSizeBits; // DCI payload, where the actual size is defined by PayloadSizeBits. The bit order is as following bit0-bit7 are mapped to first byte of MSB - LSB - uint8_t Payload[MAX_DCI_CORESET][DCI_PAYLOAD_BYTE_LEN]; + uint8_t Payload[DCI_PAYLOAD_BYTE_LEN]; } nfapi_nr_dl_dci_pdu_t; @@ -698,7 +698,7 @@ typedef struct { ///Number of DCIs in this CORESET.Value: 0->MaxDciPerSlot uint16_t numDlDci; ///DL DCI PDU - nfapi_nr_dl_dci_pdu_t dci_pdu; + nfapi_nr_dl_dci_pdu_t dci_pdu[MAX_DCI_CORESET]; } nfapi_nr_dl_tti_pdcch_pdu_rel15_t; typedef struct { diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 5621e2a7962ca95f32ff08c3981e06eec81ceadc..bd6b944fef0be35645e323502ca0f0984d5e8a6a 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -250,9 +250,7 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, int N_RB_UL = cfg->carrier_config.ul_grid_size[cfg->ssb_config.scs_common.value].value; - printf("Before ULSCH init : %p\n",gNB->dlsch[0][0]->harq_processes[0]); for (int ULSCH_id=0; ULSCH_id<NUMBER_OF_NR_ULSCH_MAX; ULSCH_id++) { - printf("ULSCH_id %d : %p\n",ULSCH_id,gNB->dlsch[0][0]->harq_processes[0]); pusch_vars[ULSCH_id] = (NR_gNB_PUSCH *)malloc16_clear( sizeof(NR_gNB_PUSCH) ); pusch_vars[ULSCH_id]->rxdataF_ext = (int32_t **)malloc16(Prx*sizeof(int32_t *) ); pusch_vars[ULSCH_id]->rxdataF_ext2 = (int32_t **)malloc16(Prx*sizeof(int32_t *) ); @@ -269,7 +267,6 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, pusch_vars[ULSCH_id]->ul_ch_magb = (int32_t **)malloc16(Prx*sizeof(int32_t *) ); pusch_vars[ULSCH_id]->rho = (int32_t **)malloc16_clear(Prx*sizeof(int32_t*) ); - printf("ULSCH_id %d (before rx antenna alloc) : %p\n",ULSCH_id,gNB->dlsch[0][0]->harq_processes[0]); for (i=0; i<Prx; i++) { pusch_vars[ULSCH_id]->rxdataF_ext[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*N_RB_UL*12*fp->symbols_per_slot ); pusch_vars[ULSCH_id]->rxdataF_ext2[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*N_RB_UL*12*fp->symbols_per_slot ); @@ -286,16 +283,13 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, pusch_vars[ULSCH_id]->ul_ch_magb[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); pusch_vars[ULSCH_id]->rho[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*(fp->N_RB_UL*12*7*2) ); } - printf("ULSCH_id %d (before llr alloc) : %p\n",ULSCH_id,gNB->dlsch[0][0]->harq_processes[0]); pusch_vars[ULSCH_id]->llr = (int16_t *)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) ); // [hna] 6144 is LTE and (8*((3*8*6144)+12)) is not clear - printf("ULSCH_id %d (after llr alloc) : %p\n",ULSCH_id,gNB->dlsch[0][0]->harq_processes[0]); pusch_vars[ULSCH_id]->ul_valid_re_per_slot = (int16_t *)malloc16_clear( sizeof(int16_t)*fp->symbols_per_slot); } //ulsch_id /* for (ulsch_id=0; ulsch_id<NUMBER_OF_UE_MAX; ulsch_id++) gNB->UE_stats_ptr[ulsch_id] = &gNB->UE_stats[ulsch_id]; */ - printf("After ULSCH init : %p\n",gNB->dlsch[0][0]->harq_processes[0]); return (0); } diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.c b/openair1/PHY/NR_TRANSPORT/nr_dci.c index 4db2648ebf30b58f5d2bdc022f72307f0bd98012..469415908f6d4b58b2eecf04d6c160a9953199ff 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dci.c @@ -95,6 +95,7 @@ void nr_generate_dci(PHY_VARS_gNB *gNB, * in frequency: the first subcarrier is obtained by adding the first CRB overlapping the SSB and the rb_offset for coreset 0 * or the rb_offset for other coresets * in time: by its first slot and its first symbol*/ + const nfapi_nr_dl_dci_pdu_t *dci_pdu = &pdcch_pdu_rel15->dci_pdu[d]; cset_start_symb = pdcch_pdu_rel15->StartSymbolIndex; cset_nsymb = pdcch_pdu_rel15->DurationSymbols; @@ -103,7 +104,7 @@ void nr_generate_dci(PHY_VARS_gNB *gNB, LOG_D(PHY, "Coreset starting subcarrier %d on symbol %d (%d symbols)\n", cset_start_sc, cset_start_symb, cset_nsymb); // DMRS length is per OFDM symbol uint32_t dmrs_length = n_rb*6; //2(QPSK)*3(per RB)*6(REG per CCE) - uint32_t encoded_length = pdcch_pdu_rel15->dci_pdu.AggregationLevel[d]*108; //2(QPSK)*9(per RB)*6(REG per CCE) + uint32_t encoded_length = dci_pdu->AggregationLevel*108; //2(QPSK)*9(per RB)*6(REG per CCE) LOG_D(PHY, "DMRS length per symbol %d\t DCI encoded length %d (precoder_granularity %d,reg_mapping %d)\n", dmrs_length, encoded_length,pdcch_pdu_rel15->precoderGranularity,pdcch_pdu_rel15->CceRegMappingType); dmrs_length += rb_offset*6; // To accommodate more DMRS symbols in case of rb offset @@ -125,19 +126,19 @@ void nr_generate_dci(PHY_VARS_gNB *gNB, // CRC attachment + Scrambling + Channel coding + Rate matching uint32_t encoder_output[NR_MAX_DCI_SIZE_DWORD]; - uint16_t n_RNTI = pdcch_pdu_rel15->dci_pdu.RNTI[d]; - uint16_t Nid = pdcch_pdu_rel15->dci_pdu.ScramblingId[d]; - uint16_t scrambling_RNTI = pdcch_pdu_rel15->dci_pdu.ScramblingRNTI[d]; + uint16_t n_RNTI = dci_pdu->RNTI; + uint16_t Nid = dci_pdu->ScramblingId; + uint16_t scrambling_RNTI = dci_pdu->ScramblingRNTI; t_nrPolar_params *currentPtr = nr_polar_params(NR_POLAR_DCI_MESSAGE_TYPE, - pdcch_pdu_rel15->dci_pdu.PayloadSizeBits[d], - pdcch_pdu_rel15->dci_pdu.AggregationLevel[d], + dci_pdu->PayloadSizeBits, + dci_pdu->AggregationLevel, 0,NULL); - polar_encoder_fast((uint64_t*)pdcch_pdu_rel15->dci_pdu.Payload[d], (void*)encoder_output, n_RNTI,1,currentPtr); + polar_encoder_fast((uint64_t*)dci_pdu->Payload, (void*)encoder_output, n_RNTI,1,currentPtr); #ifdef DEBUG_CHANNEL_CODING - printf("polar rnti %x,length %d, L %d\n",n_RNTI, pdcch_pdu_rel15->dci_pdu.PayloadSizeBits[d],pdcch_pdu_rel15->dci_pdu.AggregationLevel[d]); + printf("polar rnti %x,length %d, L %d\n",n_RNTI, dci_pdu->PayloadSizeBits,pdcch_pdu_rel15->dci_pdu.AggregationLevel[d]); printf("DCI PDU: [0]->0x%lx \t [1]->0x%lx\n", - ((uint64_t*)pdcch_pdu_rel15->dci_pdu.Payload[d])[0], ((uint64_t*)pdcch_pdu_rel15->dci_pdu.Payload[d])[1]); + ((uint64_t*)dci_pdu->Payload)[0], ((uint64_t*)dci_pdu->Payload)[1]); printf("Encoded Payload (length:%d dwords):\n", encoded_length>>5); for (int i=0; i<encoded_length>>5; i++) @@ -173,7 +174,7 @@ void nr_generate_dci(PHY_VARS_gNB *gNB, int reg_list_index = 0; int reg_list_order[NR_MAX_PDCCH_AGG_LEVEL] = {}; for (int p = 0; p < NR_MAX_PDCCH_AGG_LEVEL; p++) { - for(int p2 = 0; p2 < pdcch_pdu_rel15->dci_pdu.AggregationLevel[d]; p2++) { + for(int p2 = 0; p2 < dci_pdu->AggregationLevel; p2++) { if(gNB->cce_list[d][p2].reg_list[0].reg_idx == p * NR_NB_REG_PER_CCE) { reg_list_order[reg_list_index] = p2; reg_list_index++; @@ -183,7 +184,7 @@ void nr_generate_dci(PHY_VARS_gNB *gNB, } /*Mapping the encoded DCI along with the DMRS */ - for (int cce_count = 0; cce_count < pdcch_pdu_rel15->dci_pdu.AggregationLevel[d]; cce_count ++) { + for (int cce_count = 0; cce_count < dci_pdu->AggregationLevel; cce_count ++) { int8_t cce_idx = reg_list_order[cce_count]; @@ -239,9 +240,10 @@ void nr_generate_dci(PHY_VARS_gNB *gNB, } // reg_in_cce_idx } // cce_count - LOG_D(PHY, "DCI: payloadSize = %d | payload = %llx\n", - *pdcch_pdu_rel15->dci_pdu.PayloadSizeBits,*(unsigned long long*)pdcch_pdu_rel15->dci_pdu.Payload); - + LOG_D(PHY, + "DCI: payloadSize = %d | payload = %llx\n", + dci_pdu->PayloadSizeBits, + *(unsigned long long *)dci_pdu->Payload); } // for (int d=0;d<pdcch_pdu_rel15->numDlDci;d++) } diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci_tools.c b/openair1/PHY/NR_TRANSPORT/nr_dci_tools.c index 2b64a3062cc6f449ad126c5a80cf91e7c2f3bbaf..3814c782952a7d6dbe8ac2007fb039b2d360fb61 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci_tools.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dci_tools.c @@ -142,7 +142,7 @@ void nr_fill_cce_list(PHY_VARS_gNB *gNB, uint8_t m, nfapi_nr_dl_tti_pdcch_pdu_r AssertFatal(N_reg > 0,"N_reg cannot be 0\n"); for (int d=0;d<pdcch_pdu_rel15->numDlDci;d++) { - int L = pdcch_pdu_rel15->dci_pdu.AggregationLevel[d]; + int L = pdcch_pdu_rel15->dci_pdu[d].AggregationLevel; if (pdcch_pdu_rel15->CoreSetType == NFAPI_NR_CSET_CONFIG_MIB_SIB1) AssertFatal(L>=4, "Invalid aggregation level for SIB1 configured PDCCH %d\n", L); @@ -153,10 +153,10 @@ void nr_fill_cce_list(PHY_VARS_gNB *gNB, uint8_t m, nfapi_nr_dl_tti_pdcch_pdu_r C = N_reg/(bsize*R); } - LOG_D(PHY, "CCE list generation for candidate %d: bundle size %d ilv size %d CceIndex %d\n", m, bsize, R, pdcch_pdu_rel15->dci_pdu.CceIndex[d]); + LOG_D(PHY, "CCE list generation for candidate %d: bundle size %d ilv size %d CceIndex %d\n", m, bsize, R, pdcch_pdu_rel15->dci_pdu[d].CceIndex); for (uint8_t cce_idx=0; cce_idx<L; cce_idx++) { cce = &gNB->cce_list[d][cce_idx]; - cce->cce_idx = pdcch_pdu_rel15->dci_pdu.CceIndex[d] + cce_idx; + cce->cce_idx = pdcch_pdu_rel15->dci_pdu[d].CceIndex + cce_idx; LOG_D(PHY, "cce_idx %d\n", cce->cce_idx); if (pdcch_pdu_rel15->CceRegMappingType == NFAPI_NR_CCE_REG_MAPPING_INTERLEAVED) { @@ -236,25 +236,24 @@ void nr_fill_dci(PHY_VARS_gNB *gNB, for (int i=0;i<pdcch_pdu_rel15->numDlDci;i++) { - //uint64_t *dci_pdu = (uint64_t*)pdcch_pdu_rel15->dci_pdu.Payload[i]; + //uint64_t *dci_pdu = (uint64_t*)pdcch_pdu_rel15->dci_pdu[i].Payload; - int dlsch_id = find_nr_dlsch(pdcch_pdu_rel15->dci_pdu.RNTI[i],gNB,SEARCH_EXIST_OR_FREE); + int dlsch_id = find_nr_dlsch(pdcch_pdu_rel15->dci_pdu[i].RNTI,gNB,SEARCH_EXIST_OR_FREE); if( (dlsch_id<0) || (dlsch_id>=NUMBER_OF_NR_DLSCH_MAX) ){ - LOG_E(PHY,"illegal dlsch_id found!!! rnti %04x dlsch_id %d\n",(unsigned int)pdcch_pdu_rel15->dci_pdu.RNTI[i],dlsch_id); + LOG_E(PHY,"illegal dlsch_id found!!! rnti %04x dlsch_id %d\n",(unsigned int)pdcch_pdu_rel15->dci_pdu[i].RNTI,dlsch_id); return; } dlsch = gNB->dlsch[dlsch_id][0]; - int num_slots_tdd = (gNB->frame_parms.slots_per_frame)>>(7-gNB->gNB_config.tdd_table.tdd_period.value); - int harq_pid = slot % num_slots_tdd; + int harq_pid = 0; dlsch->slot_tx[slot] = 1; - dlsch->harq_ids[frame%2][slot] = harq_pid; + dlsch->harq_ids[frame % 2][slot] = 0; AssertFatal(harq_pid < 8 && harq_pid >= 0, "illegal harq_pid %d\n",harq_pid); dlsch->harq_mask |= (1<<harq_pid); - dlsch->rnti = pdcch_pdu_rel15->dci_pdu.RNTI[i]; + dlsch->rnti = pdcch_pdu_rel15->dci_pdu[i].RNTI; // nr_fill_cce_list(gNB,0); /* @@ -300,7 +299,7 @@ void nr_fill_ul_dci(PHY_VARS_gNB *gNB, for (int i=0;i<pdcch_pdu_rel15->numDlDci;i++) { - //uint64_t *dci_pdu = (uint64_t*)pdcch_pdu_rel15->dci_pdu.Payload[i]; + //uint64_t *dci_pdu = (uint64_t*)pdcch_pdu_rel15->dci_pdu[i].Payload; // if there's no DL DCI then generate CCE list // nr_fill_cce_list(gNB,0); diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index e3627b93445533a0d342ea4a6918b83d7995e52b..1cce5e117465f125538e57f48f1cd2d6f3fdf8a3 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -136,8 +136,7 @@ uint8_t nr_generate_pdsch(PHY_VARS_gNB *gNB, dlsch = gNB->dlsch[dlsch_id][0]; if (dlsch->slot_tx[slot] == 0) continue; - int harq_pid = dlsch->harq_ids[frame%2][slot]; - NR_DL_gNB_HARQ_t *harq = dlsch->harq_processes[harq_pid]; + NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15; uint32_t scrambled_output[NR_MAX_NB_CODEWORDS][NR_MAX_PDSCH_ENCODED_LENGTH>>5]; int16_t **mod_symbs = (int16_t**)dlsch->mod_symbs; @@ -421,15 +420,8 @@ void dump_pdsch_stats(PHY_VARS_gNB *gNB) { for (int i=0;i<NUMBER_OF_NR_SCH_STATS_MAX;i++) if (gNB->dlsch_stats[i].rnti > 0) - LOG_I(PHY,"DLSCH RNTI %x: round_trials %d(%1.1e):%d(%1.1e):%d(%1.1e):%d, current_Qm %d, current_RI %d, total_bytes TX %d\n", + LOG_D(PHY,"DLSCH RNTI %x: current_Qm %d, current_RI %d, total_bytes TX %d\n", gNB->dlsch_stats[i].rnti, - gNB->dlsch_stats[i].round_trials[0], - (double)gNB->dlsch_stats[i].round_trials[1]/gNB->dlsch_stats[i].round_trials[0], - gNB->dlsch_stats[i].round_trials[1], - (double)gNB->dlsch_stats[i].round_trials[2]/gNB->dlsch_stats[i].round_trials[0], - gNB->dlsch_stats[i].round_trials[2], - (double)gNB->dlsch_stats[i].round_trials[3]/gNB->dlsch_stats[i].round_trials[0], - gNB->dlsch_stats[i].round_trials[3], gNB->dlsch_stats[i].current_Qm, gNB->dlsch_stats[i].current_RI, gNB->dlsch_stats[i].total_bytes_tx); diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c index cb395ff4aff5850306c85a728bef4aaeb9e1c405..e6544bbe0c2a0115028d2fe1a9011cafd328dd74 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c @@ -51,7 +51,6 @@ void free_gNB_dlsch(NR_gNB_DLSCH_t **dlschptr, uint16_t N_RB) { - int i; int r; NR_gNB_DLSCH_t *dlsch = *dlschptr; @@ -63,76 +62,61 @@ void free_gNB_dlsch(NR_gNB_DLSCH_t **dlschptr, uint16_t N_RB) a_segments = a_segments*N_RB; a_segments = a_segments/273 +1; } - - - + + + #ifdef DEBUG_DLSCH_FREE LOG_D(PHY,"Freeing dlsch %p\n",dlsch); #endif - - for (i=0; i<dlsch->Mdlharq; i++) { -#ifdef DEBUG_DLSCH_FREE - LOG_D(PHY,"Freeing dlsch process %d\n",i); -#endif - - if (dlsch->harq_processes[i]) { -#ifdef DEBUG_DLSCH_FREE - LOG_D(PHY,"Freeing dlsch process %d (%p)\n",i,dlsch->harq_processes[i]); -#endif - - if (dlsch->harq_processes[i]->b) { - free16(dlsch->harq_processes[i]->b,a_segments*1056); - dlsch->harq_processes[i]->b = NULL; + NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; + if (harq->b) { + free16(harq->b, a_segments * 1056); + harq->b = NULL; #ifdef DEBUG_DLSCH_FREE - LOG_D(PHY,"Freeing dlsch process %d b (%p)\n",i,dlsch->harq_processes[i]->b); + LOG_D(PHY, "Freeing harq->b (%p)\n", harq->b); #endif - } - if (dlsch->harq_processes[i]->e) { - free16(dlsch->harq_processes[i]->e,14*N_RB*12*8); - dlsch->harq_processes[i]->e = NULL; + if (harq->e) { + free16(harq->e, 14 * N_RB * 12 * 8); + harq->e = NULL; #ifdef DEBUG_DLSCH_FREE - printf("Freeing dlsch process %d e (%p)\n",i,dlsch->harq_processes[i]->e); + printf("Freeing dlsch process %d e (%p)\n", i, harq->e); #endif - } + } - if (dlsch->harq_processes[i]->f) { - free16(dlsch->harq_processes[i]->f,14*N_RB*12*8); - dlsch->harq_processes[i]->f = NULL; + if (harq->f) { + free16(harq->f, 14 * N_RB * 12 * 8); + harq->f = NULL; #ifdef DEBUG_DLSCH_FREE - printf("Freeing dlsch process %d f (%p)\n",i,dlsch->harq_processes[i]->f); + printf("Freeing dlsch process %d f (%p)\n", i, harq->f); #endif - } + } #ifdef DEBUG_DLSCH_FREE - LOG_D(PHY,"Freeing dlsch process %d c (%p)\n",i,dlsch->harq_processes[i]->c); + LOG_D(PHY, "Freeing dlsch process %d c (%p)\n", i, harq->c); #endif - for (r=0; r<a_segments; r++) { - + for (r = 0; r < a_segments; r++) { #ifdef DEBUG_DLSCH_FREE - LOG_D(PHY,"Freeing dlsch process %d c[%d] (%p)\n",i,r,dlsch->harq_processes[i]->c[r]); + LOG_D(PHY, "Freeing dlsch process %d c[%d] (%p)\n", i, r, harq->c[r]); #endif - if (dlsch->harq_processes[i]->c[r]) { - free16(dlsch->harq_processes[i]->c[r],1056); - dlsch->harq_processes[i]->c[r] = NULL; - } - if (dlsch->harq_processes[i]->d[r]) { - free16(dlsch->harq_processes[i]->d[r],3*8448); - dlsch->harq_processes[i]->d[r] = NULL; - } - - } - free16(dlsch->harq_processes[i],sizeof(NR_DL_gNB_HARQ_t)); - dlsch->harq_processes[i] = NULL; + if (harq->c[r]) { + free16(harq->c[r], 1056); + harq->c[r] = NULL; + } + if (harq->d[r]) { + free16(harq->d[r], 3 * 8448); + harq->d[r] = NULL; + } } + free16(harq, sizeof(NR_DL_gNB_HARQ_t)); + harq = NULL; } - - free16(dlsch,sizeof(NR_gNB_DLSCH_t)); - *dlschptr = NULL; } + free16(dlsch, sizeof(NR_gNB_DLSCH_t)); + *dlschptr = NULL; } NR_gNB_DLSCH_t *new_gNB_dlsch(NR_DL_FRAME_PARMS *frame_parms, @@ -142,9 +126,7 @@ NR_gNB_DLSCH_t *new_gNB_dlsch(NR_DL_FRAME_PARMS *frame_parms, uint8_t abstraction_flag, uint16_t N_RB) { - - NR_gNB_DLSCH_t *dlsch; - unsigned char exit_flag = 0,i,r,aa,layer; + unsigned char i,r,aa,layer; int re; uint16_t a_segments = MAX_NUM_NR_DLSCH_SEGMENTS; //number of segments to be allocated @@ -155,127 +137,74 @@ NR_gNB_DLSCH_t *new_gNB_dlsch(NR_DL_FRAME_PARMS *frame_parms, uint16_t dlsch_bytes = a_segments*1056; // allocated bytes per segment - - dlsch = (NR_gNB_DLSCH_t *)malloc16(sizeof(NR_gNB_DLSCH_t)); + NR_gNB_DLSCH_t *dlsch = malloc16(sizeof(NR_gNB_DLSCH_t)); + AssertFatal(dlsch, "cannot allocate dlsch\n"); - if (dlsch) { - bzero(dlsch,sizeof(NR_gNB_DLSCH_t)); - dlsch->Kmimo = Kmimo; - dlsch->Mdlharq = Mdlharq; - dlsch->Mlimit = 4; - dlsch->Nsoft = Nsoft; - - for (layer=0; layer<NR_MAX_NB_LAYERS; layer++) { - dlsch->ue_spec_bf_weights[layer] = (int32_t**)malloc16(64*sizeof(int32_t*)); - - for (aa=0; aa<64; aa++) { - dlsch->ue_spec_bf_weights[layer][aa] = (int32_t *)malloc16(OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); - for (re=0;re<OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES; re++) { - dlsch->ue_spec_bf_weights[layer][aa][re] = 0x00007fff; - } - } - - dlsch->txdataF[layer] = (int32_t *)malloc16((NR_MAX_PDSCH_ENCODED_LENGTH/NR_MAX_NB_LAYERS)*sizeof(int32_t)); // NR_MAX_NB_LAYERS is already included in NR_MAX_PDSCH_ENCODED_LENGTH - } - - for (int q=0; q<NR_MAX_NB_CODEWORDS; q++) - dlsch->mod_symbs[q] = (int32_t *)malloc16(NR_MAX_PDSCH_ENCODED_LENGTH*sizeof(int32_t)); - - dlsch->calib_dl_ch_estimates = (int32_t**)malloc16(64*sizeof(int32_t*)); - for (aa=0; aa<64; aa++) { - dlsch->calib_dl_ch_estimates[aa] = (int32_t *)malloc16(OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES*sizeof(int32_t)); - - } - - for (i=0; i<20; i++) { - dlsch->harq_ids[0][i] = 0; - dlsch->harq_ids[1][i] = 0; - } - - for (i=0; i<Mdlharq; i++) { - dlsch->harq_processes[i] = (NR_DL_gNB_HARQ_t *)malloc16(sizeof(NR_DL_gNB_HARQ_t)); - LOG_T(PHY, "Required mem size %d dlsch->harq_processes[%d] %p\n", - dlsch_bytes, i,dlsch->harq_processes[i]); - - if (dlsch->harq_processes[i]) { - bzero(dlsch->harq_processes[i],sizeof(NR_DL_gNB_HARQ_t)); - // dlsch->harq_processes[i]->first_tx=1; - dlsch->harq_processes[i]->b = (unsigned char*)malloc16(dlsch_bytes); - dlsch->harq_processes[i]->pdu = (uint8_t*)malloc16(dlsch_bytes); - if (dlsch->harq_processes[i]->pdu) { - bzero(dlsch->harq_processes[i]->pdu,dlsch_bytes); - nr_emulate_dlsch_payload(dlsch->harq_processes[i]->pdu, (dlsch_bytes)>>3); - } else { - LOG_D(PHY,"Can't allocate PDU\n"); - exit_flag=1; - } - - if (dlsch->harq_processes[i]->b) { - bzero(dlsch->harq_processes[i]->b,dlsch_bytes); - } else { - LOG_D(PHY,"Can't get b\n"); - exit_flag=1; - } + bzero(dlsch,sizeof(NR_gNB_DLSCH_t)); + dlsch->Kmimo = Kmimo; + dlsch->Mdlharq = Mdlharq; + dlsch->Mlimit = 4; + dlsch->Nsoft = Nsoft; + + for (layer=0; layer<NR_MAX_NB_LAYERS; layer++) { + dlsch->ue_spec_bf_weights[layer] = (int32_t **)malloc16(64 * sizeof(int32_t *)); - if (abstraction_flag==0) { - for (r=0; r<a_segments; r++) { - // account for filler in first segment and CRCs for multiple segment case - // [hna] 8448 is the maximum CB size in NR - // 68*348 = 68*(maximum size of Zc) - // In section 5.3.2 in 38.212, the for loop is up to N + 2*Zc (maximum size of N is 66*Zc, therefore 68*Zc) - dlsch->harq_processes[i]->c[r] = (uint8_t*)malloc16(8448); - dlsch->harq_processes[i]->d[r] = (uint8_t*)malloc16(68*384); //max size for coded output - if (dlsch->harq_processes[i]->c[r]) { - bzero(dlsch->harq_processes[i]->c[r],8448); - } else { - LOG_D(PHY,"Can't get c\n"); - exit_flag=2; - } - if (dlsch->harq_processes[i]->d[r]) { - bzero(dlsch->harq_processes[i]->d[r],(3*8448)); - } else { - LOG_D(PHY,"Can't get d\n"); - exit_flag=2; - } - } - dlsch->harq_processes[i]->e = (uint8_t*)malloc16(14*N_RB*12*8); - if (dlsch->harq_processes[i]->e) { - bzero(dlsch->harq_processes[i]->e,14*N_RB*12*8); - } else { - printf("Can't get e\n"); - exit_flag=1; - } - dlsch->harq_processes[i]->f = (uint8_t*)malloc16(14*N_RB*12*8); - if (dlsch->harq_processes[i]->f) { - bzero(dlsch->harq_processes[i]->f,14*N_RB*12*8); - } else { - printf("Can't get f\n"); - exit_flag=1; - } - } - } else { - LOG_D(PHY,"Can't get harq_p %d\n",i); - exit_flag=3; + for (aa = 0; aa < 64; aa++) { + dlsch->ue_spec_bf_weights[layer][aa] = (int32_t *)malloc16(OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES * sizeof(int32_t)); + for (re = 0; re < OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES; re++) { + dlsch->ue_spec_bf_weights[layer][aa][re] = 0x00007fff; } } - if (exit_flag==0) { - for (i=0; i<Mdlharq; i++) { - dlsch->harq_processes[i]->round=0; - } - - return(dlsch); - } + dlsch->txdataF[layer] = + (int32_t *)malloc16((NR_MAX_PDSCH_ENCODED_LENGTH / NR_MAX_NB_LAYERS) + * sizeof(int32_t)); // NR_MAX_NB_LAYERS is already included in NR_MAX_PDSCH_ENCODED_LENGTH } - LOG_D(PHY,"new_gNB_dlsch exit flag %d, size of %ld\n", - exit_flag, sizeof(NR_gNB_DLSCH_t)); + for (int q = 0; q < NR_MAX_NB_CODEWORDS; q++) + dlsch->mod_symbs[q] = (int32_t *)malloc16(NR_MAX_PDSCH_ENCODED_LENGTH * sizeof(int32_t)); - free_gNB_dlsch(&dlsch,N_RB); + dlsch->calib_dl_ch_estimates = (int32_t **)malloc16(64 * sizeof(int32_t *)); + for (aa = 0; aa < 64; aa++) { + dlsch->calib_dl_ch_estimates[aa] = (int32_t *)malloc16(OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES * sizeof(int32_t)); + } - return(NULL); + for (i = 0; i < 20; i++) { + dlsch->harq_ids[0][i] = 0; + dlsch->harq_ids[1][i] = 0; + } + NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; + bzero(harq, sizeof(NR_DL_gNB_HARQ_t)); + + harq->b = malloc16(dlsch_bytes); + AssertFatal(harq->b, "cannot allocate memory for harq->b\n"); + harq->pdu = malloc16(dlsch_bytes); + AssertFatal(harq->pdu, "cannot allocate memory for harq->pdu\n"); + bzero(harq->pdu, dlsch_bytes); + nr_emulate_dlsch_payload(harq->pdu, (dlsch_bytes) >> 3); + bzero(harq->b, dlsch_bytes); + + for (r = 0; r < a_segments; r++) { + // account for filler in first segment and CRCs for multiple segment case + // [hna] 8448 is the maximum CB size in NR + // 68*348 = 68*(maximum size of Zc) + // In section 5.3.2 in 38.212, the for loop is up to N + 2*Zc (maximum size of N is 66*Zc, therefore 68*Zc) + harq->c[r] = malloc16(8448); + AssertFatal(harq->c[r], "cannot allocate harq->c[%d]\n", r); + harq->d[r] = malloc16(68 * 384); + AssertFatal(harq->d[r], "cannot allocate harq->d[%d]\n", r); // max size for coded output + bzero(harq->c[r], 8448); + bzero(harq->d[r], (3 * 8448)); + harq->e = malloc16(14 * N_RB * 12 * 8); + AssertFatal(harq->e, "cannot allocate harq->e\n"); + bzero(harq->e, 14 * N_RB * 12 * 8); + harq->f = malloc16(14 * N_RB * 12 * 8); + AssertFatal(harq->f, "cannot allocate harq->f\n"); + bzero(harq->f, 14 * N_RB * 12 * 8); + } + return(dlsch); } void clean_gNB_dlsch(NR_gNB_DLSCH_t *dlsch) @@ -284,28 +213,21 @@ void clean_gNB_dlsch(NR_gNB_DLSCH_t *dlsch) unsigned char Mdlharq; unsigned char i,j,r; - if (dlsch) { - Mdlharq = dlsch->Mdlharq; - dlsch->rnti = 0; - dlsch->active = 0; - - for (i=0; i<10; i++) { - dlsch->harq_ids[0][i] = Mdlharq; - dlsch->harq_ids[1][i] = Mdlharq; - } - for (i=0; i<Mdlharq; i++) { - if (dlsch->harq_processes[i]) { - // dlsch->harq_processes[i]->Ndi = 0; - //dlsch->harq_processes[i]->status = 0; - dlsch->harq_processes[i]->round = 0; - - for (j=0; j<96; j++) - for (r=0; r<MAX_NUM_NR_DLSCH_SEGMENTS; r++) - if (dlsch->harq_processes[i]->d[r]) - dlsch->harq_processes[i]->d[r][j] = NR_NULL; + AssertFatal(dlsch!=NULL,"dlsch is null\n"); + Mdlharq = dlsch->Mdlharq; + dlsch->rnti = 0; + dlsch->active = 0; + NR_DL_gNB_HARQ_t *harq=&dlsch->harq_process; - } - } + for (i=0; i<10; i++) { + dlsch->harq_ids[0][i] = Mdlharq; + dlsch->harq_ids[1][i] = Mdlharq; + } + for (i=0; i<Mdlharq; i++) { + for (j=0; j<96; j++) + for (r=0; r<MAX_NUM_NR_DLSCH_SEGMENTS; r++) + if (harq->d[r]) + harq->d[r][j] = NR_NULL; } } @@ -322,13 +244,12 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, unsigned int G; unsigned int crc=1; - uint8_t harq_pid = dlsch->harq_ids[frame%2][slot]; - AssertFatal(harq_pid<8 && harq_pid>=0,"illegal harq_pid %d\b",harq_pid); - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->harq_processes[harq_pid]->pdsch_pdu.pdsch_pdu_rel15; + NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; + nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15; uint16_t nb_rb = rel15->rbSize; uint8_t nb_symb_sch = rel15->NrOfSymbols; uint32_t A, Kb, F=0; - uint32_t *Zc = &dlsch->harq_processes[harq_pid]->Z; + uint32_t *Zc = &dlsch->harq_process.Z; uint8_t mod_order = rel15->qamModOrder[0]; uint16_t Kr=0,r; uint32_t r_offset=0; @@ -347,8 +268,7 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, float Coderate = 0.0; uint8_t Nl = 4; - dlsch->harq_processes[harq_pid]->round = nr_rv_round_map[rel15->rvIndex[0]]; - + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_DLSCH_ENCODING, VCD_FUNCTION_IN); A = rel15->TBSize[0]<<3; @@ -367,174 +287,157 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, } if (stats) { - stats->round_trials[dlsch->harq_processes[harq_pid]->round]++; stats->rnti = dlsch->rnti; - if (dlsch->harq_processes[harq_pid]->round == 0){ - stats->total_bytes_tx += rel15->TBSize[0]; - stats->current_RI = rel15->nrOfLayers; - stats->current_Qm = rel15->qamModOrder[0]; - } + stats->total_bytes_tx += rel15->TBSize[0]; + stats->current_RI = rel15->nrOfLayers; + stats->current_Qm = rel15->qamModOrder[0]; } G = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs,mod_order,rel15->nrOfLayers); LOG_D(PHY,"dlsch coding A %d G %d mod_order %d\n", A,G, mod_order); - // if (dlsch->harq_processes[harq_pid]->Ndi == 1) { // this is a new packet - if (dlsch->harq_processes[harq_pid]->round == 0) { // this is a new packet -#ifdef DEBUG_DLSCH_CODING - LOG_D(PHY,"encoding thinks this is a new packet \n"); -#endif - /* - int i; - LOG_D(PHY,"dlsch (tx): \n"); - for (i=0;i<(A>>3);i++) - LOG_D(PHY,"%02x\n",a[i]); - LOG_D(PHY,"\n"); - */ - - if (A > 3824) { - // Add 24-bit crc (polynomial A) to payload - crc = crc24a(a,A)>>8; - a[A>>3] = ((uint8_t*)&crc)[2]; - a[1+(A>>3)] = ((uint8_t*)&crc)[1]; - a[2+(A>>3)] = ((uint8_t*)&crc)[0]; - //printf("CRC %x (A %d)\n",crc,A); - //printf("a0 %d a1 %d a2 %d\n", a[A>>3], a[1+(A>>3)], a[2+(A>>3)]); + if (A > 3824) { + // Add 24-bit crc (polynomial A) to payload + crc = crc24a(a,A)>>8; + a[A>>3] = ((uint8_t*)&crc)[2]; + a[1+(A>>3)] = ((uint8_t*)&crc)[1]; + a[2+(A>>3)] = ((uint8_t*)&crc)[0]; + //printf("CRC %x (A %d)\n",crc,A); + //printf("a0 %d a1 %d a2 %d\n", a[A>>3], a[1+(A>>3)], a[2+(A>>3)]); + + harq->B = A+24; + // harq->b = a; + + AssertFatal((A / 8) + 4 <= MAX_NR_DLSCH_PAYLOAD_BYTES, + "A %d is too big (A/8+4 = %d > %d)\n", + A, + (A / 8) + 4, + MAX_NR_DLSCH_PAYLOAD_BYTES); + + memcpy(harq->b, a, (A / 8) + 4); // why is this +4 if the CRC is only 3 bytes? + } + else { + // Add 16-bit crc (polynomial A) to payload + crc = crc16(a,A)>>16; + a[A>>3] = ((uint8_t*)&crc)[1]; + a[1+(A>>3)] = ((uint8_t*)&crc)[0]; + //printf("CRC %x (A %d)\n",crc,A); + //printf("a0 %d a1 %d \n", a[A>>3], a[1+(A>>3)]); + + harq->B = A+16; + // harq->b = a; + + AssertFatal((A / 8) + 3 <= MAX_NR_DLSCH_PAYLOAD_BYTES, + "A %d is too big (A/8+3 = %d > %d)\n", + A, + (A / 8) + 3, + MAX_NR_DLSCH_PAYLOAD_BYTES); + + memcpy(harq->b, a, (A / 8) + 3); // using 3 bytes to mimic the case of 24 bit crc + } + if (R<1000) + Coderate = (float) R /(float) 1024; + else // to scale for mcs 20 and 26 in table 5.1.3.1-2 which are decimal and input 2* in nr_tbs_tools + Coderate = (float) R /(float) 2048; - dlsch->harq_processes[harq_pid]->B = A+24; - // dlsch->harq_processes[harq_pid]->b = a; - - AssertFatal((A/8)+4 <= MAX_NR_DLSCH_PAYLOAD_BYTES,"A %d is too big (A/8+4 = %d > %d)\n",A,(A/8)+4,MAX_NR_DLSCH_PAYLOAD_BYTES); - - memcpy(dlsch->harq_processes[harq_pid]->b,a,(A/8)+4); // why is this +4 if the CRC is only 3 bytes? - } - else { - // Add 16-bit crc (polynomial A) to payload - crc = crc16(a,A)>>16; - a[A>>3] = ((uint8_t*)&crc)[1]; - a[1+(A>>3)] = ((uint8_t*)&crc)[0]; - //printf("CRC %x (A %d)\n",crc,A); - //printf("a0 %d a1 %d \n", a[A>>3], a[1+(A>>3)]); + if ((A <=292) || ((A<=3824) && (Coderate <= 0.6667)) || Coderate <= 0.25) + harq->BG = 2; + else + harq->BG = 1; - dlsch->harq_processes[harq_pid]->B = A+16; - // dlsch->harq_processes[harq_pid]->b = a; - - AssertFatal((A/8)+3 <= MAX_NR_DLSCH_PAYLOAD_BYTES,"A %d is too big (A/8+3 = %d > %d)\n",A,(A/8)+3,MAX_NR_DLSCH_PAYLOAD_BYTES); - - memcpy(dlsch->harq_processes[harq_pid]->b,a,(A/8)+3); // using 3 bytes to mimic the case of 24 bit crc - } - if (R<1000) - Coderate = (float) R /(float) 1024; - else // to scale for mcs 20 and 26 in table 5.1.3.1-2 which are decimal and input 2* in nr_tbs_tools - Coderate = (float) R /(float) 2048; - - if ((A <=292) || ((A<=3824) && (Coderate <= 0.6667)) || Coderate <= 0.25) - dlsch->harq_processes[harq_pid]->BG = 2; - else - dlsch->harq_processes[harq_pid]->BG = 1; - - start_meas(dlsch_segmentation_stats); - Kb = nr_segmentation(dlsch->harq_processes[harq_pid]->b, - dlsch->harq_processes[harq_pid]->c, - dlsch->harq_processes[harq_pid]->B, - &dlsch->harq_processes[harq_pid]->C, - &dlsch->harq_processes[harq_pid]->K, - Zc, - &dlsch->harq_processes[harq_pid]->F, - dlsch->harq_processes[harq_pid]->BG); - stop_meas(dlsch_segmentation_stats); - F = dlsch->harq_processes[harq_pid]->F; - - Kr = dlsch->harq_processes[harq_pid]->K; + start_meas(dlsch_segmentation_stats); + Kb = nr_segmentation(harq->b, harq->c, harq->B, &harq->C, &harq->K, Zc, &harq->F, harq->BG); + stop_meas(dlsch_segmentation_stats); + F = harq->F; + + Kr = harq->K; #ifdef DEBUG_DLSCH_CODING - uint16_t Kr_bytes; - Kr_bytes = Kr>>3; + uint16_t Kr_bytes; + Kr_bytes = Kr>>3; #endif - //printf("segment Z %d k %d Kr %d BG %d C %d\n", *Zc,dlsch->harq_processes[harq_pid]->K,Kr,BG,dlsch->harq_processes[harq_pid]->C); - - for (r=0; r<dlsch->harq_processes[harq_pid]->C; r++) { - //d_tmp[r] = &dlsch->harq_processes[harq_pid]->d[r][0]; - //channel_input[r] = &dlsch->harq_processes[harq_pid]->d[r][0]; + //printf("segment Z %d k %d Kr %d BG %d C %d\n", *Zc,harq->K,Kr,BG,harq->C); + + for (r=0; r<harq->C; r++) { + //d_tmp[r] = &harq->d[r][0]; + //channel_input[r] = &harq->d[r][0]; #ifdef DEBUG_DLSCH_CODING - LOG_D(PHY,"Encoder: B %d F %d \n",dlsch->harq_processes[harq_pid]->B, dlsch->harq_processes[harq_pid]->F); - LOG_D(PHY,"start ldpc encoder segment %d/%d\n",r,dlsch->harq_processes[harq_pid]->C); - LOG_D(PHY,"input %d %d %d %d %d \n", dlsch->harq_processes[harq_pid]->c[r][0], dlsch->harq_processes[harq_pid]->c[r][1], dlsch->harq_processes[harq_pid]->c[r][2],dlsch->harq_processes[harq_pid]->c[r][3], dlsch->harq_processes[harq_pid]->c[r][4]); - for (int cnt =0 ; cnt < 22*(*Zc)/8; cnt ++){ - LOG_D(PHY,"%d ", dlsch->harq_processes[harq_pid]->c[r][cnt]); - } - LOG_D(PHY,"\n"); - -#endif - //ldpc_encoder_orig((unsigned char*)dlsch->harq_processes[harq_pid]->c[r],dlsch->harq_processes[harq_pid]->d[r],*Zc,Kb,Kr,BG,0); - //ldpc_encoder_optim((unsigned char*)dlsch->harq_processes[harq_pid]->c[r],(unsigned char*)&dlsch->harq_processes[harq_pid]->d[r][0],*Zc,Kb,Kr,BG,NULL,NULL,NULL,NULL); + LOG_D(PHY,"Encoder: B %d F %d \n",harq->B, harq->F); + LOG_D(PHY,"start ldpc encoder segment %d/%d\n",r,harq->C); + LOG_D(PHY,"input %d %d %d %d %d \n", harq->c[r][0], harq->c[r][1], harq->c[r][2],harq->c[r][3], harq->c[r][4]); + for (int cnt =0 ; cnt < 22*(*Zc)/8; cnt ++){ + LOG_D(PHY,"%d ", harq->c[r][cnt]); } - encoder_implemparams_t impp; - impp.n_segments=dlsch->harq_processes[harq_pid]->C; - impp.tprep = tprep; - impp.tinput = tinput; - impp.tparity = tparity; - impp.toutput = toutput; - - for(int j=0;j<(dlsch->harq_processes[harq_pid]->C/8+1);j++) { - impp.macro_num=j; - nrLDPC_encoder(dlsch->harq_processes[harq_pid]->c,dlsch->harq_processes[harq_pid]->d,*Zc,Kb,Kr,dlsch->harq_processes[harq_pid]->BG,&impp); - } - - -#ifdef DEBUG_DLSCH_CODING - write_output("enc_input0.m","enc_in0",&dlsch->harq_processes[harq_pid]->c[0][0],Kr_bytes,1,4); - write_output("enc_output0.m","enc0",&dlsch->harq_processes[harq_pid]->d[0][0],(3*8*Kr_bytes)+12,1,4); + LOG_D(PHY,"\n"); + #endif - + //ldpc_encoder_orig((unsigned char*)harq->c[r],harq->d[r],*Zc,Kb,Kr,BG,0); + //ldpc_encoder_optim((unsigned char*)harq->c[r],(unsigned char*)&harq->d[r][0],*Zc,Kb,Kr,BG,NULL,NULL,NULL,NULL); } + encoder_implemparams_t impp; + impp.n_segments=harq->C; + impp.tprep = tprep; + impp.tinput = tinput; + impp.tparity = tparity; + impp.toutput = toutput; + + for(int j=0;j<(harq->C/8+1);j++) { + impp.macro_num=j; + nrLDPC_encoder(harq->c,harq->d,*Zc,Kb,Kr,harq->BG,&impp); + } + - F = dlsch->harq_processes[harq_pid]->F; - - Kr = dlsch->harq_processes[harq_pid]->K; - for (r=0; r<dlsch->harq_processes[harq_pid]->C; r++) { - +#ifdef DEBUG_DLSCH_CODING + write_output("enc_input0.m","enc_in0",&harq->c[0][0],Kr_bytes,1,4); + write_output("enc_output0.m","enc0",&harq->d[0][0],(3*8*Kr_bytes)+12,1,4); +#endif + + F = harq->F; + + Kr = harq->K; + for (r=0; r<harq->C; r++) { + if (F>0) { for (int k=(Kr-F-2*(*Zc)); k<Kr-2*(*Zc); k++) { // writing into positions d[r][k-2Zc] as in clause 5.3.2 step 2) in 38.212 - dlsch->harq_processes[harq_pid]->d[r][k] = NR_NULL; + harq->d[r][k] = NR_NULL; //if (k<(Kr-F+8)) - //printf("r %d filler bits [%d] = %d \n", r,k, dlsch->harq_processes[harq_pid]->d[r][k]); + //printf("r %d filler bits [%d] = %d \n", r,k, harq->d[r][k]); } } - - - + + + #ifdef DEBUG_DLSCH_CODING - LOG_D(PHY,"rvidx in encoding = %d\n", rel15->rvIndex[0]); + LOG_D(PHY,"rvidx in encoding = %d\n", rel15->rvIndex[0]); #endif - - E = nr_get_E(G, dlsch->harq_processes[harq_pid]->C, mod_order, rel15->nrOfLayers, r); - + + E = nr_get_E(G, harq->C, mod_order, rel15->nrOfLayers, r); + //#ifdef DEBUG_DLSCH_CODING LOG_D(PHY,"Rate Matching, Code segment %d/%d (coded bits (G) %u, E %d, Filler bits %d, Filler offset %d mod_order %d, nb_rb %d)...\n", r, - dlsch->harq_processes[harq_pid]->C, + harq->C, G, E, F, Kr-F-2*(*Zc), mod_order,nb_rb); - + // for tbslbrm calculation according to 5.4.2.1 of 38.212 if (rel15->nrOfLayers < Nl) Nl = rel15->nrOfLayers; - + Tbslbrm = nr_compute_tbslbrm(rel15->mcsTable[0],nb_rb,Nl); - + start_meas(dlsch_rate_matching_stats); nr_rate_matching_ldpc(Ilbrm, Tbslbrm, - dlsch->harq_processes[harq_pid]->BG, + harq->BG, *Zc, - dlsch->harq_processes[harq_pid]->d[r], - dlsch->harq_processes[harq_pid]->e+r_offset, - dlsch->harq_processes[harq_pid]->C, + harq->d[r], + harq->e+r_offset, + harq->C, F, Kr-F-2*(*Zc), rel15->rvIndex[0], @@ -542,22 +445,22 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB, stop_meas(dlsch_rate_matching_stats); #ifdef DEBUG_DLSCH_CODING for (int i =0; i<16; i++) - printf("output ratematching e[%d]= %d r_offset %u\n", i,dlsch->harq_processes[harq_pid]->e[i+r_offset], r_offset); + printf("output ratematching e[%d]= %d r_offset %u\n", i,harq->e[i+r_offset], r_offset); #endif start_meas(dlsch_interleaving_stats); nr_interleaving_ldpc(E, mod_order, - dlsch->harq_processes[harq_pid]->e+r_offset, - dlsch->harq_processes[harq_pid]->f+r_offset); + harq->e+r_offset, + harq->f+r_offset); stop_meas(dlsch_interleaving_stats); #ifdef DEBUG_DLSCH_CODING for (int i =0; i<16; i++) - printf("output interleaving f[%d]= %d r_offset %u\n", i,dlsch->harq_processes[harq_pid]->f[i+r_offset], r_offset); + printf("output interleaving f[%d]= %d r_offset %u\n", i,harq->f[i+r_offset], r_offset); - if (r==dlsch->harq_processes[harq_pid]->C-1) - write_output("enc_output.m","enc",dlsch->harq_processes[harq_pid]->f,G,1,4); + if (r==harq->C-1) + write_output("enc_output.m","enc",harq->f,G,1,4); #endif r_offset += E; diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c index 5ce2c45a7dd94f4dcd4a133190fe2fdbd37b5416..05d6c4c112bbe35ccc906425545ca63d25a85989 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c @@ -289,12 +289,12 @@ void nr_fill_dlsch(PHY_VARS_gNB *gNB, AssertFatal( (dlsch_id>=0) && (dlsch_id<NUMBER_OF_NR_DLSCH_MAX), "illegal or no dlsch_id found!!! rnti %04x dlsch_id %d\n",rel15->rnti,dlsch_id); NR_gNB_DLSCH_t *dlsch = gNB->dlsch[dlsch_id][0]; - NR_DL_gNB_HARQ_t **harq = dlsch->harq_processes; + NR_DL_gNB_HARQ_t *harq = &dlsch->harq_process; /// DLSCH struct - memcpy((void*)&harq[dlsch->harq_ids[frame%2][slot]]->pdsch_pdu, (void*)pdsch_pdu, sizeof(nfapi_nr_dl_tti_pdsch_pdu)); + memcpy((void*)&harq->pdsch_pdu, (void*)pdsch_pdu, sizeof(nfapi_nr_dl_tti_pdsch_pdu)); gNB->num_pdsch_rnti[slot]++; AssertFatal(sdu!=NULL,"sdu is null\n"); - harq[dlsch->harq_ids[frame%2][slot]]->pdu = sdu; + harq->pdu = sdu; } diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index 83a66b55fb2c9d9e1709c07c6a47db8701084628..2d1fdff4be6d0c0803ae1ab9d75cdb4b7500e704 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -393,6 +393,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, // first bit of bitmap for sr presence and second bit for acknack presence uci_pdu->pduBitmap = pucch_pdu->sr_flag | ((pucch_pdu->bit_len_harq>0)<<1); uci_pdu->pucch_format = 0; // format 0 + uci_pdu->rnti = pucch_pdu->rnti; uci_pdu->ul_cqi = cqi; uci_pdu->timing_advance = 0xffff; // currently not valid uci_pdu->rssi = 1280 - (10*dB_fixed(32767*32767)-dB_fixed_times10(signal_energy_nodc(&rxdataF[0][pucch_pdu->start_symbol_index*frame_parms->ofdm_symbol_size+re_offset],12))); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c index b9245640c79d319215ad13ce1605719e0c66439a..429bd9a836857abedbad4d99aec1880ebf60f704 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c @@ -203,7 +203,7 @@ NR_UE_DLSCH_t *new_nr_ue_dlsch(uint8_t Kmimo,uint8_t Mdlharq,uint32_t Nsoft,uint return(dlsch); } - LOG_I(PHY,"new_ue_dlsch with size %zu: exit_flag = %u\n",sizeof(NR_DL_UE_HARQ_t), exit_flag); + LOG_D(PHY,"new_ue_dlsch with size %zu: exit_flag = %u\n",sizeof(NR_DL_UE_HARQ_t), exit_flag); free_nr_ue_dlsch(&dlsch,N_RB_DL); return(NULL); @@ -577,7 +577,7 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, // Fixme: correct type is unsigned, but nrLDPC_decoder and all called behind use signed int if (check_crc((uint8_t*)llrProcBuf,length_dec,harq_process->F,crc_type)) { - LOG_I(PHY,"Segment %u CRC OK\n\033[0m",r); + LOG_D(PHY,"Segment %u CRC OK\n\033[0m",r); if (r==0) { for (int i=0;i<10;i++) LOG_D(PHY,"byte %d : %x\n",i,((uint8_t*)llrProcBuf)[i]); } @@ -617,13 +617,13 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, if ((err_flag == 0) && (ret>=(1+dlsch->max_ldpc_iterations))) {// a Code segment is in error so break; - LOG_I(PHY,"AbsSubframe %d.%d CRC failed, segment %d/%d \n",frame%1024,nr_slot_rx,r,harq_process->C-1); + LOG_D(PHY,"AbsSubframe %d.%d CRC failed, segment %d/%d \n",frame%1024,nr_slot_rx,r,harq_process->C-1); err_flag = 1; } } if (err_flag == 1) { - LOG_I(PHY,"[UE %d] DLSCH: Setting NAK for SFN/SF %d/%d (pid %d, status %d, round %d, TBS %d, mcs %d) Kr %d r %d harq_process->round %d\n", + LOG_D(PHY,"[UE %d] DLSCH: Setting NAK for SFN/SF %d/%d (pid %d, status %d, round %d, TBS %d, mcs %d) Kr %d r %d harq_process->round %d\n", phy_vars_ue->Mod_id, frame, nr_slot_rx, harq_pid,harq_process->status, harq_process->round,harq_process->TBS,harq_process->mcs,Kr,r,harq_process->round); harq_process->harq_ack.ack = 0; @@ -639,7 +639,7 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, if(is_crnti) { - LOG_I(PHY,"[UE %d] DLSCH: Setting NACK for nr_slot_rx %d (pid %d, pid status %d, round %d/Max %d, TBS %d)\n", + LOG_D(PHY,"[UE %d] DLSCH: Setting NACK for nr_slot_rx %d (pid %d, pid status %d, round %d/Max %d, TBS %d)\n", phy_vars_ue->Mod_id,nr_slot_rx,harq_pid,harq_process->status,harq_process->round,dlsch->Mdlharq,harq_process->TBS); } @@ -813,6 +813,9 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, nb_rb = harq_process->nb_rb; harq_process->trials[harq_process->round]++; + // HARQ stats + phy_vars_ue->dl_stats[harq_process->round]++; + uint16_t nb_rb_oh = 0; // it was not computed at UE side even before and set to 0 in nr_compute_tbs harq_process->TBS = nr_compute_tbs(harq_process->Qm,harq_process->R,nb_rb,nb_symb_sch,nb_re_dmrs*length_dmrs, nb_rb_oh, 0, harq_process->Nl); @@ -826,7 +829,7 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, G = harq_process->G; - LOG_I(PHY,"DLSCH Decoding main, harq_pid %d TBS %d G %d, nb_re_dmrs %d, length_dmrs %d mcs %d Nl %d nb_symb_sch %d nb_rb %d\n",harq_pid,A,G, nb_re_dmrs, length_dmrs, harq_process->mcs, harq_process->Nl, nb_symb_sch,nb_rb); + LOG_D(PHY,"DLSCH Decoding main, harq_pid %d TBS %d G %d, nb_re_dmrs %d, length_dmrs %d mcs %d Nl %d nb_symb_sch %d nb_rb %d\n",harq_pid,A,G, nb_re_dmrs, length_dmrs, harq_process->mcs, harq_process->Nl, nb_symb_sch,nb_rb); proc->decoder_main_available = 1; proc->decoder_thread_available = 0; @@ -905,7 +908,7 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, return((1+dlsch->max_ldpc_iterations)); } if (LOG_DEBUGFLAG(DEBUG_DLSCH_DECOD)) - LOG_I(PHY,"Segmentation: C %d, K %d\n",harq_process->C,harq_process->K); + LOG_D(PHY,"Segmentation: C %d, K %d\n",harq_process->C,harq_process->K); notifiedFIFO_elt_t *res_dl; @@ -1079,7 +1082,7 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, #if UE_TIMING_TRACE start_meas(dlsch_turbo_decoding_stats); #endif - LOG_I(PHY,"mthread AbsSubframe %d.%d Start LDPC segment %d/%d \n",frame%1024,nr_slot_rx,r,harq_process->C-1); + LOG_D(PHY,"mthread AbsSubframe %d.%d Start LDPC segment %d/%d \n",frame%1024,nr_slot_rx,r,harq_process->C-1); /*for (int cnt =0; cnt < (kc-2)*p_decParams->Z; cnt++){ inv_d[cnt] = (1)*harq_process->d[r][cnt]; @@ -1119,7 +1122,7 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, ret = 2; } else { - LOG_I(PHY,"CRC NOK\n"); + LOG_D(PHY,"CRC NOK\n"); ret = 1+dlsch->max_ldpc_iterations; } @@ -1160,7 +1163,7 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, if ((err_flag == 0) && (ret>=(1+dlsch->max_ldpc_iterations))) {// a Code segment is in error so break; - LOG_I(PHY,"AbsSubframe %d.%d CRC failed, segment %d/%d \n",frame%1024,nr_slot_rx,r,harq_process->C-1); + LOG_D(PHY,"AbsSubframe %d.%d CRC failed, segment %d/%d \n",frame%1024,nr_slot_rx,r,harq_process->C-1); err_flag = 1; } //} //loop r @@ -1181,7 +1184,7 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue, } if(is_crnti) { - LOG_I(PHY,"[UE %d] DLSCH: Setting NACK for nr_slot_rx %d (pid %d, pid status %d, round %d/Max %d, TBS %d)\n", + LOG_D(PHY,"[UE %d] DLSCH: Setting NACK for nr_slot_rx %d (pid %d, pid status %d, round %d/Max %d, TBS %d)\n", phy_vars_ue->Mod_id,nr_slot_rx,harq_pid,harq_process->status,harq_process->round,dlsch->Mlimit,harq_process->TBS); } @@ -1332,7 +1335,7 @@ void nr_dlsch_decoding_process(void *arg) p_nrLDPC_procBuf = harq_process->p_nrLDPC_procBuf[r]; nb_symb_sch = harq_process->nb_symbols; - LOG_I(PHY,"dlsch decoding process frame %d slot %d segment %d r %u nb symb %d \n", frame, proc->nr_slot_rx, proc->num_seg, r, harq_process->nb_symbols); + LOG_D(PHY,"dlsch decoding process frame %d slot %d segment %d r %u nb symb %d \n", frame, proc->nr_slot_rx, proc->num_seg, r, harq_process->nb_symbols); nb_rb = harq_process->nb_rb; @@ -1351,7 +1354,7 @@ void nr_dlsch_decoding_process(void *arg) harq_process->G = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs, harq_process->Qm,harq_process->Nl); G = harq_process->G; - LOG_I(PHY,"DLSCH Decoding process, harq_pid %d TBS %d G %d mcs %d Nl %d nb_symb_sch %d nb_rb %d\n",harq_pid,A,G, harq_process->mcs, harq_process->Nl, nb_symb_sch,nb_rb); + LOG_D(PHY,"DLSCH Decoding process, harq_pid %d TBS %d G %d mcs %d Nl %d nb_symb_sch %d nb_rb %d\n",harq_pid,A,G, harq_process->mcs, harq_process->Nl, nb_symb_sch,nb_rb); if ((harq_process->R)<1024) Coderate = (float) (harq_process->R) /(float) 1024; @@ -1571,12 +1574,12 @@ void nr_dlsch_decoding_process(void *arg) ret = 2; } else { - LOG_I(PHY,"Segment %u CRC NOK\n",r); + LOG_D(PHY,"Segment %u CRC NOK\n",r); ret = 1+dlsch->max_ldpc_iterations; } if (no_iteration_ldpc > 10) - LOG_I(PHY,"Error number of iteration LPDC %d\n", no_iteration_ldpc); + LOG_D(PHY,"Error number of iteration LPDC %d\n", no_iteration_ldpc); for (int m=0; m < Kr>>3; m ++) diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 7b33b2040fe33a503e90c60736d834d39d7a7cd8..b7923adb0b2098734ab79623bb9cc997e6a777a0 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -94,8 +94,6 @@ typedef struct { uint32_t frame; /// Subframe where current HARQ round was sent uint32_t subframe; - /// Index of current HARQ round for this DLSCH - uint8_t round; /// MIMO mode for this DLSCH MIMO_mode_t mimo_mode; /// Concatenated sequences @@ -138,8 +136,8 @@ typedef struct { } NR_gNB_SCH_STATS_t; typedef struct { - /// Pointers to 16 HARQ processes for the DLSCH - NR_DL_gNB_HARQ_t *harq_processes[NR_MAX_NB_HARQ_PROCESSES]; + /// Pointers to variables related to DLSCH harq process + NR_DL_gNB_HARQ_t harq_process; /// TX buffers for UE-spec transmission (antenna ports 5 or 7..14, prior to precoding) int32_t *txdataF[NR_MAX_NB_LAYERS]; /// Modulated symbols buffer @@ -834,6 +832,7 @@ typedef struct PHY_VARS_gNB_s { notifiedFIFO_t *respDecode; tpool_t *threadPool; int nbDecode; + uint8_t pusch_proc_threads; } PHY_VARS_gNB; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index d67d7c8efa02be11241f17a87061342dc715c088..c648810bcef8cbed003d4880ce9f9f40944651ee 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -201,10 +201,10 @@ void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB, VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DLSCH,1); LOG_D(PHY, "PDSCH generation started (%d) in frame %d.%d\n", gNB->num_pdsch_rnti[slot],frame,slot); nr_generate_pdsch(gNB,frame, slot); - if ((frame&127) == 0) dump_pdsch_stats(gNB); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DLSCH,0); } + if ((frame&127) == 0) dump_pdsch_stats(gNB); //apply the OFDM symbol rotation here apply_nr_rotation(fp,(int16_t*) &gNB->common_vars.txdataF[0][txdataF_offset],slot,0,fp->Ncp==EXTENDED?12:14,fp->ofdm_symbol_size); diff --git a/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c b/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c index b1fd2a4df805f4e820a712e185a136307f56b2f4..edb070f8735c479614fc10bb1362501e078976d1 100644 --- a/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c +++ b/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c @@ -780,19 +780,15 @@ uint8_t get_downlink_ack(PHY_VARS_NR_UE *ue, uint8_t gNB_id, UE_nr_rxtx_proc_t 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); + LOG_D(PHY,"PUCCH Downlink ack can not be transmitted : at line %d in function %s of file %s \n", LINE_FILE , __func__, FILE_NAME); } else { @@ -808,6 +804,8 @@ uint8_t get_downlink_ack(PHY_VARS_NR_UE *ue, uint8_t gNB_id, UE_nr_rxtx_proc_t number_harq_feedback++; ack_data[code_word][dai_current - 1] = harq_status->ack; dai[code_word][dai_current - 1] = dai_current; + harq_status->slot_for_feedback_ack = NR_MAX_SLOTS_PER_FRAME; + harq_status->send_harq_status = 0; } if (do_reset == TRUE) { init_downlink_harq_status(ue->dlsch[thread_idx][gNB_id][code_word]->harq_processes[dl_harq_pid]); diff --git a/openair1/SIMULATION/NR_PHY/dlschsim.c b/openair1/SIMULATION/NR_PHY/dlschsim.c index c60bc8dd9f3237adb9c207325bb4fdaab8844e0d..061866b12c08f8140e74c2227a484b1fc10cf0d6 100644 --- a/openair1/SIMULATION/NR_PHY/dlschsim.c +++ b/openair1/SIMULATION/NR_PHY/dlschsim.c @@ -427,7 +427,7 @@ int main(int argc, char **argv) UE->dlsch_ra[0] = new_nr_ue_dlsch(1, 1, Nsoft, 5, N_RB_DL, 0); unsigned char harq_pid = 0; //dlsch->harq_ids[subframe]; NR_gNB_DLSCH_t *dlsch = gNB->dlsch[0][0]; - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->harq_processes[harq_pid]->pdsch_pdu.pdsch_pdu_rel15; + nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->harq_process.pdsch_pdu.pdsch_pdu_rel15; //time_stats_t *rm_stats, *te_stats, *i_stats; uint8_t is_crnti = 0, llr8_flag = 0; unsigned int TBS = 8424; @@ -519,7 +519,7 @@ int main(int argc, char **argv) //if (i<16) // printf("encoder output f[%d] = %d\n",i,dlsch->harq_processes[0]->f[i]); - if (dlsch->harq_processes[0]->f[i] == 0) + if (dlsch->harq_process.f[i] == 0) modulated_input[i] = 1.0; ///sqrt(2); //QPSK else modulated_input[i] = -1.0; ///sqrt(2); @@ -547,7 +547,7 @@ int main(int argc, char **argv) else channel_output_uncoded[i] = 0; - if (channel_output_uncoded[i] != dlsch->harq_processes[harq_pid]->f[i]) + if (channel_output_uncoded[i] != dlsch->harq_process.f[i]) errors_bit_uncoded = errors_bit_uncoded + 1; } diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index d8eb8849a31ee6aeff50670f21cee8f556cc00ae..9581038283f993ce18d738ed7f84d1eef344c9f6 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -186,8 +186,7 @@ void update_dmrs_config(NR_CellGroupConfig_t *scg,PHY_VARS_NR_UE *ue, int8_t* dm int g_mcsIndex = -1, g_mcsTableIdx = 0, g_rbStart = -1, g_rbSize = -1; void nr_dlsim_preprocessor(module_id_t module_id, frame_t frame, - sub_frame_t slot, - int num_slots_per_tdd) { + sub_frame_t slot) { NR_UE_info_t *UE_info = &RC.nrmac[module_id]->UE_info; AssertFatal(UE_info->num_UEs == 1, "can have only a single UE\n"); NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[0]; @@ -203,15 +202,25 @@ void nr_dlsim_preprocessor(module_id_t module_id, sched_ctrl->active_bwp, sched_ctrl->search_space, 1 /* dedicated */); sched_ctrl->cce_index = 0; - /* set "any" value for PUCCH (simulator evaluates PDSCH only) */ - sched_ctrl->pucch_sched_idx = 0; - sched_ctrl->pucch_occ_idx = 0; - sched_ctrl->rbStart = g_rbStart; sched_ctrl->rbSize = g_rbSize; sched_ctrl->mcs = g_mcsIndex; sched_ctrl->time_domain_allocation = 2; sched_ctrl->mcsTableIdx = g_mcsTableIdx; + /* the simulator assumes the HARQ PID is equal to the slot number */ + sched_ctrl->dl_harq_pid = slot; + /* The scheduler uses lists to track whether a HARQ process is + * free/busy/awaiting retransmission, and updates the HARQ process states. + * However, in the simulation, we never get ack or nack for any HARQ process, + * thus the list and HARQ states don't match what the scheduler expects. + * Therefore, below lines just "repair" everything so that the scheduler + * won't remark that there is no HARQ feedback */ + sched_ctrl->feedback_dl_harq.head = -1; // always overwrite feedback HARQ process + if (sched_ctrl->harq_processes[slot].round == 0) // depending on round set in simulation ... + add_front_nr_list(&sched_ctrl->available_dl_harq, slot); // ... make PID available + else + add_front_nr_list(&sched_ctrl->retrans_dl_harq, slot); // ... make PID retransmission + sched_ctrl->harq_processes[slot].is_waiting = false; AssertFatal(sched_ctrl->rbStart >= 0, "invalid rbStart %d\n", sched_ctrl->rbStart); AssertFatal(sched_ctrl->rbSize > 0, "invalid rbSize %d\n", sched_ctrl->rbSize); AssertFatal(sched_ctrl->mcs >= 0, "invalid sched_ctrl->mcs %d\n", sched_ctrl->mcs); @@ -671,6 +680,9 @@ int main(int argc, char **argv) rrc_mac_config_req_gNB(0,0,1,pusch_tgt_snrx10,pucch_tgt_snrx10,NULL,1,secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup); phy_init_nr_gNB(gNB,0,0); N_RB_DL = gNB->frame_parms.N_RB_DL; + NR_UE_info_t *UE_info = &RC.nrmac[0]->UE_info; + UE_info->num_UEs=1; + // stub to configure frame_parms // nr_phy_config_request_sim(gNB,N_RB_DL,N_RB_DL,mu,Nid_cell,SSB_positions); // call MAC to configure common parameters @@ -836,10 +848,10 @@ int main(int argc, char **argv) scheduled_response.thread_id = UE_proc.thread_id; nr_ue_phy_config_request(&UE_mac->phy_config); - NR_UE_info_t *UE_info = &RC.nrmac[0]->UE_info; //NR_COMMON_channels_t *cc = RC.nrmac[0]->common_channels; snrRun = 0; + for (SNR = snr0; SNR < snr1; SNR += .2) { varArray_t *table_tx=initVarArray(1000,sizeof(double)); @@ -885,7 +897,7 @@ int main(int argc, char **argv) NR_DL_UE_HARQ_t *UE_harq_process = dlsch0->harq_processes[harq_pid]; NR_gNB_DLSCH_t *gNB_dlsch = gNB->dlsch[0][0]; - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &gNB_dlsch->harq_processes[slot]->pdsch_pdu.pdsch_pdu_rel15; + nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &gNB_dlsch->harq_process.pdsch_pdu.pdsch_pdu_rel15; UE_harq_process->harq_ack.ack = 0; round = 0; @@ -901,15 +913,11 @@ int main(int argc, char **argv) UE_info->UE_sched_ctrl[0].harq_processes[harq_pid].round = round; - gNB->dlsch[0][0]->harq_processes[harq_pid]->round = round; for (int i=0; i<MAX_NUM_CORESET; i++) gNB_mac->UE_info.num_pdcch_cand[0][i] = 0; if (css_flag == 0) { - const uint8_t slots_per_frame[5] = {10, 20, 40, 80, 160}; - const NR_TDD_UL_DL_Pattern_t *tdd_pattern = &scc->tdd_UL_DL_ConfigurationCommon->pattern1; - const int num_slots_per_tdd = slots_per_frame[*scc->ssbSubcarrierSpacing] >> (7 - tdd_pattern->dl_UL_TransmissionPeriodicity); - nr_schedule_ue_spec(0, frame, slot, num_slots_per_tdd); + nr_schedule_ue_spec(0, frame, slot); } else { nr_schedule_css_dlsch_phytest(0,frame,slot); } @@ -1053,8 +1061,8 @@ int main(int argc, char **argv) for (i = 0; i < available_bits; i++) { - if(((gNB_dlsch->harq_processes[harq_pid]->f[i] == 0) && (UE_llr[i] <= 0)) || - ((gNB_dlsch->harq_processes[harq_pid]->f[i] == 1) && (UE_llr[i] >= 0))) + if(((gNB_dlsch->harq_process.f[i] == 0) && (UE_llr[i] <= 0)) || + ((gNB_dlsch->harq_process.f[i] == 1) && (UE_llr[i] >= 0))) { if(errors_scrambling == 0) { LOG_D(PHY,"\n"); @@ -1067,7 +1075,7 @@ int main(int argc, char **argv) for (i = 0; i < TBS; i++) { estimated_output_bit[i] = (UE_harq_process->b[i/8] & (1 << (i & 7))) >> (i & 7); - test_input_bit[i] = (gNB_dlsch->harq_processes[harq_pid]->b[i / 8] & (1 << (i & 7))) >> (i & 7); // Further correct for multiple segments + test_input_bit[i] = (gNB_dlsch->harq_process.b[i / 8] & (1 << (i & 7))) >> (i & 7); // Further correct for multiple segments if (estimated_output_bit[i] != test_input_bit[i]) { if(errors_bit == 0) @@ -1107,9 +1115,9 @@ int main(int argc, char **argv) if (print_perf==1) { printf("\ngNB TX function statistics (per %d us slot, NPRB %d, mcs %d, TBS %d, Kr %d (Zc %d))\n", 1000>>*scc->ssbSubcarrierSpacing, g_rbSize, g_mcsIndex, - gNB->dlsch[0][0]->harq_processes[0]->pdsch_pdu.pdsch_pdu_rel15.TBSize[0]<<3, - gNB->dlsch[0][0]->harq_processes[0]->K, - gNB->dlsch[0][0]->harq_processes[0]->K/((gNB->dlsch[0][0]->harq_processes[0]->pdsch_pdu.pdsch_pdu_rel15.TBSize[0]<<3)>3824?22:10)); + gNB->dlsch[0][0]->harq_process.pdsch_pdu.pdsch_pdu_rel15.TBSize[0]<<3, + gNB->dlsch[0][0]->harq_process.K, + gNB->dlsch[0][0]->harq_process.K/((gNB->dlsch[0][0]->harq_process.pdsch_pdu.pdsch_pdu_rel15.TBSize[0]<<3)>3824?22:10)); printDistribution(&gNB->phy_proc_tx,table_tx,"PHY proc tx"); printStatIndent2(&gNB->dlsch_encoding_stats,"DLSCH encoding time"); printStatIndent3(&gNB->dlsch_segmentation_stats,"DLSCH segmentation time"); diff --git a/openair2/GNB_APP/L1_nr_paramdef.h b/openair2/GNB_APP/L1_nr_paramdef.h index a5a808c2811ad21684cabbedb572ea03fc810518..67be560778b9848ffe29e254d75f788988b06be6 100644 --- a/openair2/GNB_APP/L1_nr_paramdef.h +++ b/openair2/GNB_APP/L1_nr_paramdef.h @@ -46,6 +46,7 @@ #define CONFIG_STRING_L1_LOCAL_N_PORTD "local_n_portd" #define CONFIG_STRING_L1_REMOTE_N_PORTD "remote_n_portd" #define CONFIG_STRING_L1_TRANSPORT_N_PREFERENCE "tr_n_preference" +#define CONFIG_STRING_L1_PUSCH_PROC_THREADS "pusch_proc_threads" /*----------------------------------------------------------------------------------------------------------------------------------------------------*/ /* L1 configuration parameters */ @@ -61,6 +62,7 @@ {CONFIG_STRING_L1_REMOTE_N_PORTC, NULL, 0, uptr:NULL, defintval:50030, TYPE_UINT, 0}, \ {CONFIG_STRING_L1_LOCAL_N_PORTD, NULL, 0, uptr:NULL, defintval:50031, TYPE_UINT, 0}, \ {CONFIG_STRING_L1_REMOTE_N_PORTD, NULL, 0, uptr:NULL, defintval:50031, TYPE_UINT, 0}, \ +{CONFIG_STRING_L1_PUSCH_PROC_THREADS, NULL, 0, uptr:NULL, defintval:1, TYPE_UINT, 0} \ } #define L1_CC_IDX 0 #define L1_TRANSPORT_N_PREFERENCE_IDX 1 @@ -71,6 +73,7 @@ #define L1_REMOTE_N_PORTC_IDX 6 #define L1_LOCAL_N_PORTD_IDX 7 #define L1_REMOTE_N_PORTD_IDX 8 +#define L1_PUSCH_PROC_THREADS 9 /*----------------------------------------------------------------------------------------------------------------------------------------------------*/ #endif diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index d830e51f4da0abfe3623f9ab18480fbf79a17f4f..0c056d27b6a4e0d5a4daada9e3e1021b4ad660cf 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -51,7 +51,8 @@ #include "nfapi_vnf.h" #include "nfapi_pnf.h" -#include "L1_paramdef.h" +//#include "L1_paramdef.h" +#include "L1_nr_paramdef.h" #include "MACRLC_paramdef.h" #include "common/config/config_userapi.h" //#include "RRC_config_tools.h" @@ -399,6 +400,8 @@ void RCconfig_NR_L1(void) { RC.gNB[j]->Mod_id = j; } + RC.gNB[j]->pusch_proc_threads = *(L1_ParamList.paramarray[j][L1_PUSCH_PROC_THREADS].uptr); + if(strcmp(*(L1_ParamList.paramarray[j][L1_TRANSPORT_N_PREFERENCE_IDX].strptr), "local_mac") == 0) { //sf_ahead = 2; // Need 4 subframe gap between RX and TX }else if (strcmp(*(L1_ParamList.paramarray[j][L1_TRANSPORT_N_PREFERENCE_IDX].strptr), "nfapi") == 0) { diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index 981f2ba193d726934ea45921ccefac80f6a71b1a..f1fe0c97c9128be73e3758fe0e0eacfcac73eeb2 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -82,7 +82,6 @@ typedef enum { /* global parameters, not under a specific section */ #define GNB_CONFIG_STRING_ASN1_VERBOSITY "Asn1_verbosity" #define GNB_CONFIG_STRING_ACTIVE_GNBS "Active_gNBs" -#define GNB_CONFIG_PUSCH_THREADS "Num_Threads_PUSCH" /*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/ /* global configuration parameters */ /* optname helpstr paramflags XXXptr defXXXval type numelt */ @@ -92,10 +91,6 @@ typedef enum { {GNB_CONFIG_STRING_ACTIVE_GNBS, NULL, 0, uptr:NULL, defstrval:NULL, TYPE_STRINGLIST, 0} \ } -#define NUM_THREADS_DESC { \ -{GNB_CONFIG_PUSCH_THREADS, NULL, 0, uptr:&num_threads_pusch, defuintval:1, TYPE_UINT, 0} \ -} - #define GNB_ASN1_VERBOSITY_IDX 0 #define GNB_ACTIVE_GNBS_IDX 1 diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h index 1c8c510ec6b96d2aa0b7e0c797403241e6510804..381dce11b2cddce03c9633c17add5dc24d3ad7e6 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h @@ -119,22 +119,22 @@ typedef NR_BSR_SHORT NR_BSR_SHORT_TRUNCATED; // Long BSR for all logical channel group ID typedef struct { - uint8_t Buffer_size7: 8; - uint8_t Buffer_size6: 8; - uint8_t Buffer_size5: 8; - uint8_t Buffer_size4: 8; - uint8_t Buffer_size3: 8; - uint8_t Buffer_size2: 8; - uint8_t Buffer_size1: 8; - uint8_t Buffer_size0: 8; - uint8_t LcgID0: 1; - uint8_t LcgID1: 1; - uint8_t LcgID2: 1; - uint8_t LcgID3: 1; - uint8_t LcgID4: 1; - uint8_t LcgID5: 1; - uint8_t LcgID6: 1; - uint8_t LcgID7: 1; + uint8_t LcgID0: 1; // octet 1 [0] + uint8_t LcgID1: 1; // octet 1 [1] + uint8_t LcgID2: 1; // octet 1 [2] + uint8_t LcgID3: 1; // octet 1 [3] + uint8_t LcgID4: 1; // octet 1 [4] + uint8_t LcgID5: 1; // octet 1 [5] + uint8_t LcgID6: 1; // octet 1 [6] + uint8_t LcgID7: 1; // octet 1 [7] + uint8_t Buffer_size0: 8; // octet 2 [7:0] + uint8_t Buffer_size1: 8; // octet 3 [7:0] + uint8_t Buffer_size2: 8; // octet 4 [7:0] + uint8_t Buffer_size3: 8; // octet 5 [7:0] + uint8_t Buffer_size4: 8; // octet 6 [7:0] + uint8_t Buffer_size5: 8; // octet 7 [7:0] + uint8_t Buffer_size6: 8; // octet 8 [7:0] + uint8_t Buffer_size7: 8; // octet 9 [7:0] } __attribute__ ((__packed__)) NR_BSR_LONG; typedef NR_BSR_LONG NR_BSR_LONG_TRUNCATED; diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index c8bba7907a3b3e3534ab0aa8b1bef2e54bf69d5f..8dc261df1da1efacbd340ea239777a5be74a1670 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -2382,9 +2382,9 @@ uint8_t get_K_ptrs(uint16_t nrb0, uint16_t nrb1, uint16_t N_RB) { // Set the transform precoding status according to 6.1.3 of 3GPP TS 38.214 version 16.3.0 Release 16: // - "UE procedure for applying transform precoding on PUSCH" -uint8_t get_transformPrecoding(NR_ServingCellConfigCommon_t *scc, - NR_PUSCH_Config_t *pusch_config, - NR_BWP_Uplink_t *ubwp, +uint8_t get_transformPrecoding(const NR_ServingCellConfigCommon_t *scc, + const NR_PUSCH_Config_t *pusch_config, + const NR_BWP_Uplink_t *ubwp, uint8_t *dci_format, int rnti_type, uint8_t configuredGrant){ @@ -2416,8 +2416,8 @@ uint8_t get_transformPrecoding(NR_ServingCellConfigCommon_t *scc, return -1; } -uint16_t nr_dci_size(NR_ServingCellConfigCommon_t *scc, - NR_CellGroupConfig_t *secondaryCellGroup, +uint16_t nr_dci_size(const NR_ServingCellConfigCommon_t *scc, + const NR_CellGroupConfig_t *secondaryCellGroup, dci_pdu_rel15_t *dci_pdu, nr_dci_format_t format, nr_rnti_type_t rnti_type, diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h index 7534035cdc09918b25e763fef94a196936dfb933..58ecd54733244486b1e3ba726b7e718fd74ed50c 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h @@ -53,8 +53,8 @@ int is_nr_DL_slot(NR_ServingCellConfigCommon_t *scc,slot_t slotP); int is_nr_UL_slot(NR_ServingCellConfigCommon_t *scc,slot_t slotP); -uint16_t nr_dci_size(NR_ServingCellConfigCommon_t *scc, - NR_CellGroupConfig_t *secondaryCellGroup, +uint16_t nr_dci_size(const NR_ServingCellConfigCommon_t *scc, + const NR_CellGroupConfig_t *secondaryCellGroup, dci_pdu_rel15_t *dci_pdu, nr_dci_format_t format, nr_rnti_type_t rnti_type, @@ -150,9 +150,9 @@ uint8_t get_num_dmrs_symbols(NR_PDSCH_Config_t *pdsch_Config,int dmrs_TypeA_Posi @param rnti_type rnti type @param configuredGrant indicates whether a configured grant was received or not @returns transformPrecoding value */ -uint8_t get_transformPrecoding(NR_ServingCellConfigCommon_t *scc, - NR_PUSCH_Config_t *pusch_config, - NR_BWP_Uplink_t *ubwp, +uint8_t get_transformPrecoding(const NR_ServingCellConfigCommon_t *scc, + const NR_PUSCH_Config_t *pusch_config, + const NR_BWP_Uplink_t *ubwp, uint8_t *dci_format, int rnti_type, uint8_t configuredGrant); diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index 2565c8e73c3446e40a6e94a6d16e3da93e3d2837..f6bd5436bc239fd132054f066ba9e762be47058d 100755 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -82,6 +82,7 @@ int set_tdd_config_nr_ue(fapi_nr_config_request_t *cfg, } int nb_slots_per_period = ((1<<mu) * NR_NUMBER_OF_SUBFRAMES_PER_FRAME)/nb_periods_per_frame; + cfg->tdd_table.tdd_period_in_slots = nb_slots_per_period; if ( (nrofDownlinkSymbols + nrofUplinkSymbols) == 0 ) AssertFatal(nb_slots_per_period == (nrofDownlinkSlots + nrofUplinkSlots), diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index 3bd9f021c86b7ec605d0b01c468ebce2414c3246..dd0aa15c52a0c40b3236db207d70ddcb424faa1e 100755 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -350,6 +350,8 @@ typedef struct { RA_config_t ra; /// SSB index from MIB decoding uint8_t mib_ssb; + /// Last NDI of UL HARQ processes + uint8_t UL_ndi[NR_MAX_HARQ_PROCESSES]; //// FAPI-like interface message fapi_nr_ul_config_request_t *ul_config_request; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 8a329f52694d880d5f081d19d438a8cfa8619cdf..64067e9d60df8b978b2885bf04c2bc7cb3468de5 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -2046,7 +2046,7 @@ uint16_t nr_generate_ulsch_pdu(uint8_t *sdus_payload, if (crnti) { // MAC CE fixed subheader mac_pdu_ptr->R = 0; - mac_pdu_ptr->LCID = CRNTI; + mac_pdu_ptr->LCID = UL_SCH_LCID_C_RNTI; mac_pdu_ptr++; // C-RNTI MAC CE (2 octets) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 0a6af58dee912181a2c8abc1e26afc4da8103e1a..d6e1cba6df103f133a755501b0fb9258c0f12d05 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -889,7 +889,8 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in uint16_t TBS_bytes = ulcfg_pdu->pusch_config_pdu.pusch_data.tb_size; - if (IS_SOFTMODEM_NOS1){ + // Push data from MAC to PHY only when NDI toggles + if (IS_SOFTMODEM_NOS1 && (mac->UL_ndi[ulcfg_pdu->pusch_config_pdu.pusch_data.harq_process_id] != ulcfg_pdu->pusch_config_pdu.pusch_data.new_data_indicator)){ // Getting IP traffic to be transmitted data_existing = nr_ue_get_sdu(mod_id, cc_id, @@ -901,6 +902,7 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in &access_mode); } + mac->UL_ndi[ulcfg_pdu->pusch_config_pdu.pusch_data.harq_process_id] = ulcfg_pdu->pusch_config_pdu.pusch_data.new_data_indicator; //Random traffic to be transmitted if there is no IP traffic available for this Tx opportunity if (!IS_SOFTMODEM_NOS1 || !data_existing) { //Use zeros for the header bytes in noS1 mode, in order to make sure that the LCID is not valid diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index bd6a8f3384186e0cbef47c1c24999c13c0b19db0..6aa906b82b196b48f34be24f501a542744d4bbac 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -346,10 +346,18 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, } RC.nrmac[Mod_idP]->common_channels[0].vrb_map_UL = - calloc(n * 275, sizeof(uint16_t)); + calloc(n * MAX_BWP_SIZE, sizeof(uint16_t)); AssertFatal(RC.nrmac[Mod_idP]->common_channels[0].vrb_map_UL, "could not allocate memory for RC.nrmac[]->common_channels[0].vrb_map_UL\n"); + for (int i = 0; i < MAX_NUM_BWP; ++i) { + RC.nrmac[Mod_idP]->pucch_index_used[i] = + calloc(n, sizeof(*RC.nrmac[Mod_idP]->pucch_index_used)); + AssertFatal(RC.nrmac[Mod_idP]->pucch_index_used[i], + "could not allocate memory for RC.nrmac[]->pucch_index_used[%d]\n", + i); + } + LOG_I(MAC,"Configuring common parameters from NR ServingCellConfig\n"); config_common(Mod_idP, @@ -389,22 +397,7 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP, NR_UE_info_t *UE_info = &RC.nrmac[Mod_idP]->UE_info; if (add_ue == 1 && get_softmodem_params()->phy_test) { - const int UE_id = add_new_nr_ue(Mod_idP,rnti); - UE_info->secondaryCellGroup[UE_id] = secondaryCellGroup; - compute_csi_bitlen (secondaryCellGroup, UE_info, UE_id); - struct NR_ServingCellConfig__downlinkBWP_ToAddModList *bwpList = - secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList; - AssertFatal(bwpList->list.count == 1, - "downlinkBWP_ToAddModList has %d BWP!\n", - bwpList->list.count); - const int bwp_id = 1; - UE_info->UE_sched_ctrl[UE_id].active_bwp = bwpList->list.array[bwp_id - 1]; - struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList = - secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList; - AssertFatal(ubwpList->list.count == 1, - "uplinkBWP_ToAddModList has %d BWP!\n", - ubwpList->list.count); - UE_info->UE_sched_ctrl[UE_id].active_ubwp = ubwpList->list.array[bwp_id - 1]; + const int UE_id = add_new_nr_ue(Mod_idP, rnti, secondaryCellGroup); LOG_I(PHY,"Added new UE_id %d/%x with initial secondaryCellGroup\n",UE_id,rnti); } else if (add_ue == 1 && !get_softmodem_params()->phy_test) { /* TODO: should check for free RA process */ diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index 18be96fee89cbd76980375229c8555ac56b24b75..d5dbbe5ddfcae5b78d80114b916a134ae8ce152c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -59,24 +59,31 @@ void clear_mac_stats(gNB_MAC_INST *gNB) { memset((void*)gNB->UE_info.mac_stats,0,MAX_MOBILES_PER_GNB*sizeof(NR_mac_stats_t)); } -void dump_mac_stats(gNB_MAC_INST *gNB) { - +void dump_mac_stats(gNB_MAC_INST *gNB) +{ NR_UE_info_t *UE_info = &gNB->UE_info; - NR_mac_stats_t *stats; - int lc_id; - - for (int UE_id=0;UE_id<MAX_MOBILES_PER_GNB;UE_id++) { - if (UE_info->active[UE_id]) { - LOG_I(MAC, "UE %x\n", UE_info->rnti[UE_id]); - stats = &UE_info->mac_stats[UE_id]; - LOG_I(MAC,"dlsch_rounds %d/%d/%d/%d, dlsch_errors %d\n",stats->dlsch_rounds[0],stats->dlsch_rounds[1],stats->dlsch_rounds[2],stats->dlsch_rounds[3],stats->dlsch_errors); - LOG_I(MAC,"dlsch_total_bytes %d\n",stats->dlsch_total_bytes); - LOG_I(MAC,"ulsch_rounds %d/%d/%d/%d, ulsch_errors %d\n",stats->ulsch_rounds[0],stats->ulsch_rounds[1],stats->ulsch_rounds[2],stats->ulsch_rounds[3],stats->ulsch_errors); - LOG_I(MAC,"ulsch_total_bytes_scheduled %d, ulsch_total_bytes_received %d\n",stats->ulsch_total_bytes_scheduled,stats->ulsch_total_bytes_rx); - for (lc_id=0;lc_id<63;lc_id++) { - if (stats->lc_bytes_tx[lc_id]>0) LOG_I(MAC,"LCID %d : %d bytes TX\n",lc_id,stats->lc_bytes_tx[lc_id]); - if (stats->lc_bytes_rx[lc_id]>0) LOG_I(MAC,"LCID %d : %d bytes RX\n",lc_id,stats->lc_bytes_rx[lc_id]); - } + int num = 1; + for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) { + LOG_I(MAC, "UE ID %d RNTI %04x (%d/%d)\n", UE_id, UE_info->rnti[UE_id], num++, UE_info->num_UEs); + const NR_mac_stats_t *stats = &UE_info->mac_stats[UE_id]; + LOG_I(MAC, "UE %d: dlsch_rounds %d/%d/%d/%d, dlsch_errors %d\n", + UE_id, + stats->dlsch_rounds[0], stats->dlsch_rounds[1], + stats->dlsch_rounds[2], stats->dlsch_rounds[3], stats->dlsch_errors); + LOG_I(MAC, "UE %d: dlsch_total_bytes %d\n", UE_id, stats->dlsch_total_bytes); + LOG_I(MAC, "UE %d: ulsch_rounds %d/%d/%d/%d, ulsch_errors %d\n", + UE_id, + stats->ulsch_rounds[0], stats->ulsch_rounds[1], + stats->ulsch_rounds[2], stats->ulsch_rounds[3], stats->ulsch_errors); + LOG_I(MAC, + "UE %d: ulsch_total_bytes_scheduled %d, ulsch_total_bytes_received %d\n", + UE_id, + stats->ulsch_total_bytes_scheduled, stats->ulsch_total_bytes_rx); + for (int lc_id = 0; lc_id < 63; lc_id++) { + if (stats->lc_bytes_tx[lc_id] > 0) + LOG_I(MAC, "UE %d: LCID %d: %d bytes TX\n", UE_id, lc_id, stats->lc_bytes_tx[lc_id]); + if (stats->lc_bytes_rx[lc_id] > 0) + LOG_I(MAC, "UE %d: LCID %d: %d bytes RX\n", UE_id, lc_id, stats->lc_bytes_rx[lc_id]); } } } @@ -89,6 +96,7 @@ void clear_nr_nfapi_information(gNB_MAC_INST * gNB, const int num_slots = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; nfapi_nr_dl_tti_request_t *DL_req = &gNB->DL_req[0]; + nfapi_nr_dl_tti_pdcch_pdu_rel15_t ***pdcch = (nfapi_nr_dl_tti_pdcch_pdu_rel15_t ***)gNB->pdcch_pdu_idx[CC_idP]; nfapi_nr_ul_tti_request_t *future_ul_tti_req = &gNB->UL_tti_req_ahead[CC_idP][(slotP + num_slots - 1) % num_slots]; nfapi_nr_ul_dci_request_t *UL_dci_req = &gNB->UL_dci_req[0]; @@ -103,6 +111,7 @@ void clear_nr_nfapi_information(gNB_MAC_INST * gNB, DL_req[CC_idP].dl_tti_request_body.nPDUs = 0; DL_req[CC_idP].dl_tti_request_body.nGroup = 0; //DL_req[CC_idP].dl_tti_request_body.transmission_power_pcfich = 6000; + memset(pdcch, 0, sizeof(**pdcch) * MAX_NUM_BWP * MAX_NUM_CORESET); UL_dci_req[CC_idP].SFN = frameP; UL_dci_req[CC_idP].Slot = slotP; @@ -299,11 +308,9 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, int nb_periods_per_frame; - const int UE_id = 0; const int bwp_id = 1; gNB_MAC_INST *gNB = RC.nrmac[module_idP]; - NR_UE_info_t *UE_info = &gNB->UE_info; NR_COMMON_channels_t *cc = gNB->common_channels; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; NR_TDD_UL_DL_Pattern_t *tdd_pattern = &scc->tdd_UL_DL_ConfigurationCommon->pattern1; @@ -360,23 +367,27 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, nr_rrc_trigger(&ctxt, 0 /*CC_id*/, frame, slot >> *scc->ssbSubcarrierSpacing); } - const uint64_t dlsch_in_slot_bitmap = (1 << 1) | (1 << 3); - const uint64_t ulsch_in_slot_bitmap = (1 << 8); +#define BIT(x) (1 << (x)) + const uint64_t dlsch_in_slot_bitmap = BIT( 1) | BIT( 2) | BIT( 3) | BIT( 4) | BIT( 5) | BIT( 6) + | BIT(11) | BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16); + const uint64_t ulsch_in_slot_bitmap = BIT( 8) | BIT(18); memset(RC.nrmac[module_idP]->cce_list[bwp_id][0],0,MAX_NUM_CCE*sizeof(int)); // coreset0 memset(RC.nrmac[module_idP]->cce_list[bwp_id][1],0,MAX_NUM_CCE*sizeof(int)); // coresetid 1 - for (int i=0; i<MAX_NUM_CORESET; i++) - RC.nrmac[module_idP]->UE_info.num_pdcch_cand[UE_id][i] = 0; + NR_UE_info_t *UE_info = &RC.nrmac[module_idP]->UE_info; + for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) + for (int i=0; i<MAX_NUM_CORESET; i++) + UE_info->num_pdcch_cand[UE_id][i] = 0; for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { //mbsfn_status[CC_id] = 0; // clear vrb_maps - memset(cc[CC_id].vrb_map, 0, sizeof(uint16_t) * 275); + memset(cc[CC_id].vrb_map, 0, sizeof(uint16_t) * MAX_BWP_SIZE); // clear last scheduled slot's content (only)! const int num_slots = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; const int last_slot = (slot + num_slots - 1) % num_slots; uint16_t *vrb_map_UL = cc[CC_id].vrb_map_UL; - memset(&vrb_map_UL[last_slot * 275], 0, sizeof(uint16_t) * 275); + memset(&vrb_map_UL[last_slot * MAX_BWP_SIZE], 0, sizeof(uint16_t) * MAX_BWP_SIZE); clear_nr_nfapi_information(RC.nrmac[module_idP], CC_id, frame, slot); } @@ -410,9 +421,9 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, // This schedule SR // TODO - // This schedule CSI measurement reporting - if (UE_info->active[UE_id]) - nr_csi_meas_reporting(module_idP, UE_id, frame, slot, num_slots_per_tdd, nr_ulmix_slots, nr_slots_per_frame[*scc->ssbSubcarrierSpacing]); + // Schedule CSI measurement reporting: check in slot 0 for the whole frame + if (slot == 0) + nr_csi_meas_reporting(module_idP, frame, slot); // This schedule RA procedure if not in phy_test mode // Otherwise already consider 5G already connected @@ -421,19 +432,16 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, } // This schedules the DCI for Uplink and subsequently PUSCH - if (slot < 10) { + { nr_schedule_ulsch(module_idP, frame, slot, num_slots_per_tdd, nr_ulmix_slots, ulsch_in_slot_bitmap); } // This schedules the DCI for Downlink and PDSCH - if (is_xlsch_in_slot(dlsch_in_slot_bitmap, slot % num_slots_per_tdd) - && slot < 10) { - nr_schedule_ue_spec(module_idP, frame, slot, num_slots_per_tdd); - } + if (is_xlsch_in_slot(dlsch_in_slot_bitmap, slot)) + nr_schedule_ue_spec(module_idP, frame, slot); - if (UE_info->active[UE_id]) - nr_schedule_pucch(module_idP, UE_id, nr_ulmix_slots, frame, slot); + nr_schedule_pucch(module_idP, frame, slot); stop_meas(&RC.nrmac[module_idP]->eNB_scheduler); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 09eff5c056ab8cd2a17482e548c18df89e35b2e7..b914e80d23bc04ebd13e8ba268bc9df1dc9633b2 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -645,7 +645,7 @@ void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t } uint16_t *vrb_map_UL = - &RC.nrmac[module_idP]->common_channels[CC_id].vrb_map_UL[ra->Msg3_slot * 275]; + &RC.nrmac[module_idP]->common_channels[CC_id].vrb_map_UL[ra->Msg3_slot * MAX_BWP_SIZE]; for (int i = 0; i < ra->msg3_nb_rb; ++i) { AssertFatal(!vrb_map_UL[i + ra->msg3_first_rb], "RB %d in %4d.%2d is already taken, cannot allocate Msg3!\n", @@ -766,7 +766,7 @@ void nr_generate_Msg2(module_id_t module_idP, sub_frame_t slotP) { - int dci_formats[2], rnti_types[2], mcsIndex; + int mcsIndex; int startSymbolAndLength = 0, StartSymbolIndex = -1, NrOfSymbols = 14, StartSymbolIndex_tmp, NrOfSymbols_tmp, x_Overhead, time_domain_assignment = 0; gNB_MAC_INST *nr_mac = RC.nrmac[module_idP]; NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id]; @@ -793,27 +793,55 @@ void nr_generate_Msg2(module_id_t module_idP, if ((ra->Msg2_frame == frameP) && (ra->Msg2_slot == slotP)) { nfapi_nr_dl_tti_request_body_t *dl_req = &nr_mac->DL_req[CC_id].dl_tti_request_body; + // Checking if the DCI allocation is feasible in current subframe + if (dl_req->nPDUs > NFAPI_NR_MAX_DL_TTI_PDUS - 2) { + LOG_I(MAC, "[RAPROC] Subframe %d: FAPI DL structure is full, skip scheduling UE %d\n", slotP, RA_rnti); + return; + } + + uint8_t nr_of_candidates, aggregation_level; + find_aggregation_candidates(&aggregation_level, &nr_of_candidates, ss); + NR_BWP_Downlink_t *bwp = ra->secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra->bwp_id - 1]; + NR_ControlResourceSet_t *coreset = get_coreset(bwp, ss, 0 /* common */); + int CCEIndex = allocate_nr_CCEs(nr_mac, + bwp, + coreset, + aggregation_level, + 0, // Y + 0, // m + nr_of_candidates); + + if (CCEIndex < 0) { + LOG_E(MAC, "%s(): cannot find free CCE for RA RNTI %04x!\n", __func__, ra->rnti); + return; + } + nfapi_nr_pdu_t *tx_req = &nr_mac->TX_req[CC_id].pdu_list[nr_mac->TX_req[CC_id].Number_of_PDUs]; - nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdcch_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs]; - memset((void*)dl_tti_pdcch_pdu,0,sizeof(nfapi_nr_dl_tti_request_pdu_t)); - dl_tti_pdcch_pdu->PDUType = NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE; - dl_tti_pdcch_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdcch_pdu)); + /* look up the PDCCH PDU for this CC, BWP, and CORESET. If it does not + * exist, create it. This is especially important if we have multiple RAs, + * and the DLSCH has to reuse them, so we need to mark them */ + const int bwpid = bwp->bwp_Id; + const int coresetid = coreset->controlResourceSetId; + nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = nr_mac->pdcch_pdu_idx[CC_id][bwpid][coresetid]; + if (!pdcch_pdu_rel15) { + nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdcch_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs]; + memset(dl_tti_pdcch_pdu, 0, sizeof(nfapi_nr_dl_tti_request_pdu_t)); + dl_tti_pdcch_pdu->PDUType = NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE; + dl_tti_pdcch_pdu->PDUSize = (uint8_t)(2 + sizeof(nfapi_nr_dl_tti_pdcch_pdu)); + dl_req->nPDUs += 1; + pdcch_pdu_rel15 = &dl_tti_pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15; + nr_configure_pdcch(pdcch_pdu_rel15, ss, coreset, scc, bwp); + nr_mac->pdcch_pdu_idx[CC_id][bwpid][coresetid] = pdcch_pdu_rel15; + } - nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs+1]; + nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs]; memset((void *)dl_tti_pdsch_pdu,0,sizeof(nfapi_nr_dl_tti_request_pdu_t)); dl_tti_pdsch_pdu->PDUType = NFAPI_NR_DL_TTI_PDSCH_PDU_TYPE; dl_tti_pdsch_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdsch_pdu)); - - nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = &dl_tti_pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15; + dl_req->nPDUs+=1; nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu_rel15 = &dl_tti_pdsch_pdu->pdsch_pdu.pdsch_pdu_rel15; - // Checking if the DCI allocation is feasible in current subframe - if (dl_req->nPDUs == NFAPI_NR_MAX_DL_TTI_PDUS) { - LOG_I(MAC, "[RAPROC] Subframe %d: FAPI DL structure is full, skip scheduling UE %d\n", slotP, RA_rnti); - return; - } - LOG_I(MAC,"[gNB %d] [RAPROC] CC_id %d Frame %d, slotP %d: Generating RAR DCI, state %d\n", module_idP, CC_id, frameP, slotP, ra->state); // This code from this point on will not work on initialBWP or CORESET0 @@ -824,7 +852,6 @@ void nr_generate_Msg2(module_id_t module_idP, ra->crnti); AssertFatal(ra->secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count == 1, "downlinkBWP_ToAddModList has %d BWP!\n", ra->secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count); - NR_BWP_Downlink_t *bwp = ra->secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra->bwp_id - 1]; NR_BWP_Uplink_t *ubwp=ra->secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[ra->bwp_id-1]; LOG_I(MAC, "[RAPROC] Scheduling common search space DCI type 1 dlBWP BW %d\n", dci10_bw); @@ -837,7 +864,11 @@ void nr_generate_Msg2(module_id_t module_idP, pdsch_pdu_rel15->pduBitmap = 0; pdsch_pdu_rel15->rnti = RA_rnti; - pdsch_pdu_rel15->pduIndex = 0; + /* SCF222: PDU index incremented for each PDSCH PDU sent in TX control + * message. This is used to associate control information to data and is + * reset every slot. */ + const int pduindex = nr_mac->pdu_index[CC_id]++; + pdsch_pdu_rel15->pduIndex = pduindex; pdsch_pdu_rel15->BWPSize = NRRIV2BW(bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); @@ -887,65 +918,61 @@ void nr_generate_Msg2(module_id_t module_idP, pdsch_pdu_rel15->NrOfSymbols = NrOfSymbols; pdsch_pdu_rel15->dlDmrsSymbPos = fill_dmrs_mask(NULL, scc->dmrs_TypeA_Position, NrOfSymbols); - dci_pdu_rel15_t dci_pdu_rel15[MAX_DCI_CORESET]; - dci_pdu_rel15[0].frequency_domain_assignment.val = PRBalloc_to_locationandbandwidth0(pdsch_pdu_rel15->rbSize, + /* Fill PDCCH DL DCI PDU */ + nfapi_nr_dl_dci_pdu_t *dci_pdu = &pdcch_pdu_rel15->dci_pdu[pdcch_pdu_rel15->numDlDci]; + pdcch_pdu_rel15->numDlDci++; + dci_pdu->RNTI = RA_rnti; + /* TODO: remove next line */ + AssertFatal(ss->searchSpaceType->present != NR_SearchSpace__searchSpaceType_PR_ue_Specific, + "shouldn't the RA SS be common?\n"); + dci_pdu->ScramblingId = *scc->physCellId; + dci_pdu->ScramblingRNTI = 0; + dci_pdu->AggregationLevel = aggregation_level; + dci_pdu->CceIndex = CCEIndex; + dci_pdu->beta_PDCCH_1_0 = 0; + dci_pdu->powerControlOffsetSS = 1; + + dci_pdu_rel15_t dci_payload; + dci_payload.frequency_domain_assignment.val = PRBalloc_to_locationandbandwidth0(pdsch_pdu_rel15->rbSize, pdsch_pdu_rel15->rbStart,dci10_bw); - dci_pdu_rel15[0].time_domain_assignment.val = time_domain_assignment; - dci_pdu_rel15[0].vrb_to_prb_mapping.val = 0; - dci_pdu_rel15[0].mcs = pdsch_pdu_rel15->mcsIndex[0]; - dci_pdu_rel15[0].tb_scaling = 0; - - LOG_I(MAC, "[RAPROC] DCI type 1 payload: freq_alloc %d (%d,%d,%d), time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d \n", - dci_pdu_rel15[0].frequency_domain_assignment.val, - pdsch_pdu_rel15->rbStart, - pdsch_pdu_rel15->rbSize, - dci10_bw, - dci_pdu_rel15[0].time_domain_assignment.val, - dci_pdu_rel15[0].vrb_to_prb_mapping.val, - dci_pdu_rel15[0].mcs, - dci_pdu_rel15[0].tb_scaling); - - uint8_t nr_of_candidates, aggregation_level; - find_aggregation_candidates(&aggregation_level, &nr_of_candidates, ss); - NR_ControlResourceSet_t *coreset = get_coreset(bwp, ss, 0 /* common */); - int CCEIndex = allocate_nr_CCEs(nr_mac, - bwp, - coreset, - aggregation_level, - 0, // Y - 0, // m - nr_of_candidates); - - if (CCEIndex < 0) { - LOG_E(MAC, "%s(): cannot find free CCE for RA RNTI %04x!\n", __func__, ra->rnti); - return; - } - nr_configure_pdcch(nr_mac, - pdcch_pdu_rel15, - RA_rnti, - ss, - coreset, - scc, - bwp, - aggregation_level, - CCEIndex); + dci_payload.time_domain_assignment.val = time_domain_assignment; + dci_payload.vrb_to_prb_mapping.val = 0; + dci_payload.mcs = pdsch_pdu_rel15->mcsIndex[0]; + dci_payload.tb_scaling = 0; + + LOG_I(MAC, + "[RAPROC] DCI type 1 payload: freq_alloc %d (%d,%d,%d), time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d \n", + dci_payload.frequency_domain_assignment.val, + pdsch_pdu_rel15->rbStart, + pdsch_pdu_rel15->rbSize, + dci10_bw, + dci_payload.time_domain_assignment.val, + dci_payload.vrb_to_prb_mapping.val, + dci_payload.mcs, + dci_payload.tb_scaling); LOG_I(MAC, "Frame %d: Subframe %d : Adding common DL DCI for RA_RNTI %x\n", frameP, slotP, RA_rnti); - dci_formats[0] = NR_DL_DCI_FORMAT_1_0; - rnti_types[0] = NR_RNTI_RA; - - LOG_I(MAC, "[RAPROC] DCI params: rnti %d, rnti_type %d, dci_format %d coreset params: FreqDomainResource %llx, start_symbol %d n_symb %d\n", - pdcch_pdu_rel15->dci_pdu.RNTI[0], - rnti_types[0], - dci_formats[0], - (unsigned long long)pdcch_pdu_rel15->FreqDomainResource, - pdcch_pdu_rel15->StartSymbolIndex, - pdcch_pdu_rel15->DurationSymbols); - - fill_dci_pdu_rel15(scc,ra->secondaryCellGroup,pdcch_pdu_rel15, &dci_pdu_rel15[0], dci_formats, rnti_types,dci10_bw,ra->bwp_id); - - dl_req->nPDUs+=2; + const int dci_format = NR_DL_DCI_FORMAT_1_0; + const int rnti_type = NR_RNTI_RA; + + LOG_I(MAC, + "[RAPROC] DCI params: rnti %d, rnti_type %d, dci_format %d coreset params: FreqDomainResource %llx, start_symbol %d n_symb %d\n", + pdcch_pdu_rel15->dci_pdu[0].RNTI, + rnti_type, + dci_format, + (unsigned long long)pdcch_pdu_rel15->FreqDomainResource, + pdcch_pdu_rel15->StartSymbolIndex, + pdcch_pdu_rel15->DurationSymbols); + + fill_dci_pdu_rel15(scc, + ra->secondaryCellGroup, + dci_pdu, + &dci_payload, + dci_format, + rnti_type, + dci10_bw, + ra->bwp_id); // Program UL processing for Msg3 nr_get_Msg3alloc(module_idP, CC_id, scc, ubwp, slotP, frameP, ra); @@ -955,11 +982,11 @@ void nr_generate_Msg2(module_id_t module_idP, LOG_I(MAC,"[gNB %d][RAPROC] Frame %d, Subframe %d: RA state %d\n", module_idP, frameP, slotP, ra->state); x_Overhead = 0; - nr_get_tbs_dl(&dl_tti_pdsch_pdu->pdsch_pdu, x_Overhead, pdsch_pdu_rel15->numDmrsCdmGrpsNoData, dci_pdu_rel15[0].tb_scaling); + nr_get_tbs_dl(&dl_tti_pdsch_pdu->pdsch_pdu, x_Overhead, pdsch_pdu_rel15->numDmrsCdmGrpsNoData, dci_payload.tb_scaling); // DL TX request tx_req->PDU_length = pdsch_pdu_rel15->TBSize[0]; - tx_req->PDU_index = nr_mac->pdu_index[CC_id]++; + tx_req->PDU_index = pduindex; tx_req->num_TLV = 1; tx_req->TLVs[0].length = 8; nr_mac->TX_req[CC_id].SFN = frameP; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index 66766535e84de0e67861d0267b243d3e5e0a4a81..1de46aaea4504707b4f1305c78c165cb76aadff6 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -126,7 +126,12 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP, mib_sdu_length); if ((frameP & 1023) < 80){ - LOG_I(MAC,"[gNB %d] Frame %d : MIB->BCH CC_id %d, Received %d bytes\n",module_idP, frameP, CC_id, mib_sdu_length); + LOG_D(MAC, + "[gNB %d] Frame %d : MIB->BCH CC_id %d, Received %d bytes\n", + module_idP, + frameP, + CC_id, + mib_sdu_length); } dl_config_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs]; @@ -331,13 +336,19 @@ void nr_fill_nfapi_dl_sib1_pdu(int Mod_idP, memset((void*)dl_tti_pdcch_pdu,0,sizeof(nfapi_nr_dl_tti_request_pdu_t)); dl_tti_pdcch_pdu->PDUType = NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE; dl_tti_pdcch_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdcch_pdu)); + dl_req->nPDUs += 1; + nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = &dl_tti_pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15; + nr_configure_pdcch(pdcch_pdu_rel15, + gNB_mac->sched_ctrlCommon->search_space, + gNB_mac->sched_ctrlCommon->coreset, + scc, + bwp); - nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs+1]; + nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs]; memset((void*)dl_tti_pdsch_pdu,0,sizeof(nfapi_nr_dl_tti_request_pdu_t)); dl_tti_pdsch_pdu->PDUType = NFAPI_NR_DL_TTI_PDSCH_PDU_TYPE; dl_tti_pdsch_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdsch_pdu)); - - nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = &dl_tti_pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15; + dl_req->nPDUs += 1; nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu_rel15 = &dl_tti_pdsch_pdu->pdsch_pdu.pdsch_pdu_rel15; pdcch_pdu_rel15->CoreSetType = NFAPI_NR_CSET_CONFIG_MIB_SIB1; @@ -385,48 +396,50 @@ void nr_fill_nfapi_dl_sib1_pdu(int Mod_idP, LOG_D(MAC,"dlDmrsSymbPos = 0x%x\n", pdsch_pdu_rel15->dlDmrsSymbPos); - dci_pdu_rel15_t dci_pdu_rel15[MAX_DCI_CORESET]; - memset(dci_pdu_rel15, 0, sizeof(dci_pdu_rel15_t) * MAX_DCI_CORESET); + /* Fill PDCCH DL DCI PDU */ + nfapi_nr_dl_dci_pdu_t *dci_pdu = &pdcch_pdu_rel15->dci_pdu[pdcch_pdu_rel15->numDlDci]; + pdcch_pdu_rel15->numDlDci++; + dci_pdu->RNTI = SI_RNTI; + dci_pdu->ScramblingId = *scc->physCellId; + dci_pdu->ScramblingRNTI = 0; + dci_pdu->AggregationLevel = gNB_mac->sched_ctrlCommon->aggregation_level; + dci_pdu->CceIndex = gNB_mac->sched_ctrlCommon->cce_index; + dci_pdu->beta_PDCCH_1_0 = 0; + dci_pdu->powerControlOffsetSS = 1; - dci_pdu_rel15[0].bwp_indicator.val = gNB_mac->sched_ctrlCommon->active_bwp->bwp_Id; + /* DCI payload */ + dci_pdu_rel15_t dci_payload; + memset(&dci_payload, 0, sizeof(dci_pdu_rel15_t)); - // frequency domain assignment - dci_pdu_rel15[0].frequency_domain_assignment.val = - PRBalloc_to_locationandbandwidth0(pdsch_pdu_rel15->rbSize, - pdsch_pdu_rel15->rbStart, - gNB_mac->type0_PDCCH_CSS_config.num_rbs); - - dci_pdu_rel15[0].time_domain_assignment.val = gNB_mac->sched_ctrlCommon->time_domain_allocation; - dci_pdu_rel15[0].mcs = gNB_mac->sched_ctrlCommon->mcs; - dci_pdu_rel15[0].rv = pdsch_pdu_rel15->rvIndex[0]; - dci_pdu_rel15[0].harq_pid = 0; - dci_pdu_rel15[0].ndi = 0; - dci_pdu_rel15[0].dai[0].val = 0; - dci_pdu_rel15[0].tpc = 0; // table 7.2.1-1 in 38.213 - dci_pdu_rel15[0].pucch_resource_indicator = 0; - dci_pdu_rel15[0].pdsch_to_harq_feedback_timing_indicator.val = 0; - dci_pdu_rel15[0].antenna_ports.val = 0; - dci_pdu_rel15[0].dmrs_sequence_initialization.val = pdsch_pdu_rel15->SCID; - - nr_configure_pdcch(gNB_mac, - pdcch_pdu_rel15, - SI_RNTI, - gNB_mac->sched_ctrlCommon->search_space, - gNB_mac->sched_ctrlCommon->coreset, - scc, - bwp, - gNB_mac->sched_ctrlCommon->aggregation_level, - gNB_mac->sched_ctrlCommon->cce_index); - - int dci_formats[2]; - int rnti_types[2]; - - dci_formats[0] = NR_DL_DCI_FORMAT_1_0; - rnti_types[0] = NR_RNTI_SI; + dci_payload.bwp_indicator.val = gNB_mac->sched_ctrlCommon->active_bwp->bwp_Id; - fill_dci_pdu_rel15(scc,secondaryCellGroup,pdcch_pdu_rel15,dci_pdu_rel15,dci_formats,rnti_types,pdsch_pdu_rel15->BWPSize,gNB_mac->sched_ctrlCommon->active_bwp->bwp_Id); - - dl_req->nPDUs += 2; + // frequency domain assignment + dci_payload.frequency_domain_assignment.val = PRBalloc_to_locationandbandwidth0( + pdsch_pdu_rel15->rbSize, pdsch_pdu_rel15->rbStart, gNB_mac->type0_PDCCH_CSS_config.num_rbs); + + dci_payload.time_domain_assignment.val = gNB_mac->sched_ctrlCommon->time_domain_allocation; + dci_payload.mcs = gNB_mac->sched_ctrlCommon->mcs; + dci_payload.rv = pdsch_pdu_rel15->rvIndex[0]; + dci_payload.harq_pid = 0; + dci_payload.ndi = 0; + dci_payload.dai[0].val = 0; + dci_payload.tpc = 0; // table 7.2.1-1 in 38.213 + dci_payload.pucch_resource_indicator = 0; + dci_payload.pdsch_to_harq_feedback_timing_indicator.val = 0; + dci_payload.antenna_ports.val = 0; + dci_payload.dmrs_sequence_initialization.val = pdsch_pdu_rel15->SCID; + + int dci_format = NR_DL_DCI_FORMAT_1_0; + int rnti_type = NR_RNTI_SI; + + fill_dci_pdu_rel15(scc, + secondaryCellGroup, + &pdcch_pdu_rel15->dci_pdu[pdcch_pdu_rel15->numDlDci - 1], + &dci_payload, + dci_format, + rnti_type, + pdsch_pdu_rel15->BWPSize, + gNB_mac->sched_ctrlCommon->active_bwp->bwp_Id); LOG_D(MAC,"BWPSize: %i\n", pdcch_pdu_rel15->BWPSize); LOG_D(MAC,"BWPStart: %i\n", pdcch_pdu_rel15->BWPStart); @@ -504,4 +517,4 @@ void schedule_nr_sib1(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) gNB_mac->TX_req[CC_id].SFN = frameP; gNB_mac->TX_req[CC_id].Slot = slotP; } -} \ No newline at end of file +} diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 4110af07edaef19f2cea0a4ee773352e5bb4d2bc..4d491b28434edd5c2f649e4ad1d9cef42b56b03f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -56,27 +56,22 @@ #define WORD 32 //#define SIZE_OF_POINTER sizeof (void *) -int nr_generate_dlsch_pdu(module_id_t module_idP, - NR_UE_sched_ctrl_t *ue_sched_ctl, - unsigned char *sdus_payload, +// Compute and write all MAC CEs and subheaders, and return number of written +// bytes +int nr_write_ce_dlsch_pdu(module_id_t module_idP, + const NR_UE_sched_ctrl_t *ue_sched_ctl, unsigned char *mac_pdu, - unsigned char num_sdus, - unsigned short *sdu_lengths, - unsigned char *sdu_lcids, unsigned char drx_cmd, - unsigned char *ue_cont_res_id, - unsigned short post_padding) { + unsigned char *ue_cont_res_id) +{ gNB_MAC_INST *gNB = RC.nrmac[module_idP]; NR_MAC_SUBHEADER_FIXED *mac_pdu_ptr = (NR_MAC_SUBHEADER_FIXED *) mac_pdu; - unsigned char *dlsch_buffer_ptr = sdus_payload; uint8_t last_size = 0; int offset = 0, mac_ce_size, i, timing_advance_cmd, tag_id = 0; // MAC CEs uint8_t mac_header_control_elements[16], *ce_ptr; ce_ptr = &mac_header_control_elements[0]; - // 1) Compute MAC CE and related subheaders - // DRX command subheader (MAC CE size 0) if (drx_cmd != 255) { mac_pdu_ptr->R = 0; @@ -301,42 +296,6 @@ int nr_generate_dlsch_pdu(module_id_t module_idP, } } - // 2) Generation of DLSCH MAC subPDUs including subheaders and MAC SDUs - for (i = 0; i < num_sdus; i++) { - - if (sdu_lengths[i] < 256) { - ((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->R = 0; - ((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->F = 0; - ((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->LCID = sdu_lcids[i]; - ((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->L = (unsigned char) sdu_lengths[i]; - last_size = 2; - } else { - ((NR_MAC_SUBHEADER_LONG *) mac_pdu_ptr)->R = 0; - ((NR_MAC_SUBHEADER_LONG *) mac_pdu_ptr)->F = 1; - ((NR_MAC_SUBHEADER_LONG *) mac_pdu_ptr)->LCID = sdu_lcids[i]; - ((NR_MAC_SUBHEADER_LONG *) mac_pdu_ptr)->L1 = ((unsigned short) sdu_lengths[i] >> 8) & 0xff; - ((NR_MAC_SUBHEADER_LONG *) mac_pdu_ptr)->L2 = (unsigned short) sdu_lengths[i] & 0xff; - last_size = 3; - } - - mac_pdu_ptr += last_size; - // 3) cycle through SDUs, compute each relevant and place dlsch_buffer in - memcpy((void *) mac_pdu_ptr, (void *) dlsch_buffer_ptr, sdu_lengths[i]); - dlsch_buffer_ptr += sdu_lengths[i]; - mac_pdu_ptr += sdu_lengths[i]; - LOG_D(MAC, "Generate DLSCH header num sdu %d len header %d len sdu %d -> offset %ld\n", num_sdus, last_size, sdu_lengths[i], (unsigned char *)mac_pdu_ptr - mac_pdu); - } - - // 4) Compute final offset for padding - if (post_padding > 0) { - ((NR_MAC_SUBHEADER_FIXED *) mac_pdu_ptr)->R = 0; - ((NR_MAC_SUBHEADER_FIXED *) mac_pdu_ptr)->LCID = DL_SCH_LCID_PADDING; - mac_pdu_ptr++; - LOG_D(MAC, "Generate Padding -> offset %ld\n", (unsigned char *)mac_pdu_ptr - mac_pdu); - } else { - // no MAC subPDU with padding - } - // compute final offset offset = ((unsigned char *) mac_pdu_ptr - mac_pdu); //printf("Offset %d \n", ((unsigned char *) mac_pdu_ptr - mac_pdu)); @@ -372,123 +331,236 @@ uint8_t getN_PRB_DMRS(NR_BWP_Downlink_t *bwp, int numDmrsCdmGrpsNoData) { } } -void nr_simple_dlsch_preprocessor(module_id_t module_id, - frame_t frame, - sub_frame_t slot, - int num_slots_per_tdd) { - NR_UE_info_t *UE_info = &RC.nrmac[module_id]->UE_info; +void nr_store_dlsch_buffer(module_id_t module_id, + frame_t frame, + sub_frame_t slot) { - AssertFatal(UE_info->num_UEs <= 1, - "%s() cannot handle more than one UE, but found %d\n", - __func__, - UE_info->num_UEs); - if (UE_info->num_UEs == 0) - return; + NR_UE_info_t *UE_info = &RC.nrmac[module_id]->UE_info; - const int UE_id = 0; - const int CC_id = 0; + for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) { + NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; - NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + sched_ctrl->num_total_bytes = 0; + const int lcid = DL_SCH_LCID_DTCH; + const uint16_t rnti = UE_info->rnti[UE_id]; + sched_ctrl->rlc_status[lcid] = mac_rlc_status_ind(module_id, + rnti, + module_id, + frame, + slot, + ENB_FLAG_YES, + MBMS_FLAG_NO, + lcid, + 0, + 0); + sched_ctrl->num_total_bytes += sched_ctrl->rlc_status[lcid].bytes_in_buffer; + LOG_D(MAC, + "[%s][%d.%d], DTCH%d->DLSCH, RLC status %d bytes TA %d\n", + __func__, + frame, + slot, + lcid, + sched_ctrl->rlc_status[lcid].bytes_in_buffer, + sched_ctrl->ta_apply); + } +} - /* Retrieve amount of data to send for this UE */ - sched_ctrl->num_total_bytes = 0; - const int lcid = DL_SCH_LCID_DTCH; - const rnti_t rnti = UE_info->rnti[UE_id]; - sched_ctrl->rlc_status[lcid] = mac_rlc_status_ind(module_id, - rnti, - module_id, - frame, - slot, - ENB_FLAG_YES, - MBMS_FLAG_NO, - lcid, - 0, - 0); - sched_ctrl->num_total_bytes += sched_ctrl->rlc_status[lcid].bytes_in_buffer; - if (sched_ctrl->num_total_bytes == 0 - && !sched_ctrl->ta_apply) /* If TA should be applied, give at least one RB */ - return; +bool allocate_retransmission(module_id_t module_id, + uint8_t *rballoc_mask, + int *n_rb_sched, + int UE_id, + int current_harq_pid){ + NR_UE_sched_ctrl_t *sched_ctrl = &RC.nrmac[module_id]->UE_info.UE_sched_ctrl[UE_id]; + NR_UE_ret_info_t *retInfo = &sched_ctrl->retInfo[current_harq_pid]; + const uint16_t bwpSize = NRRIV2BW(sched_ctrl->active_bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + int rbStart = NRRIV2PRBOFFSET(sched_ctrl->active_bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - LOG_D(MAC, "[%s][%d.%d], DTCH%d->DLSCH, RLC status %d bytes TA %d\n", - __FUNCTION__, - frame, - slot, - lcid, - sched_ctrl->rlc_status[lcid].bytes_in_buffer, - sched_ctrl->ta_apply); - - /* Find a free CCE */ - const int target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific; - sched_ctrl->search_space = get_searchspace(sched_ctrl->active_bwp, target_ss); - uint8_t nr_of_candidates; - find_aggregation_candidates(&sched_ctrl->aggregation_level, - &nr_of_candidates, - sched_ctrl->search_space); - sched_ctrl->coreset = get_coreset(sched_ctrl->active_bwp, sched_ctrl->search_space, 1 /*dedicated*/); - int cid = sched_ctrl->coreset->controlResourceSetId; - const uint16_t Y = UE_info->Y[UE_id][cid][slot]; - const int m = UE_info->num_pdcch_cand[UE_id][cid]; - sched_ctrl->cce_index = allocate_nr_CCEs(RC.nrmac[module_id], - sched_ctrl->active_bwp, - sched_ctrl->coreset, - sched_ctrl->aggregation_level, - Y, - m, - nr_of_candidates); - if (sched_ctrl->cce_index < 0) { - LOG_E(MAC, "%s(): could not find CCE for UE %d\n", __func__, UE_id); - return; + sched_ctrl->time_domain_allocation = retInfo->time_domain_allocation; + + /* ensure that there is a free place for RB allocation */ + int rbSize = 0; + while (rbSize < retInfo->rbSize) { + rbStart += rbSize; /* last iteration rbSize was not enough, skip it */ + rbSize = 0; + while (rbStart < bwpSize && !rballoc_mask[rbStart]) rbStart++; + if (rbStart >= bwpSize) { + LOG_D(MAC, + "cannot allocate retransmission for UE %d/RNTI %04x: no resources\n", + UE_id, + RC.nrmac[module_id]->UE_info.rnti[UE_id]); + return false; + } + while (rbStart + rbSize < bwpSize + && rballoc_mask[rbStart + rbSize] + && rbSize < retInfo->rbSize) + rbSize++; } - UE_info->num_pdcch_cand[UE_id][cid]++; + sched_ctrl->rbSize = retInfo->rbSize; + sched_ctrl->rbStart = rbStart; - /* Find PUCCH occasion */ - nr_acknack_scheduling(module_id, - UE_id, - frame, - slot, - num_slots_per_tdd, - &sched_ctrl->pucch_sched_idx, - &sched_ctrl->pucch_occ_idx); + /* MCS etc: just reuse from previous scheduling opportunity */ + sched_ctrl->mcsTableIdx = retInfo->mcsTableIdx; + sched_ctrl->mcs = retInfo->mcs; + sched_ctrl->numDmrsCdmGrpsNoData = retInfo->numDmrsCdmGrpsNoData; - AssertFatal(sched_ctrl->pucch_sched_idx >= 0, "no uplink slot for PUCCH found!\n"); + /* retransmissions: directly allocate */ + *n_rb_sched -= sched_ctrl->rbSize; + for (int rb = 0; rb < sched_ctrl->rbSize; rb++) + rballoc_mask[rb+sched_ctrl->rbStart] = 0; + return true; +} - uint16_t *vrb_map = RC.nrmac[module_id]->common_channels[CC_id].vrb_map; - // for now HARQ PID is fixed and should be the same as in post-processor - const int current_harq_pid = slot % num_slots_per_tdd; - NR_UE_harq_t *harq = &sched_ctrl->harq_processes[current_harq_pid]; - NR_UE_ret_info_t *retInfo = &sched_ctrl->retInfo[current_harq_pid]; - const uint16_t bwpSize = NRRIV2BW(sched_ctrl->active_bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - int rbStart = NRRIV2PRBOFFSET(sched_ctrl->active_bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); +float thr_ue[MAX_MOBILES_PER_GNB]; - if (harq->round != 0) { /* retransmission */ - sched_ctrl->time_domain_allocation = retInfo->time_domain_allocation; +void pf_dl(module_id_t module_id, + frame_t frame, + sub_frame_t slot, + NR_list_t *UE_list, + int n_rb_sched, + uint8_t *rballoc_mask, + int max_num_ue) { - /* ensure that there is a free place for RB allocation */ - int rbSize = 0; - while (rbSize < retInfo->rbSize) { - rbStart += rbSize; /* last iteration rbSize was not enough, skip it */ - rbSize = 0; - while (rbStart < bwpSize && vrb_map[rbStart]) rbStart++; - if (rbStart >= bwpSize) { - LOG_E(MAC, - "cannot allocate retransmission for UE %d/RNTI %04x: no resources\n", + NR_UE_info_t *UE_info = &RC.nrmac[module_id]->UE_info; + float coeff_ue[MAX_MOBILES_PER_GNB]; + // UEs that could be scheduled + int ue_array[MAX_MOBILES_PER_GNB]; + NR_list_t UE_sched = { .head = -1, .next = ue_array, .tail = -1, .len = MAX_MOBILES_PER_GNB }; + + /* Loop UE_info->list to check retransmission */ + for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { + NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + sched_ctrl->search_space = get_searchspace(sched_ctrl->active_bwp, NR_SearchSpace__searchSpaceType_PR_ue_Specific); + sched_ctrl->coreset = get_coreset(sched_ctrl->active_bwp, sched_ctrl->search_space, 1 /* dedicated */); + /* get the PID of a HARQ process awaiting retrnasmission, or -1 otherwise */ + sched_ctrl->dl_harq_pid = sched_ctrl->retrans_dl_harq.head; + const rnti_t rnti = UE_info->rnti[UE_id]; + + /* Calculate Throughput */ + const float a = 0.0005f; // corresponds to 200ms window + const uint32_t b = UE_info->mac_stats[UE_id].dlsch_current_bytes; + thr_ue[UE_id] = (1 - a) * thr_ue[UE_id] + a * b; + + /* retransmission */ + if (sched_ctrl->dl_harq_pid >= 0) { + /* Find a free CCE */ + bool freeCCE = find_free_CCE(module_id, slot, UE_id); + if (!freeCCE){ + LOG_D(MAC, "%4d.%2d could not find CCE for DL DCI retransmission UE %d/RNTI %04x\n", frame, slot, UE_id, rnti); + continue; + } + /* Find PUCCH occasion: if it fails, undo CCE allocation (undoing PUCCH + * allocation after CCE alloc fail would be more complex) */ + const bool alloc = nr_acknack_scheduling(module_id, UE_id, frame, slot); + if (!alloc) { + LOG_W(MAC, + "%s(): could not find PUCCH for UE %d/%04x@%d.%d\n", + __func__, UE_id, - rnti); + rnti, + frame, + slot); + int cid = sched_ctrl->coreset->controlResourceSetId; + UE_info->num_pdcch_cand[UE_id][cid]--; + int *cce_list = RC.nrmac[module_id]->cce_list[sched_ctrl->active_bwp->bwp_Id][cid]; + for (int i = 0; i < sched_ctrl->aggregation_level; i++) + cce_list[sched_ctrl->cce_index + i] = 0; return; } - while (rbStart + rbSize < bwpSize - && !vrb_map[rbStart + rbSize] - && rbSize < retInfo->rbSize) - rbSize++; + /* Allocate retransmission */ + bool r = allocate_retransmission(module_id, rballoc_mask, &n_rb_sched, UE_id, sched_ctrl->dl_harq_pid); + if (!r) { + LOG_D(MAC, "%4d.%2d retransmission can NOT be allocated\n", frame, slot); + continue; + } + /* reduce max_num_ue once we are sure UE can be allocated, i.e., has CCE */ + max_num_ue--; + if (max_num_ue < 0) return; + } else { + /* Check DL buffer and skip this UE if no bytes and no TA necessary */ + if (sched_ctrl->num_total_bytes == 0 && frame != (sched_ctrl->ta_frame + 10) % 1024) + continue; + + /* Calculate coeff */ + sched_ctrl->time_domain_allocation = 2; + sched_ctrl->mcsTableIdx = 0; + sched_ctrl->mcs = 9; + sched_ctrl->numDmrsCdmGrpsNoData = 1; + uint8_t N_PRB_DMRS = + getN_PRB_DMRS(sched_ctrl->active_bwp, sched_ctrl->numDmrsCdmGrpsNoData); + int nrOfSymbols = getNrOfSymbols(sched_ctrl->active_bwp, + sched_ctrl->time_domain_allocation); + uint32_t tbs = nr_compute_tbs(nr_get_Qm_dl(sched_ctrl->mcs, sched_ctrl->mcsTableIdx), + nr_get_code_rate_dl(sched_ctrl->mcs, sched_ctrl->mcsTableIdx), + 1, // rbSize + nrOfSymbols, + N_PRB_DMRS, // FIXME // This should be multiplied by the + // number of dmrs symbols + 0 /* N_PRB_oh, 0 for initialBWP */, 0 /* tb_scaling */, + 1 /* nrOfLayers */) + >> 3; + coeff_ue[UE_id] = (float) tbs / thr_ue[UE_id]; + LOG_D(MAC,"b %d, thr_ue[%d] %f, tbs %d, coeff_ue[%d] %f\n", + b, UE_id, thr_ue[UE_id], tbs, UE_id, coeff_ue[UE_id]); + /* Create UE_sched list for UEs eligible for new transmission*/ + add_tail_nr_list(&UE_sched, UE_id); } - sched_ctrl->rbSize = retInfo->rbSize; - sched_ctrl->rbStart = rbStart; + } - /* MCS etc: just reuse from previous scheduling opportunity */ - sched_ctrl->mcsTableIdx = retInfo->mcsTableIdx; - sched_ctrl->mcs = retInfo->mcs; - sched_ctrl->numDmrsCdmGrpsNoData = retInfo->numDmrsCdmGrpsNoData; - } else { + /* Loop UE_sched to find max coeff and allocate transmission */ + while (max_num_ue > 0 && n_rb_sched > 0 && UE_sched.head >= 0) { + + /* Find max coeff from UE_sched*/ + int *max = &UE_sched.head; /* assume head is max */ + int *p = &UE_sched.next[*max]; + while (*p >= 0) { + /* if the current one has larger coeff, save for later */ + if (coeff_ue[*p] > coeff_ue[*max]) + max = p; + p = &UE_sched.next[*p]; + } + /* remove the max one: do not use remove_nr_list() it goes through the + * whole list every time. Note that UE_sched.tail might not be set + * correctly anymore */ + const int UE_id = *max; + p = &UE_sched.next[*max]; + *max = UE_sched.next[*max]; + *p = -1; + + NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + const uint16_t rnti = UE_info->rnti[UE_id]; + const uint16_t bwpSize = NRRIV2BW(sched_ctrl->active_bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + int rbStart = NRRIV2PRBOFFSET(sched_ctrl->active_bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + + /* Find a free CCE */ + bool freeCCE = find_free_CCE(module_id, slot, UE_id); + if (!freeCCE) { + LOG_D(MAC, "%4d.%2d could not find CCE for DL DCI UE %d/RNTI %04x\n", frame, slot, UE_id, rnti); + continue; + } + /* reduce max_num_ue once we are sure UE can be allocated, i.e., has CCE */ + max_num_ue--; + if (max_num_ue < 0) return; + + /* Find PUCCH occasion: if it fails, undo CCE allocation (undoing PUCCH + * allocation after CCE alloc fail would be more complex) */ + const bool alloc = nr_acknack_scheduling(module_id, UE_id, frame, slot); + if (!alloc) { + LOG_W(MAC, + "%s(): could not find PUCCH for UE %d/%04x@%d.%d\n", + __func__, + UE_id, + rnti, + frame, + slot); + int cid = sched_ctrl->coreset->controlResourceSetId; + UE_info->num_pdcch_cand[UE_id][cid]--; + int *cce_list = RC.nrmac[module_id]->cce_list[sched_ctrl->active_bwp->bwp_Id][cid]; + for (int i = 0; i < sched_ctrl->aggregation_level; i++) + cce_list[sched_ctrl->cce_index + i] = 0; + return; + } + + /* Allocate transmission */ // Time-domain allocation sched_ctrl->time_domain_allocation = 2; @@ -498,20 +570,22 @@ void nr_simple_dlsch_preprocessor(module_id_t module_id, sched_ctrl->numDmrsCdmGrpsNoData = 1; // Freq-demain allocation - while (rbStart < bwpSize && vrb_map[rbStart]) rbStart++; + while (rbStart < bwpSize && !rballoc_mask[rbStart]) rbStart++; - uint8_t N_PRB_DMRS = + const uint8_t N_PRB_DMRS = getN_PRB_DMRS(sched_ctrl->active_bwp, sched_ctrl->numDmrsCdmGrpsNoData); - int nrOfSymbols = getNrOfSymbols(sched_ctrl->active_bwp, - sched_ctrl->time_domain_allocation); - uint8_t N_DMRS_SLOT = get_num_dmrs_symbols(sched_ctrl->active_bwp->bwp_Dedicated->pdsch_Config->choice.setup, - RC.nrmac[module_id]->common_channels->ServingCellConfigCommon->dmrs_TypeA_Position , - nrOfSymbols); + const int nrOfSymbols = getNrOfSymbols(sched_ctrl->active_bwp, + sched_ctrl->time_domain_allocation); + const NR_ServingCellConfigCommon_t *scc = RC.nrmac[module_id]->common_channels->ServingCellConfigCommon; + const uint8_t N_DMRS_SLOT = get_num_dmrs_symbols( + sched_ctrl->active_bwp->bwp_Dedicated->pdsch_Config->choice.setup, + scc->dmrs_TypeA_Position, + nrOfSymbols); int rbSize = 0; + uint32_t TBS = 0; const int oh = 2 + (sched_ctrl->num_total_bytes >= 256) + 2 * (frame == (sched_ctrl->ta_frame + 10) % 1024); - uint32_t TBS = 0; do { rbSize++; TBS = nr_compute_tbs(nr_get_Qm_dl(sched_ctrl->mcs, sched_ctrl->mcsTableIdx), @@ -523,31 +597,74 @@ void nr_simple_dlsch_preprocessor(module_id_t module_id, 0 /* tb_scaling */, 1 /* nrOfLayers */) >> 3; - } while (rbStart + rbSize < bwpSize && !vrb_map[rbStart + rbSize] && TBS < sched_ctrl->num_total_bytes + oh); + } while (rbStart + rbSize < bwpSize && rballoc_mask[rbStart + rbSize] && TBS < sched_ctrl->num_total_bytes + oh); sched_ctrl->rbSize = rbSize; sched_ctrl->rbStart = rbStart; + + /* transmissions: directly allocate */ + n_rb_sched -= sched_ctrl->rbSize; + for (int rb = 0; rb < sched_ctrl->rbSize; rb++) + rballoc_mask[rb+sched_ctrl->rbStart] = 0; } +} - /* mark the corresponding RBs as used */ - for (int rb = 0; rb < sched_ctrl->rbSize; rb++) - vrb_map[rb + sched_ctrl->rbStart] = 1; +void nr_simple_dlsch_preprocessor(module_id_t module_id, + frame_t frame, + sub_frame_t slot) { + NR_UE_info_t *UE_info = &RC.nrmac[module_id]->UE_info; + + if (UE_info->num_UEs == 0) + return; + + const int CC_id = 0; + + + /* Get bwpSize from the first UE */ + int UE_id = UE_info->list.head; + NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + const uint16_t bwpSize = NRRIV2BW(sched_ctrl->active_bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + + uint16_t *vrb_map = RC.nrmac[module_id]->common_channels[CC_id].vrb_map; + uint8_t rballoc_mask[bwpSize]; + int n_rb_sched = 0; + for (int i = 0; i < bwpSize; i++) { + // calculate mask: init with "NOT" vrb_map: + // if any RB in vrb_map is blocked (1), the current RBG will be 0 + rballoc_mask[i] = !vrb_map[i]; + n_rb_sched += rballoc_mask[i]; + } + + /* Retrieve amount of data to send for this UE */ + nr_store_dlsch_buffer(module_id, frame, slot); + + /* proportional fair scheduling algorithm */ + pf_dl(module_id, + frame, + slot, + &UE_info->list, + n_rb_sched, + rballoc_mask, + 2); } void nr_schedule_ue_spec(module_id_t module_id, frame_t frame, - sub_frame_t slot, - int num_slots_per_tdd) { + sub_frame_t slot) { gNB_MAC_INST *gNB_mac = RC.nrmac[module_id]; /* PREPROCESSOR */ - gNB_mac->pre_processor_dl(module_id, frame, slot, num_slots_per_tdd); + gNB_mac->pre_processor_dl(module_id, frame, slot); + const int CC_id = 0; + NR_ServingCellConfigCommon_t *scc = gNB_mac->common_channels[CC_id].ServingCellConfigCommon; NR_UE_info_t *UE_info = &gNB_mac->UE_info; - const int CC_id = 0; - NR_UE_list_t *UE_list = &UE_info->list; + nfapi_nr_dl_tti_request_body_t *dl_req = &gNB_mac->DL_req[CC_id].dl_tti_request_body; + + NR_list_t *UE_list = &UE_info->list; for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + UE_info->mac_stats[UE_id].dlsch_current_bytes = 0; /* update TA and set ta_apply every 10 frames. * Possible improvement: take the periodicity from input file. @@ -578,10 +695,13 @@ void nr_schedule_ue_spec(module_id_t module_id, uint8_t N_PRB_DMRS = getN_PRB_DMRS(sched_ctrl->active_bwp, sched_ctrl->numDmrsCdmGrpsNoData); - uint8_t N_DMRS_SLOT = get_num_dmrs_symbols(sched_ctrl->active_bwp->bwp_Dedicated->pdsch_Config->choice.setup, RC.nrmac[module_id]->common_channels->ServingCellConfigCommon->dmrs_TypeA_Position , nrOfSymbols); + const nfapi_nr_dmrs_type_e dmrsConfigType = getDmrsConfigType(sched_ctrl->active_bwp); + const int nrOfLayers = 1; + const uint16_t R = nr_get_code_rate_dl(sched_ctrl->mcs, sched_ctrl->mcsTableIdx); + const uint8_t Qm = nr_get_Qm_dl(sched_ctrl->mcs, sched_ctrl->mcsTableIdx); const uint32_t TBS = nr_compute_tbs(nr_get_Qm_dl(sched_ctrl->mcs, sched_ctrl->mcsTableIdx), nr_get_code_rate_dl(sched_ctrl->mcs, sched_ctrl->mcsTableIdx), @@ -590,36 +710,228 @@ void nr_schedule_ue_spec(module_id_t module_id, N_PRB_DMRS * N_DMRS_SLOT, 0 /* N_PRB_oh, 0 for initialBWP */, 0 /* tb_scaling */, - 1 /* nrOfLayers */) + nrOfLayers) >> 3; - const int current_harq_pid = slot % num_slots_per_tdd; + int8_t current_harq_pid = sched_ctrl->dl_harq_pid; + if (current_harq_pid < 0) { + /* PP has not selected a specific HARQ Process, get a new one */ + current_harq_pid = sched_ctrl->available_dl_harq.head; + AssertFatal(current_harq_pid >= 0, + "no free HARQ process available for UE %d\n", + UE_id); + remove_front_nr_list(&sched_ctrl->available_dl_harq); + sched_ctrl->dl_harq_pid = current_harq_pid; + } else { + /* PP selected a specific HARQ process. Check whether it will be a new + * transmission or a retransmission, and remove from the corresponding + * list */ + if (sched_ctrl->harq_processes[current_harq_pid].round == 0) + remove_nr_list(&sched_ctrl->available_dl_harq, current_harq_pid); + else + remove_nr_list(&sched_ctrl->retrans_dl_harq, current_harq_pid); + } NR_UE_harq_t *harq = &sched_ctrl->harq_processes[current_harq_pid]; - NR_sched_pucch *pucch = &sched_ctrl->sched_pucch[sched_ctrl->pucch_sched_idx][sched_ctrl->pucch_occ_idx]; + DevAssert(!harq->is_waiting); + add_tail_nr_list(&sched_ctrl->feedback_dl_harq, current_harq_pid); + NR_sched_pucch_t *pucch = &sched_ctrl->sched_pucch[0]; harq->feedback_slot = pucch->ul_slot; - harq->is_waiting = 1; + harq->is_waiting = true; UE_info->mac_stats[UE_id].dlsch_rounds[harq->round]++; - LOG_D(MAC, "%4d.%2d RNTI %04x start %d RBS %d MCS %d TBS %d HARQ PID %d round %d NDI %d\n", - frame, slot, rnti, sched_ctrl->rbStart, sched_ctrl->rbSize, sched_ctrl->mcs, - TBS, current_harq_pid, harq->round, harq->ndi); - - nfapi_nr_dl_tti_request_body_t *dl_req = &gNB_mac->DL_req[CC_id].dl_tti_request_body; - nr_fill_nfapi_dl_pdu(module_id, - dl_req, - rnti, - UE_info->secondaryCellGroup[UE_id], - sched_ctrl, - pucch, - getDmrsConfigType(sched_ctrl->active_bwp), - nr_get_code_rate_dl(sched_ctrl->mcs, sched_ctrl->mcsTableIdx), - nr_get_Qm_dl(sched_ctrl->mcs, sched_ctrl->mcsTableIdx), - TBS, - startSymbolIndex, - nrOfSymbols, - current_harq_pid, - harq->ndi, - harq->round); + LOG_D(MAC, + "%4d.%2d RNTI %04x start %d RBs %d startSymbol %d nb_symbsol %d MCS %d TBS %d HARQ PID %d round %d NDI %d\n", + frame, + slot, + rnti, + sched_ctrl->rbStart, + sched_ctrl->rbSize, + startSymbolIndex, + nrOfSymbols, + sched_ctrl->mcs, + TBS, + current_harq_pid, + harq->round, + harq->ndi); + + NR_BWP_Downlink_t *bwp = sched_ctrl->active_bwp; + AssertFatal(bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList, + "searchSpacesToAddModList is null\n"); + AssertFatal(bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.count > 0, + "searchSPacesToAddModList is empty\n"); + + /* look up the PDCCH PDU for this CC, BWP, and CORESET. If it does not + * exist, create it */ + const int bwpid = sched_ctrl->active_bwp->bwp_Id; + const int coresetid = sched_ctrl->coreset->controlResourceSetId; + nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu = gNB_mac->pdcch_pdu_idx[CC_id][bwpid][coresetid]; + if (!pdcch_pdu) { + nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdcch_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs]; + memset(dl_tti_pdcch_pdu, 0, sizeof(nfapi_nr_dl_tti_request_pdu_t)); + dl_tti_pdcch_pdu->PDUType = NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE; + dl_tti_pdcch_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdcch_pdu)); + dl_req->nPDUs += 1; + pdcch_pdu = &dl_tti_pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15; + nr_configure_pdcch(pdcch_pdu, sched_ctrl->search_space, sched_ctrl->coreset, scc, bwp); + gNB_mac->pdcch_pdu_idx[CC_id][bwpid][coresetid] = pdcch_pdu; + } + + nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs]; + memset(dl_tti_pdsch_pdu, 0, sizeof(nfapi_nr_dl_tti_request_pdu_t)); + dl_tti_pdsch_pdu->PDUType = NFAPI_NR_DL_TTI_PDSCH_PDU_TYPE; + dl_tti_pdsch_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdsch_pdu)); + dl_req->nPDUs += 1; + nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu = &dl_tti_pdsch_pdu->pdsch_pdu.pdsch_pdu_rel15; + + pdsch_pdu->pduBitmap = 0; + pdsch_pdu->rnti = rnti; + /* SCF222: PDU index incremented for each PDSCH PDU sent in TX control + * message. This is used to associate control information to data and is + * reset every slot. */ + const int pduindex = gNB_mac->pdu_index[CC_id]++; + pdsch_pdu->pduIndex = pduindex; + + // BWP + pdsch_pdu->BWPSize = NRRIV2BW(bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + pdsch_pdu->BWPStart = NRRIV2PRBOFFSET(bwp->bwp_Common->genericParameters.locationAndBandwidth,MAX_BWP_SIZE); + pdsch_pdu->SubcarrierSpacing = bwp->bwp_Common->genericParameters.subcarrierSpacing; + if (bwp->bwp_Common->genericParameters.cyclicPrefix) + pdsch_pdu->CyclicPrefix = *bwp->bwp_Common->genericParameters.cyclicPrefix; + else + pdsch_pdu->CyclicPrefix = 0; + + // Codeword information + pdsch_pdu->NrOfCodewords = 1; + pdsch_pdu->targetCodeRate[0] = R; + pdsch_pdu->qamModOrder[0] = Qm; + pdsch_pdu->mcsIndex[0] = sched_ctrl->mcs; + pdsch_pdu->mcsTable[0] = sched_ctrl->mcsTableIdx; + pdsch_pdu->rvIndex[0] = nr_rv_round_map[harq->round]; + pdsch_pdu->TBSize[0] = TBS; + + pdsch_pdu->dataScramblingId = *scc->physCellId; + pdsch_pdu->nrOfLayers = nrOfLayers; + pdsch_pdu->transmissionScheme = 0; + pdsch_pdu->refPoint = 0; // Point A + + // DMRS + pdsch_pdu->dlDmrsSymbPos = + fill_dmrs_mask(bwp->bwp_Dedicated->pdsch_Config->choice.setup, + scc->dmrs_TypeA_Position, + nrOfSymbols); + pdsch_pdu->dmrsConfigType = dmrsConfigType; + pdsch_pdu->dlDmrsScramblingId = *scc->physCellId; + pdsch_pdu->SCID = 0; + pdsch_pdu->numDmrsCdmGrpsNoData = sched_ctrl->numDmrsCdmGrpsNoData; + pdsch_pdu->dmrsPorts = 1; + + // Pdsch Allocation in frequency domain + pdsch_pdu->resourceAlloc = 1; + pdsch_pdu->rbStart = sched_ctrl->rbStart; + pdsch_pdu->rbSize = sched_ctrl->rbSize; + pdsch_pdu->VRBtoPRBMapping = 1; // non-interleaved, check if this is ok for initialBWP + + // Resource Allocation in time domain + pdsch_pdu->StartSymbolIndex = startSymbolIndex; + pdsch_pdu->NrOfSymbols = nrOfSymbols; + + /* Check and validate PTRS values */ + struct NR_SetupRelease_PTRS_DownlinkConfig *phaseTrackingRS = + bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS; + if (phaseTrackingRS) { + bool valid_ptrs_setup = set_dl_ptrs_values(phaseTrackingRS->choice.setup, + pdsch_pdu->rbSize, + pdsch_pdu->mcsIndex[0], + pdsch_pdu->mcsTable[0], + &pdsch_pdu->PTRSFreqDensity, + &pdsch_pdu->PTRSTimeDensity, + &pdsch_pdu->PTRSPortIndex, + &pdsch_pdu->nEpreRatioOfPDSCHToPTRS, + &pdsch_pdu->PTRSReOffset, + pdsch_pdu->NrOfSymbols); + if (valid_ptrs_setup) + pdsch_pdu->pduBitmap |= 0x1; // Bit 0: pdschPtrs - Indicates PTRS included (FR2) + } + + /* Fill PDCCH DL DCI PDU */ + nfapi_nr_dl_dci_pdu_t *dci_pdu = &pdcch_pdu->dci_pdu[pdcch_pdu->numDlDci]; + pdcch_pdu->numDlDci++; + dci_pdu->RNTI = rnti; + if (sched_ctrl->coreset->pdcch_DMRS_ScramblingID && + sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_ue_Specific) { + dci_pdu->ScramblingId = *sched_ctrl->coreset->pdcch_DMRS_ScramblingID; + dci_pdu->ScramblingRNTI = rnti; + } else { + dci_pdu->ScramblingId = *scc->physCellId; + dci_pdu->ScramblingRNTI = 0; + } + dci_pdu->AggregationLevel = sched_ctrl->aggregation_level; + dci_pdu->CceIndex = sched_ctrl->cce_index; + dci_pdu->beta_PDCCH_1_0 = 0; + dci_pdu->powerControlOffsetSS = 1; + + /* DCI payload */ + dci_pdu_rel15_t dci_payload; + memset(&dci_payload, 0, sizeof(dci_pdu_rel15_t)); + // bwp indicator + const int n_dl_bwp = UE_info->secondaryCellGroup[UE_id]->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count; + AssertFatal(n_dl_bwp == 1, + "downlinkBWP_ToAddModList has %d BWP!\n", + n_dl_bwp); + // as per table 7.3.1.1.2-1 in 38.212 + dci_payload.bwp_indicator.val = n_dl_bwp < 4 ? bwp->bwp_Id : bwp->bwp_Id - 1; + AssertFatal(bwp->bwp_Dedicated->pdsch_Config->choice.setup->resourceAllocation == NR_PDSCH_Config__resourceAllocation_resourceAllocationType1, + "Only frequency resource allocation type 1 is currently supported\n"); + dci_payload.frequency_domain_assignment.val = + PRBalloc_to_locationandbandwidth0( + pdsch_pdu->rbSize, + pdsch_pdu->rbStart, + pdsch_pdu->BWPSize); + dci_payload.time_domain_assignment.val = sched_ctrl->time_domain_allocation; + dci_payload.mcs = sched_ctrl->mcs; + dci_payload.rv = pdsch_pdu->rvIndex[0]; + dci_payload.harq_pid = current_harq_pid; + dci_payload.ndi = harq->ndi; + dci_payload.dai[0].val = (pucch->dai_c-1)&3; + dci_payload.tpc = sched_ctrl->tpc1; // TPC for PUCCH: table 7.2.1-1 in 38.213 + dci_payload.pucch_resource_indicator = pucch->resource_indicator; + dci_payload.pdsch_to_harq_feedback_timing_indicator.val = pucch->timing_indicator; // PDSCH to HARQ TI + dci_payload.antenna_ports.val = 0; // nb of cdm groups w/o data 1 and dmrs port 0 + dci_payload.dmrs_sequence_initialization.val = pdsch_pdu->SCID; + LOG_D(MAC, + "%4d.%2d DCI type 1 payload: freq_alloc %d (%d,%d,%d), " + "time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d ndi %d rv %d\n", + frame, + slot, + dci_payload.frequency_domain_assignment.val, + pdsch_pdu->rbStart, + pdsch_pdu->rbSize, + pdsch_pdu->BWPSize, + dci_payload.time_domain_assignment.val, + dci_payload.vrb_to_prb_mapping.val, + dci_payload.mcs, + dci_payload.tb_scaling, + dci_payload.ndi, + dci_payload.rv); + + const long f = sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats; + const int dci_format = f ? NR_DL_DCI_FORMAT_1_1 : NR_DL_DCI_FORMAT_1_0; + const int rnti_type = NR_RNTI_C; + + fill_dci_pdu_rel15(scc, + UE_info->secondaryCellGroup[UE_id], + dci_pdu, + &dci_payload, + dci_format, + rnti_type, + pdsch_pdu->BWPSize, + bwp->bwp_Id); + + LOG_D(MAC, + "coreset params: FreqDomainResource %llx, start_symbol %d n_symb %d\n", + (unsigned long long)pdcch_pdu->FreqDomainResource, + pdcch_pdu->StartSymbolIndex, + pdcch_pdu->DurationSymbols); NR_UE_ret_info_t *retInfo = &sched_ctrl->retInfo[current_harq_pid]; if (harq->round != 0) { /* retransmission */ @@ -645,8 +957,9 @@ void nr_schedule_ue_spec(module_id_t module_id, retInfo->mcs, retInfo->numDmrsCdmGrpsNoData); /* we do not have to do anything, since we do not require to get data - * from RLC, encode MAC CEs, or copy data to FAPI structures */ - LOG_W(MAC, + * from RLC or encode MAC CEs. The TX_req structure is filled below + * or copy data to FAPI structures */ + LOG_D(MAC, "%d.%2d DL retransmission UE %d/RNTI %04x HARQ PID %d round %d NDI %d\n", frame, slot, @@ -655,111 +968,121 @@ void nr_schedule_ue_spec(module_id_t module_id, current_harq_pid, harq->round, harq->ndi); + AssertFatal(harq->tb_size == TBS, + "UE %d mismatch between scheduled TBS and buffered TB for HARQ PID %d\n", + UE_id, + current_harq_pid); } else { /* initial transmission */ LOG_D(MAC, "[%s] Initial HARQ transmission in %d.%d\n", __FUNCTION__, frame, slot); - /* reserve space for timing advance of UE if necessary, - * nr_generate_dlsch_pdu() checks for ta_apply and add TA CE if necessary */ - const int ta_len = (sched_ctrl->ta_apply) ? 2 : 0; - - /* Get RLC data */ - int header_length_total = 0; - int header_length_last = 0; - int sdu_length_total = 0; - int num_sdus = 0; - uint16_t sdu_lengths[NB_RB_MAX] = {0}; - uint8_t mac_sdus[MAX_NR_DLSCH_PAYLOAD_BYTES]; - unsigned char sdu_lcids[NB_RB_MAX] = {0}; - const int lcid = DL_SCH_LCID_DTCH; - if (sched_ctrl->num_total_bytes > 0) { - /* this is the data from the RLC we would like to request (e.g., only - * some bytes for first LC and some more from a second one */ - const rlc_buffer_occupancy_t ndata = sched_ctrl->rlc_status[lcid].bytes_in_buffer; - /* this is the maximum data we can transport based on TBS minus headers */ - const int mindata = min(ndata, TBS - ta_len - header_length_total - sdu_length_total - 2 - (ndata >= 256)); - LOG_D(MAC, - "[gNB %d][USER-PLANE DEFAULT DRB] Frame %d : DTCH->DLSCH, Requesting " - "%d bytes from RLC (lcid %d total hdr len %d), TBS: %d \n \n", - module_id, - frame, - mindata, - lcid, - header_length_total, - TBS); - sdu_lengths[num_sdus] = mac_rlc_data_req(module_id, - rnti, - module_id, - frame, - ENB_FLAG_YES, - MBMS_FLAG_NO, - lcid, - mindata, - (char *)&mac_sdus[sdu_length_total], - 0, - 0); + harq->tb_size = TBS; + uint8_t *buf = (uint8_t *) harq->tb; - LOG_D(MAC, - "[gNB %d][USER-PLANE DEFAULT DRB] Got %d bytes for DTCH %d \n", - module_id, - sdu_lengths[num_sdus], - lcid); - - sdu_lcids[num_sdus] = lcid; - sdu_length_total += sdu_lengths[num_sdus]; - header_length_last = 1 + 1 + (sdu_lengths[num_sdus] >= 128); - header_length_total += header_length_last; - num_sdus++; + /* first, write all CEs that might be there */ + int written = nr_write_ce_dlsch_pdu(module_id, + sched_ctrl, + (unsigned char *)buf, + 255, // no drx + NULL); // contention res id + buf += written; + int size = TBS - written; + DevAssert(size >= 0); + + /* next, get RLC data */ + + const int lcid = DL_SCH_LCID_DTCH; + int dlsch_total_bytes = 0; + if (sched_ctrl->num_total_bytes > 0) { + tbs_size_t len = 0; + while (size > 3) { + // we do not know how much data we will get from RLC, i.e., whether it + // will be longer than 256B or not. Therefore, reserve space for long header, then + // fetch data, then fill real length + NR_MAC_SUBHEADER_LONG *header = (NR_MAC_SUBHEADER_LONG *) buf; + buf += 3; + size -= 3; + + /* limit requested number of bytes to what preprocessor specified, or + * such that TBS is full */ + const rlc_buffer_occupancy_t ndata = min(sched_ctrl->rlc_status[lcid].bytes_in_buffer, size); + len = mac_rlc_data_req(module_id, + rnti, + module_id, + frame, + ENB_FLAG_YES, + MBMS_FLAG_NO, + lcid, + ndata, + (char *)buf, + 0, + 0); + + LOG_D(MAC, + "%4d.%2d RNTI %04x: %d bytes from DTCH %d (ndata %d, remaining size %d)\n", + frame, + slot, + rnti, + len, + lcid, + ndata, + size); + if (len == 0) + break; + + header->R = 0; + header->F = 1; + header->LCID = lcid; + header->L1 = (len >> 8) & 0xff; + header->L2 = len & 0xff; + size -= len; + buf += len; + dlsch_total_bytes += len; + } + if (len == 0) { + /* RLC did not have data anymore, mark buffer as unused */ + buf -= 3; + size += 3; + } } else if (get_softmodem_params()->phy_test || get_softmodem_params()->do_ra) { - LOG_D(MAC, "Configuring DL_TX in %d.%d: random data\n", frame, slot); + /* we will need the large header, phy-test typically allocates all + * resources and fills to the last byte below */ + NR_MAC_SUBHEADER_LONG *header = (NR_MAC_SUBHEADER_LONG *) buf; + buf += 3; + size -= 3; + DevAssert(size > 0); + LOG_D(MAC, "Configuring DL_TX in %d.%d: TBS %d with %d B of random data\n", frame, slot, TBS, size); // fill dlsch_buffer with random data - for (int i = 0; i < TBS; i++) - mac_sdus[i] = (unsigned char) (lrand48()&0xff); - sdu_lcids[0] = 0x3f; // DRB - sdu_lengths[0] = TBS - ta_len - 3; - header_length_total += 2 + (sdu_lengths[0] >= 256); - sdu_length_total += sdu_lengths[0]; - num_sdus +=1; + for (int i = 0; i < size; i++) + buf[i] = lrand48() & 0xff; + header->R = 0; + header->F = 1; + header->LCID = DL_SCH_LCID_PADDING; + header->L1 = (size >> 8) & 0xff; + header->L2 = size & 0xff; + size -= size; + buf += size; + dlsch_total_bytes += size; } - UE_info->mac_stats[UE_id].dlsch_total_bytes += TBS; - UE_info->mac_stats[UE_id].lc_bytes_tx[lcid] += sdu_length_total; - - const int post_padding = TBS > header_length_total + sdu_length_total + ta_len; - - const int ntx_req = gNB_mac->TX_req[CC_id].Number_of_PDUs; - nfapi_nr_pdu_t *tx_req = &gNB_mac->TX_req[CC_id].pdu_list[ntx_req]; - /* pointer to directly generate the PDU into the nFAPI structure */ - uint32_t *buf = tx_req->TLVs[0].value.direct; - - const int offset = nr_generate_dlsch_pdu( - module_id, - sched_ctrl, - (unsigned char *)mac_sdus, - (unsigned char *)buf, - num_sdus, // num_sdus - sdu_lengths, - sdu_lcids, - 255, // no drx - NULL, // contention res id - post_padding); - - // Padding: fill remainder of DLSCH with 0 - if (post_padding > 0) { - for (int j = 0; j < TBS - offset; j++) - buf[offset + j] = 0; + // Add padding header and zero rest out if there is space left + if (size > 0) { + NR_MAC_SUBHEADER_FIXED *padding = (NR_MAC_SUBHEADER_FIXED *) buf; + padding->R = 0; + padding->LCID = DL_SCH_LCID_PADDING; + size -= 1; + buf += 1; + while (size > 0) { + *buf = 0; + buf += 1; + size -= 1; + } } - /* the buffer has been filled by nr_generate_dlsch_pdu(), below we simply - * fill the remaining information */ - tx_req->PDU_length = TBS; - tx_req->PDU_index = gNB_mac->pdu_index[0]++; - tx_req->num_TLV = 1; - tx_req->TLVs[0].length = TBS + 2; - gNB_mac->TX_req[CC_id].Number_of_PDUs++; - gNB_mac->TX_req[CC_id].SFN = frame; - gNB_mac->TX_req[CC_id].Slot = slot; + UE_info->mac_stats[UE_id].dlsch_total_bytes += TBS; + UE_info->mac_stats[UE_id].dlsch_current_bytes = TBS; + UE_info->mac_stats[UE_id].lc_bytes_tx[lcid] += dlsch_total_bytes; retInfo->rbSize = sched_ctrl->rbSize; retInfo->time_domain_allocation = sched_ctrl->time_domain_allocation; @@ -779,21 +1102,20 @@ void nr_schedule_ue_spec(module_id_t module_id, } T(T_GNB_MAC_DL_PDU_WITH_DATA, T_INT(module_id), T_INT(CC_id), T_INT(rnti), - T_INT(frame), T_INT(slot), T_INT(current_harq_pid), T_BUFFER(buf, TBS)); - -#if defined(ENABLE_MAC_PAYLOAD_DEBUG) - if (frame%100 == 0) { - LOG_I(MAC, - "%d.%d, first 10 payload bytes, TBS size: %d \n", - frame, - slot, - TBS); - for(int i = 0; i < 10; i++) - LOG_I(MAC, "byte %d: %x\n", i, ((uint8_t *) buf)[i]); - } -#endif + T_INT(frame), T_INT(slot), T_INT(current_harq_pid), T_BUFFER(harq->tb, TBS)); } + const int ntx_req = gNB_mac->TX_req[CC_id].Number_of_PDUs; + nfapi_nr_pdu_t *tx_req = &gNB_mac->TX_req[CC_id].pdu_list[ntx_req]; + tx_req->PDU_length = TBS; + tx_req->PDU_index = pduindex; + tx_req->num_TLV = 1; + tx_req->TLVs[0].length = TBS + 2; + memcpy(tx_req->TLVs[0].value.direct, harq->tb, TBS); + gNB_mac->TX_req[CC_id].Number_of_PDUs++; + gNB_mac->TX_req[CC_id].SFN = frame; + gNB_mac->TX_req[CC_id].Slot = slot; + /* mark UE as scheduled */ sched_ctrl->rbSize = 0; } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index 5707f2c75a74754668d20e155801d713585a1b4f..8dbe8728f3aee9841fd0d22e01c2b695f415dde4 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -255,9 +255,10 @@ void nr_schedule_css_dlsch_phytest(module_id_t module_idP, /* schedules whole bandwidth for first user, all the time */ void nr_preprocessor_phytest(module_id_t module_id, frame_t frame, - sub_frame_t slot, - int num_slots_per_tdd) + sub_frame_t slot) { + if (slot != 1) + return; NR_UE_info_t *UE_info = &RC.nrmac[module_id]->UE_info; const int UE_id = 0; const int CC_id = 0; @@ -328,14 +329,25 @@ void nr_preprocessor_phytest(module_id_t module_id, __func__, UE_id); - nr_acknack_scheduling(module_id, - UE_id, - frame, - slot, - num_slots_per_tdd, - &sched_ctrl->pucch_sched_idx, - &sched_ctrl->pucch_occ_idx); - AssertFatal(sched_ctrl->pucch_sched_idx >= 0, "no uplink slot for PUCCH found!\n"); + const bool alloc = nr_acknack_scheduling(module_id, UE_id, frame, slot); + if (!alloc) { + LOG_D(MAC, + "%s(): could not find PUCCH for UE %d/%04x@%d.%d\n", + __func__, + UE_id, + rnti, + frame, + slot); + UE_info->num_pdcch_cand[UE_id][cid]--; + int *cce_list = RC.nrmac[module_id]->cce_list[sched_ctrl->active_bwp->bwp_Id][cid]; + for (int i = 0; i < sched_ctrl->aggregation_level; i++) + cce_list[sched_ctrl->cce_index + i] = 0; + return; + } + + AssertFatal(alloc, + "could not find uplink slot for PUCCH (RNTI %04x@%d.%d)!\n", + rnti, frame, slot); sched_ctrl->rbStart = rbStart; sched_ctrl->rbSize = rbSize; @@ -350,13 +362,15 @@ void nr_preprocessor_phytest(module_id_t module_id, } sched_ctrl->mcs = 9; sched_ctrl->numDmrsCdmGrpsNoData = 1; + /* get the PID of a HARQ process awaiting retransmission, or -1 otherwise */ + sched_ctrl->dl_harq_pid = sched_ctrl->retrans_dl_harq.head; /* mark the corresponding RBs as used */ for (int rb = 0; rb < sched_ctrl->rbSize; rb++) vrb_map[rb + sched_ctrl->rbStart] = 1; } -void nr_ul_preprocessor_phytest(module_id_t module_id, +bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_t slot, int num_slots_per_tdd, @@ -372,7 +386,7 @@ void nr_ul_preprocessor_phytest(module_id_t module_id, __func__, UE_info->num_UEs); if (UE_info->num_UEs == 0) - return; + return false; const int UE_id = 0; const int CC_id = 0; @@ -387,15 +401,15 @@ void nr_ul_preprocessor_phytest(module_id_t module_id, tda, tdaList->list.count); int K2 = get_K2(sched_ctrl->active_ubwp, tda, mu); - const int sched_frame = frame + (slot + K2 >= num_slots_per_tdd); - const int sched_slot = (slot + K2) % num_slots_per_tdd; + const int sched_frame = frame + (slot + K2 >= nr_slots_per_frame[mu]); + const int sched_slot = (slot + K2) % nr_slots_per_frame[mu]; /* check if slot is UL, and that slot is 8 (assuming K2=6 because of UE * limitations). Note that if K2 or the TDD configuration is changed, below * conditions might exclude each other and never be true */ if (!(is_xlsch_in_slot(ulsch_in_slot_bitmap, sched_slot) && sched_slot == 8)) - return; + return false; - const int bw = NRRIV2BW(sched_ctrl->active_ubwp->bwp_Common->genericParameters.locationAndBandwidth, 275); + const int bw = NRRIV2BW(sched_ctrl->active_ubwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); uint16_t rbStart = 0; uint16_t rbSize = 50; /* due to OAI UE limitations */ if (rbSize>bw) @@ -411,7 +425,7 @@ void nr_ul_preprocessor_phytest(module_id_t module_id, frame, slot, i); - return; + return false; } } @@ -438,7 +452,7 @@ void nr_ul_preprocessor_phytest(module_id_t module_id, nr_of_candidates); if (sched_ctrl->cce_index < 0) { LOG_E(MAC, "%s(): CCE list not empty, couldn't schedule PUSCH\n", __func__); - return; + return false; } UE_info->num_pdcch_cand[UE_id][cid]++; @@ -465,6 +479,8 @@ void nr_ul_preprocessor_phytest(module_id_t module_id, sched_pusch->mcs = mcs; sched_pusch->rbStart = rbStart; sched_pusch->rbSize = rbSize; + /* get the PID of a HARQ process awaiting retransmission, or -1 for "any new" */ + sched_pusch->ul_harq_pid = sched_ctrl->retrans_ul_harq.head; /* Calculate TBS from MCS */ sched_pusch->R = nr_get_code_rate_ul(mcs, ps->mcs_table); @@ -487,4 +503,5 @@ void nr_ul_preprocessor_phytest(module_id_t module_id, /* mark the corresponding RBs as used */ for (int rb = rbStart; rb < rbStart + rbSize; rb++) vrb_map_UL[rb] = 1; + return true; } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 0ef79084ae97c87ac71474a026612b2e4a84bc2a..20da8fa30aaa520b3e44a22549de780c03f0043f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -502,259 +502,34 @@ void nr_configure_css_dci_initial(nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu, } -void nr_fill_nfapi_dl_pdu(int Mod_idP, - nfapi_nr_dl_tti_request_body_t *dl_req, - rnti_t rnti, - NR_CellGroupConfig_t *secondaryCellGroup, - NR_UE_sched_ctrl_t *sched_ctrl, - NR_sched_pucch *pucch_sched, - nfapi_nr_dmrs_type_e dmrsConfigType, - uint16_t R, - uint8_t Qm, - uint32_t TBS, - int StartSymbolIndex, - int NrOfSymbols, - int harq_pid, - int ndi, - int round) { - gNB_MAC_INST *nr_mac = RC.nrmac[Mod_idP]; - NR_COMMON_channels_t *cc = nr_mac->common_channels; - NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - - const int bwp_id = sched_ctrl->active_bwp->bwp_Id; - const int nrOfLayers = 1; - const int mcs = sched_ctrl->mcs; - const int mcs_table_index = sched_ctrl->mcsTableIdx; - bool valid_ptrs_setup = false; - - AssertFatal(secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count == 1, - "downlinkBWP_ToAddModList has %d BWP!\n", - secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count); - NR_BWP_Downlink_t *bwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1]; - - AssertFatal(bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList!=NULL,"searchPsacesToAddModList is null\n"); - AssertFatal(bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.count>0, - "searchPsacesToAddModList is empty\n"); - - nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdcch_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs]; - memset((void*)dl_tti_pdcch_pdu,0,sizeof(nfapi_nr_dl_tti_request_pdu_t)); - dl_tti_pdcch_pdu->PDUType = NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE; - dl_tti_pdcch_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdcch_pdu)); - - nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs+1]; - memset((void*)dl_tti_pdsch_pdu,0,sizeof(nfapi_nr_dl_tti_request_pdu_t)); - dl_tti_pdsch_pdu->PDUType = NFAPI_NR_DL_TTI_PDSCH_PDU_TYPE; - dl_tti_pdsch_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdsch_pdu)); - - nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = &dl_tti_pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15; - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu_rel15 = &dl_tti_pdsch_pdu->pdsch_pdu.pdsch_pdu_rel15; - - - pdsch_pdu_rel15->pduBitmap = 0; - pdsch_pdu_rel15->rnti = rnti; - pdsch_pdu_rel15->pduIndex = nr_mac->pdu_index[0]++; - - // BWP - pdsch_pdu_rel15->BWPSize = NRRIV2BW(bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - pdsch_pdu_rel15->BWPStart = NRRIV2PRBOFFSET(bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - pdsch_pdu_rel15->SubcarrierSpacing = bwp->bwp_Common->genericParameters.subcarrierSpacing; - if (bwp->bwp_Common->genericParameters.cyclicPrefix) - pdsch_pdu_rel15->CyclicPrefix = *bwp->bwp_Common->genericParameters.cyclicPrefix; - else - pdsch_pdu_rel15->CyclicPrefix = 0; - - pdsch_pdu_rel15->NrOfCodewords = 1; - pdsch_pdu_rel15->targetCodeRate[0] = nr_get_code_rate_dl(mcs, mcs_table_index); - pdsch_pdu_rel15->qamModOrder[0] = 2; - pdsch_pdu_rel15->mcsIndex[0] = mcs; - pdsch_pdu_rel15->mcsTable[0] = mcs_table_index; - pdsch_pdu_rel15->rvIndex[0] = nr_rv_round_map[round]; - pdsch_pdu_rel15->dataScramblingId = *scc->physCellId; - pdsch_pdu_rel15->nrOfLayers = nrOfLayers; - pdsch_pdu_rel15->transmissionScheme = 0; - pdsch_pdu_rel15->refPoint = 0; // Point A - pdsch_pdu_rel15->dmrsConfigType = dmrsConfigType; - pdsch_pdu_rel15->dlDmrsScramblingId = *scc->physCellId; - pdsch_pdu_rel15->SCID = 0; - pdsch_pdu_rel15->numDmrsCdmGrpsNoData = sched_ctrl->numDmrsCdmGrpsNoData; - pdsch_pdu_rel15->dmrsPorts = 1; - pdsch_pdu_rel15->resourceAlloc = 1; - pdsch_pdu_rel15->rbStart = sched_ctrl->rbStart; - pdsch_pdu_rel15->rbSize = sched_ctrl->rbSize; - pdsch_pdu_rel15->VRBtoPRBMapping = 1; // non-interleaved, check if this is ok for initialBWP - pdsch_pdu_rel15->targetCodeRate[0] = R; - pdsch_pdu_rel15->qamModOrder[0] = Qm; - pdsch_pdu_rel15->TBSize[0] = TBS; - pdsch_pdu_rel15->mcsTable[0] = sched_ctrl->mcsTableIdx; - pdsch_pdu_rel15->StartSymbolIndex = StartSymbolIndex; - pdsch_pdu_rel15->NrOfSymbols = NrOfSymbols; - - pdsch_pdu_rel15->dlDmrsSymbPos = - fill_dmrs_mask(bwp->bwp_Dedicated->pdsch_Config->choice.setup, - scc->dmrs_TypeA_Position, - pdsch_pdu_rel15->NrOfSymbols); - - /* Check and validate PTRS values */ - if(bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS != NULL) { - valid_ptrs_setup = set_dl_ptrs_values(bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup, - pdsch_pdu_rel15->rbSize, pdsch_pdu_rel15->mcsIndex[0], - pdsch_pdu_rel15->mcsTable[0], - &pdsch_pdu_rel15->PTRSFreqDensity,&pdsch_pdu_rel15->PTRSTimeDensity, - &pdsch_pdu_rel15->PTRSPortIndex,&pdsch_pdu_rel15->nEpreRatioOfPDSCHToPTRS, - &pdsch_pdu_rel15->PTRSReOffset, pdsch_pdu_rel15->NrOfSymbols); - if(valid_ptrs_setup==true) { - pdsch_pdu_rel15->pduBitmap |=0x1; - } - } - - dci_pdu_rel15_t dci_pdu_rel15[MAX_DCI_CORESET]; - memset(dci_pdu_rel15, 0, sizeof(dci_pdu_rel15_t) * MAX_DCI_CORESET); - - // bwp indicator - int n_dl_bwp = secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count; - if (n_dl_bwp < 4) - dci_pdu_rel15[0].bwp_indicator.val = bwp_id; - else - dci_pdu_rel15[0].bwp_indicator.val = bwp_id - 1; // as per table 7.3.1.1.2-1 in 38.212 - // frequency domain assignment - if (bwp->bwp_Dedicated->pdsch_Config->choice.setup->resourceAllocation==NR_PDSCH_Config__resourceAllocation_resourceAllocationType1) - dci_pdu_rel15[0].frequency_domain_assignment.val = - PRBalloc_to_locationandbandwidth0( - pdsch_pdu_rel15->rbSize, - pdsch_pdu_rel15->rbStart, - NRRIV2BW(bwp->bwp_Common->genericParameters.locationAndBandwidth, - MAX_BWP_SIZE)); - else - AssertFatal(1==0,"Only frequency resource allocation type 1 is currently supported\n"); - // time domain assignment: row index used instead of SLIV - dci_pdu_rel15[0].time_domain_assignment.val = sched_ctrl->time_domain_allocation; - // mcs and rv - dci_pdu_rel15[0].mcs = mcs; - dci_pdu_rel15[0].rv = pdsch_pdu_rel15->rvIndex[0]; - // harq pid and ndi - dci_pdu_rel15[0].harq_pid = harq_pid; - dci_pdu_rel15[0].ndi = ndi; - // DAI - dci_pdu_rel15[0].dai[0].val = (pucch_sched->dai_c-1)&3; - - // TPC for PUCCH - dci_pdu_rel15[0].tpc = sched_ctrl->tpc1; // table 7.2.1-1 in 38.213 - // PUCCH resource indicator - dci_pdu_rel15[0].pucch_resource_indicator = pucch_sched->resource_indicator; - // PDSCH to HARQ TI - dci_pdu_rel15[0].pdsch_to_harq_feedback_timing_indicator.val = pucch_sched->timing_indicator; - // antenna ports - dci_pdu_rel15[0].antenna_ports.val = 0; // nb of cdm groups w/o data 1 and dmrs port 0 - // dmrs sequence initialization - dci_pdu_rel15[0].dmrs_sequence_initialization.val = pdsch_pdu_rel15->SCID; - LOG_D(MAC, - "[gNB scheduler phytest] DCI type 1 payload: freq_alloc %d (%d,%d,%d), " - "time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d ndi %d rv %d\n", - dci_pdu_rel15[0].frequency_domain_assignment.val, - pdsch_pdu_rel15->rbStart, - pdsch_pdu_rel15->rbSize, - NRRIV2BW(bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE), - dci_pdu_rel15[0].time_domain_assignment.val, - dci_pdu_rel15[0].vrb_to_prb_mapping.val, - dci_pdu_rel15[0].mcs, - dci_pdu_rel15[0].tb_scaling, - dci_pdu_rel15[0].ndi, - dci_pdu_rel15[0].rv); - - nr_configure_pdcch(nr_mac, - pdcch_pdu_rel15, - rnti, - sched_ctrl->search_space, - sched_ctrl->coreset, - scc, - bwp, - sched_ctrl->aggregation_level, - sched_ctrl->cce_index); - - int dci_formats[2]; - int rnti_types[2]; - - if (sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats) - dci_formats[0] = NR_DL_DCI_FORMAT_1_1; - else - dci_formats[0] = NR_DL_DCI_FORMAT_1_0; - - rnti_types[0] = NR_RNTI_C; - - fill_dci_pdu_rel15(scc,secondaryCellGroup,pdcch_pdu_rel15,dci_pdu_rel15,dci_formats,rnti_types,pdsch_pdu_rel15->BWPSize,bwp_id); - - LOG_D(MAC, - "DCI params: rnti %x, rnti_type %d, dci_format %d\n", - pdcch_pdu_rel15->dci_pdu.RNTI[0], - rnti_types[0], - dci_formats[0]); - LOG_D(MAC, - "coreset params: FreqDomainResource %llx, start_symbol %d n_symb %d\n", - (unsigned long long)pdcch_pdu_rel15->FreqDomainResource, - pdcch_pdu_rel15->StartSymbolIndex, - pdcch_pdu_rel15->DurationSymbols); - - LOG_D(MAC, - "DLSCH PDU: start PRB %d n_PRB %d start symbol %d nb_symbols %d " - "nb_layers %d nb_codewords %d mcs %d TBS: %d\n", - pdsch_pdu_rel15->rbStart, - pdsch_pdu_rel15->rbSize, - pdsch_pdu_rel15->StartSymbolIndex, - pdsch_pdu_rel15->NrOfSymbols, - pdsch_pdu_rel15->nrOfLayers, - pdsch_pdu_rel15->NrOfCodewords, - pdsch_pdu_rel15->mcsIndex[0], - TBS); - - dl_req->nPDUs += 2; -} - -void config_uldci(NR_BWP_Uplink_t *ubwp, - nfapi_nr_pusch_pdu_t *pusch_pdu, - nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15, +void config_uldci(const NR_BWP_Uplink_t *ubwp, + const nfapi_nr_pusch_pdu_t *pusch_pdu, dci_pdu_rel15_t *dci_pdu_rel15, - int *dci_formats, - int time_domain_assignment, uint8_t tpc, - int n_ubwp, int bwp_id) { + int dci_format, + int time_domain_assignment, + uint8_t tpc, + int n_ubwp, + int bwp_id) { const int bw = NRRIV2BW(ubwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - switch (dci_formats[(pdcch_pdu_rel15->numDlDci) - 1]) { + dci_pdu_rel15->frequency_domain_assignment.val = + PRBalloc_to_locationandbandwidth0(pusch_pdu->rb_size, pusch_pdu->rb_start, bw); + dci_pdu_rel15->time_domain_assignment.val = time_domain_assignment; + dci_pdu_rel15->frequency_hopping_flag.val = pusch_pdu->frequency_hopping; + dci_pdu_rel15->mcs = pusch_pdu->mcs_index; + dci_pdu_rel15->ndi = pusch_pdu->pusch_data.new_data_indicator; + dci_pdu_rel15->rv = pusch_pdu->pusch_data.rv_index; + dci_pdu_rel15->harq_pid = pusch_pdu->pusch_data.harq_process_id; + dci_pdu_rel15->tpc = tpc; + AssertFatal(ubwp->bwp_Dedicated->pusch_Config->choice.setup->resourceAllocation == NR_PUSCH_Config__resourceAllocation_resourceAllocationType1, + "Only frequency resource allocation type 1 is currently supported\n"); + switch (dci_format) { case NR_UL_DCI_FORMAT_0_0: - dci_pdu_rel15->frequency_domain_assignment.val = - PRBalloc_to_locationandbandwidth0(pusch_pdu->rb_size, pusch_pdu->rb_start, bw); - - dci_pdu_rel15->time_domain_assignment.val = time_domain_assignment; - dci_pdu_rel15->frequency_hopping_flag.val = pusch_pdu->frequency_hopping; - dci_pdu_rel15->mcs = pusch_pdu->mcs_index; - dci_pdu_rel15->format_indicator = 0; - dci_pdu_rel15->ndi = pusch_pdu->pusch_data.new_data_indicator; - dci_pdu_rel15->rv = pusch_pdu->pusch_data.rv_index; - dci_pdu_rel15->harq_pid = pusch_pdu->pusch_data.harq_process_id; - dci_pdu_rel15->tpc = tpc; break; case NR_UL_DCI_FORMAT_0_1: - dci_pdu_rel15->ndi = pusch_pdu->pusch_data.new_data_indicator; - dci_pdu_rel15->rv = pusch_pdu->pusch_data.rv_index; - dci_pdu_rel15->harq_pid = pusch_pdu->pusch_data.harq_process_id; - dci_pdu_rel15->frequency_hopping_flag.val = pusch_pdu->frequency_hopping; dci_pdu_rel15->dai[0].val = 0; //TODO - // bwp indicator - if (n_ubwp < 4) - dci_pdu_rel15->bwp_indicator.val = bwp_id; - else - dci_pdu_rel15->bwp_indicator.val = bwp_id - 1; // as per table 7.3.1.1.2-1 in 38.212 - // frequency domain assignment - AssertFatal(ubwp->bwp_Dedicated->pusch_Config->choice.setup->resourceAllocation - == NR_PUSCH_Config__resourceAllocation_resourceAllocationType1, - "Only frequency resource allocation type 1 is currently supported\n"); - dci_pdu_rel15->frequency_domain_assignment.val = - PRBalloc_to_locationandbandwidth0(pusch_pdu->rb_size, pusch_pdu->rb_start, bw); - // time domain assignment - dci_pdu_rel15->time_domain_assignment.val = time_domain_assignment; - // mcs - dci_pdu_rel15->mcs = pusch_pdu->mcs_index; - // tpc command for pusch - dci_pdu_rel15->tpc = tpc; + // bwp indicator as per table 7.3.1.1.2-1 in 38.212 + dci_pdu_rel15->bwp_indicator.val = n_ubwp < 4 ? bwp_id : bwp_id - 1; // SRS resource indicator if (ubwp->bwp_Dedicated->pusch_Config->choice.setup->txConfig != NULL) { AssertFatal(*ubwp->bwp_Dedicated->pusch_Config->choice.setup->txConfig == NR_PUSCH_Config__txConfig_codebook, @@ -771,10 +546,8 @@ void config_uldci(NR_BWP_Uplink_t *ubwp, } LOG_D(MAC, - "%s() ULDCI type 0 payload: PDCCH CCEIndex %d, freq_alloc %d, " - "time_alloc %d, freq_hop_flag %d, mcs %d tpc %d ndi %d rv %d\n", + "%s() ULDCI type 0 payload: freq_alloc %d, time_alloc %d, freq_hop_flag %d, mcs %d tpc %d ndi %d rv %d\n", __func__, - pdcch_pdu_rel15->dci_pdu.CceIndex[pdcch_pdu_rel15->numDlDci], dci_pdu_rel15->frequency_domain_assignment.val, dci_pdu_rel15->time_domain_assignment.val, dci_pdu_rel15->frequency_hopping_flag.val, @@ -784,15 +557,12 @@ void config_uldci(NR_BWP_Uplink_t *ubwp, dci_pdu_rel15->rv); } -void nr_configure_pdcch(gNB_MAC_INST *nr_mac, - nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu, - uint16_t rnti, +void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu, NR_SearchSpace_t *ss, NR_ControlResourceSet_t *coreset, NR_ServingCellConfigCommon_t *scc, - NR_BWP_Downlink_t *bwp, - uint8_t aggregation_level, - int CCEIndex) { + NR_BWP_Downlink_t *bwp) +{ if (bwp) { // This is not the InitialBWP pdcch_pdu->BWPSize = NRRIV2BW(bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); pdcch_pdu->BWPStart = NRRIV2PRBOFFSET(bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); @@ -847,27 +617,6 @@ void nr_configure_pdcch(gNB_MAC_INST *nr_mac, //precoderGranularity pdcch_pdu->precoderGranularity = coreset->precoderGranularity; - - pdcch_pdu->dci_pdu.RNTI[pdcch_pdu->numDlDci]=rnti; - - if (coreset->pdcch_DMRS_ScramblingID != NULL && - ss->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_ue_Specific) { - pdcch_pdu->dci_pdu.ScramblingId[pdcch_pdu->numDlDci] = *coreset->pdcch_DMRS_ScramblingID; - pdcch_pdu->dci_pdu.ScramblingRNTI[pdcch_pdu->numDlDci]=rnti; - } - else { - pdcch_pdu->dci_pdu.ScramblingId[pdcch_pdu->numDlDci] = *scc->physCellId; - pdcch_pdu->dci_pdu.ScramblingRNTI[pdcch_pdu->numDlDci]=0; - } - - pdcch_pdu->dci_pdu.AggregationLevel[pdcch_pdu->numDlDci] = aggregation_level; - pdcch_pdu->dci_pdu.CceIndex[pdcch_pdu->numDlDci] = CCEIndex; - - if (ss->searchSpaceType->choice.ue_Specific->dci_Formats==NR_SearchSpace__searchSpaceType__ue_Specific__dci_Formats_formats0_0_And_1_0) - pdcch_pdu->dci_pdu.beta_PDCCH_1_0[pdcch_pdu->numDlDci]=0; - - pdcch_pdu->dci_pdu.powerControlOffsetSS[pdcch_pdu->numDlDci]=1; - pdcch_pdu->numDlDci++; } else { // this is for InitialBWP AssertFatal(1==0,"Fill in InitialBWP PDCCH configuration\n"); @@ -1084,7 +833,7 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, } -void prepare_dci(NR_CellGroupConfig_t *secondaryCellGroup, +void prepare_dci(const NR_CellGroupConfig_t *secondaryCellGroup, dci_pdu_rel15_t *dci_pdu_rel15, nr_dci_format_t format, int bwp_id) { @@ -1160,591 +909,505 @@ void prepare_dci(NR_CellGroupConfig_t *secondaryCellGroup, } -void fill_dci_pdu_rel15(NR_ServingCellConfigCommon_t *scc, - NR_CellGroupConfig_t *secondaryCellGroup, - nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15, +void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, + const NR_CellGroupConfig_t *secondaryCellGroup, + nfapi_nr_dl_dci_pdu_t *pdcch_dci_pdu, dci_pdu_rel15_t *dci_pdu_rel15, - int *dci_formats, - int *rnti_types, + int dci_format, + int rnti_type, int N_RB, int bwp_id) { - - uint8_t fsize=0, pos=0; - - for (int d=0;d<pdcch_pdu_rel15->numDlDci;d++) { - - uint64_t *dci_pdu = (uint64_t *)pdcch_pdu_rel15->dci_pdu.Payload[d]; - int dci_size = nr_dci_size(scc,secondaryCellGroup,&dci_pdu_rel15[d],dci_formats[d],rnti_types[d],N_RB,bwp_id); - pdcch_pdu_rel15->dci_pdu.PayloadSizeBits[d] = dci_size; - AssertFatal(pdcch_pdu_rel15->dci_pdu.PayloadSizeBits[d]<=64, "DCI sizes above 64 bits not yet supported"); - - if(dci_formats[d]==NR_DL_DCI_FORMAT_1_1 || dci_formats[d]==NR_UL_DCI_FORMAT_0_1) - prepare_dci(secondaryCellGroup,&dci_pdu_rel15[d],dci_formats[d],bwp_id); - - /// Payload generation - switch(dci_formats[d]) { - case NR_DL_DCI_FORMAT_1_0: - switch(rnti_types[d]) { - case NR_RNTI_RA: - // Freq domain assignment - fsize = (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) ); - pos=fsize; - *dci_pdu |= (((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val&((1<<fsize)-1)) << (dci_size-pos)); - LOG_D(MAC,"frequency-domain assignment %d (%d bits) N_RB_BWP %d=> %d (0x%lx)\n",dci_pdu_rel15->frequency_domain_assignment.val,fsize,N_RB,dci_size-pos,*dci_pdu); - // Time domain assignment - pos+=4; - *dci_pdu |= (((uint64_t)dci_pdu_rel15->time_domain_assignment.val&0xf) << (dci_size-pos)); - LOG_D(MAC,"time-domain assignment %d (3 bits)=> %d (0x%lx)\n",dci_pdu_rel15->time_domain_assignment.val,dci_size-pos,*dci_pdu); - // VRB to PRB mapping - - pos++; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->vrb_to_prb_mapping.val&0x1)<<(dci_size-pos); - LOG_D(MAC,"vrb to prb mapping %d (1 bits)=> %d (0x%lx)\n",dci_pdu_rel15->vrb_to_prb_mapping.val,dci_size-pos,*dci_pdu); - // MCS - pos+=5; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->mcs&0x1f)<<(dci_size-pos); + uint8_t fsize = 0, pos = 0; + + uint64_t *dci_pdu = (uint64_t *)pdcch_dci_pdu->Payload; + int dci_size = nr_dci_size(scc, secondaryCellGroup, dci_pdu_rel15, dci_format, rnti_type, N_RB, bwp_id); + pdcch_dci_pdu->PayloadSizeBits = dci_size; + AssertFatal(dci_size <= 64, "DCI sizes above 64 bits not yet supported"); + + if (dci_format == NR_DL_DCI_FORMAT_1_1 || dci_format == NR_UL_DCI_FORMAT_0_1) + prepare_dci(secondaryCellGroup, dci_pdu_rel15, dci_format, bwp_id); + + /// Payload generation + switch (dci_format) { + case NR_DL_DCI_FORMAT_1_0: + switch (rnti_type) { + case NR_RNTI_RA: + // Freq domain assignment + fsize = (int)ceil(log2((N_RB * (N_RB + 1)) >> 1)); + pos = fsize; + *dci_pdu |= (((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val & ((1 << fsize) - 1)) << (dci_size - pos)); + LOG_D(MAC, + "frequency-domain assignment %d (%d bits) N_RB_BWP %d=> %d (0x%lx)\n", + dci_pdu_rel15->frequency_domain_assignment.val, + fsize, + N_RB, + dci_size - pos, + *dci_pdu); + // Time domain assignment + pos += 4; + *dci_pdu |= (((uint64_t)dci_pdu_rel15->time_domain_assignment.val & 0xf) << (dci_size - pos)); + LOG_D(MAC, + "time-domain assignment %d (3 bits)=> %d (0x%lx)\n", + dci_pdu_rel15->time_domain_assignment.val, + dci_size - pos, + *dci_pdu); + // VRB to PRB mapping + pos++; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->vrb_to_prb_mapping.val & 0x1) << (dci_size - pos); + LOG_D(MAC, + "vrb to prb mapping %d (1 bits)=> %d (0x%lx)\n", + dci_pdu_rel15->vrb_to_prb_mapping.val, + dci_size - pos, + *dci_pdu); + // MCS + pos += 5; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->mcs & 0x1f) << (dci_size - pos); #ifdef DEBUG_FILL_DCI - LOG_I(MAC,"mcs %d (5 bits)=> %d (0x%lx)\n",dci_pdu_rel15->mcs,dci_size-pos,*dci_pdu); + LOG_I(MAC, "mcs %d (5 bits)=> %d (0x%lx)\n", dci_pdu_rel15->mcs, dci_size - pos, *dci_pdu); #endif - // TB scaling - pos+=2; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->tb_scaling&0x3)<<(dci_size-pos); + // TB scaling + pos += 2; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->tb_scaling & 0x3) << (dci_size - pos); #ifdef DEBUG_FILL_DCI - LOG_I(MAC,"tb_scaling %d (2 bits)=> %d (0x%lx)\n",dci_pdu_rel15->tb_scaling,dci_size-pos,*dci_pdu); + LOG_I(MAC, "tb_scaling %d (2 bits)=> %d (0x%lx)\n", dci_pdu_rel15->tb_scaling, dci_size - pos, *dci_pdu); #endif - break; - - case NR_RNTI_C: - - // indicating a DL DCI format 1bit - pos++; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->format_indicator&1)<<(dci_size-pos); - LOG_D(MAC,"Format indicator %d (%d bits) N_RB_BWP %d => %d (0x%lx)\n",dci_pdu_rel15->format_indicator,1,N_RB,dci_size-pos,*dci_pdu); - - // Freq domain assignment (275rb >> fsize = 16) - fsize = (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) ); - pos+=fsize; - *dci_pdu |= (((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val&((1<<fsize)-1)) << (dci_size-pos)); - - LOG_D(MAC,"Freq domain assignment %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->frequency_domain_assignment.val,fsize,dci_size-pos,*dci_pdu); - - uint16_t is_ra = 1; - for (int i=0; i<fsize; i++) - if (!((dci_pdu_rel15->frequency_domain_assignment.val>>i)&1)) { - is_ra = 0; - break; - } - if (is_ra) //fsize are all 1 38.212 p86 - { - // ra_preamble_index 6 bits - pos+=6; - *dci_pdu |= ((dci_pdu_rel15->ra_preamble_index&0x3f)<<(dci_size-pos)); - - // UL/SUL indicator 1 bit - pos++; - *dci_pdu |= (dci_pdu_rel15->ul_sul_indicator.val&1)<<(dci_size-pos); - - // SS/PBCH index 6 bits - pos+=6; - *dci_pdu |= ((dci_pdu_rel15->ss_pbch_index&0x3f)<<(dci_size-pos)); - - // prach_mask_index 4 bits - pos+=4; - *dci_pdu |= ((dci_pdu_rel15->prach_mask_index&0xf)<<(dci_size-pos)); - - } //end if - - else { - - // Time domain assignment 4bit - - pos+=4; - *dci_pdu |= ((dci_pdu_rel15->time_domain_assignment.val&0xf) << (dci_size-pos)); - LOG_D(MAC,"Time domain assignment %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->time_domain_assignment.val,4,dci_size-pos,*dci_pdu); - - // VRB to PRB mapping 1bit - pos++; - *dci_pdu |= (dci_pdu_rel15->vrb_to_prb_mapping.val&1)<<(dci_size-pos); - LOG_D(MAC,"VRB to PRB %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->vrb_to_prb_mapping.val,1,dci_size-pos,*dci_pdu); - - // MCS 5bit //bit over 32, so dci_pdu ++ - pos+=5; - *dci_pdu |= (dci_pdu_rel15->mcs&0x1f)<<(dci_size-pos); - LOG_D(MAC,"MCS %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->mcs,5,dci_size-pos,*dci_pdu); - - // New data indicator 1bit - pos++; - *dci_pdu |= (dci_pdu_rel15->ndi&1)<<(dci_size-pos); - LOG_D(MAC,"NDI %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->ndi,1,dci_size-pos,*dci_pdu); - - // Redundancy version 2bit - pos+=2; - *dci_pdu |= (dci_pdu_rel15->rv&0x3)<<(dci_size-pos); - LOG_D(MAC,"RV %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->rv,2,dci_size-pos,*dci_pdu); - - // HARQ process number 4bit - pos+=4; - *dci_pdu |= ((dci_pdu_rel15->harq_pid&0xf)<<(dci_size-pos)); - LOG_D(MAC,"HARQ_PID %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->harq_pid,4,dci_size-pos,*dci_pdu); - - // Downlink assignment index 2bit - pos+=2; - *dci_pdu |= ((dci_pdu_rel15->dai[0].val&3)<<(dci_size-pos)); - LOG_D(MAC,"DAI %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->dai[0].val,2,dci_size-pos,*dci_pdu); - - // TPC command for scheduled PUCCH 2bit - pos+=2; - *dci_pdu |= ((dci_pdu_rel15->tpc&3)<<(dci_size-pos)); - LOG_D(MAC,"TPC %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->tpc,2,dci_size-pos,*dci_pdu); - - // PUCCH resource indicator 3bit - pos+=3; - *dci_pdu |= ((dci_pdu_rel15->pucch_resource_indicator&0x7)<<(dci_size-pos)); - LOG_D(MAC,"PUCCH RI %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->pucch_resource_indicator,3,dci_size-pos,*dci_pdu); - - // PDSCH-to-HARQ_feedback timing indicator 3bit - pos+=3; - *dci_pdu |= ((dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.val&0x7)<<(dci_size-pos)); - LOG_D(MAC,"PDSCH to HARQ TI %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.val,3,dci_size-pos,*dci_pdu); - - } //end else - break; - - case NR_RNTI_P: - - // Short Messages Indicator – 2 bits - for (int i=0; i<2; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->short_messages_indicator>>(1-i))&1)<<(dci_size-pos++); - // Short Messages – 8 bits - for (int i=0; i<8; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->short_messages>>(7-i))&1)<<(dci_size-pos++); - // Freq domain assignment 0-16 bit - fsize = (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) ); - for (int i=0; i<fsize; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val>>(fsize-i-1))&1)<<(dci_size-pos++); - // Time domain assignment 4 bit - for (int i=0; i<4; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->time_domain_assignment.val>>(3-i))&1)<<(dci_size-pos++); - // VRB to PRB mapping 1 bit - *dci_pdu |= ((uint64_t)dci_pdu_rel15->vrb_to_prb_mapping.val&1)<<(dci_size-pos++); - // MCS 5 bit - for (int i=0; i<5; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->mcs>>(4-i))&1)<<(dci_size-pos++); - - // TB scaling 2 bit - for (int i=0; i<2; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->tb_scaling>>(1-i))&1)<<(dci_size-pos++); - - - break; - - case NR_RNTI_SI: - pos=1; - - // Freq domain assignment 0-16 bit - fsize = (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) ); - for (int i=0; i<fsize; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val>>(fsize-1-i))&1)<<(dci_size-pos++); - - // Time domain assignment 4 bit - for (int i=0; i<4; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->time_domain_assignment.val>>(3-i))&1)<<(dci_size-pos++); - - // VRB to PRB mapping 1 bit - *dci_pdu |= ((uint64_t)dci_pdu_rel15->vrb_to_prb_mapping.val&1)<<(dci_size-pos++); + break; + case NR_RNTI_C: + // indicating a DL DCI format 1bit + pos++; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->format_indicator & 1) << (dci_size - pos); + LOG_D(MAC, + "Format indicator %d (%d bits) N_RB_BWP %d => %d (0x%lx)\n", + dci_pdu_rel15->format_indicator, + 1, + N_RB, + dci_size - pos, + *dci_pdu); + // Freq domain assignment (275rb >> fsize = 16) + fsize = (int)ceil(log2((N_RB * (N_RB + 1)) >> 1)); + pos += fsize; + *dci_pdu |= (((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val & ((1 << fsize) - 1)) << (dci_size - pos)); + LOG_D(MAC, + "Freq domain assignment %d (%d bits)=> %d (0x%lx)\n", + dci_pdu_rel15->frequency_domain_assignment.val, + fsize, + dci_size - pos, + *dci_pdu); + uint16_t is_ra = 1; + for (int i = 0; i < fsize; i++) { + if (!((dci_pdu_rel15->frequency_domain_assignment.val >> i) & 1)) { + is_ra = 0; + break; + } + } + if (is_ra) { // fsize are all 1 38.212 p86 + // ra_preamble_index 6 bits + pos += 6; + *dci_pdu |= ((dci_pdu_rel15->ra_preamble_index & 0x3f) << (dci_size - pos)); + // UL/SUL indicator 1 bit + pos++; + *dci_pdu |= (dci_pdu_rel15->ul_sul_indicator.val & 1) << (dci_size - pos); + // SS/PBCH index 6 bits + pos += 6; + *dci_pdu |= ((dci_pdu_rel15->ss_pbch_index & 0x3f) << (dci_size - pos)); + // prach_mask_index 4 bits + pos += 4; + *dci_pdu |= ((dci_pdu_rel15->prach_mask_index & 0xf) << (dci_size - pos)); + } else { + // Time domain assignment 4bit + pos += 4; + *dci_pdu |= ((dci_pdu_rel15->time_domain_assignment.val & 0xf) << (dci_size - pos)); + LOG_D(MAC, + "Time domain assignment %d (%d bits)=> %d (0x%lx)\n", + dci_pdu_rel15->time_domain_assignment.val, + 4, + dci_size - pos, + *dci_pdu); + // VRB to PRB mapping 1bit + pos++; + *dci_pdu |= (dci_pdu_rel15->vrb_to_prb_mapping.val & 1) << (dci_size - pos); + LOG_D(MAC, + "VRB to PRB %d (%d bits)=> %d (0x%lx)\n", + dci_pdu_rel15->vrb_to_prb_mapping.val, + 1, + dci_size - pos, + *dci_pdu); // MCS 5bit //bit over 32, so dci_pdu ++ - for (int i=0; i<5; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->mcs>>(4-i))&1)<<(dci_size-pos++); - - // Redundancy version 2 bit - for (int i=0; i<2; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->rv>>(1-i))&1)<<(dci_size-pos++); - - // System information indicator 1bit - *dci_pdu |= ((uint64_t)dci_pdu_rel15->system_info_indicator&1)<<(dci_size-pos++); + pos += 5; + *dci_pdu |= (dci_pdu_rel15->mcs & 0x1f) << (dci_size - pos); + LOG_D(MAC, "MCS %d (%d bits)=> %d (0x%lx)\n", dci_pdu_rel15->mcs, 5, dci_size - pos, *dci_pdu); + // New data indicator 1bit + pos++; + *dci_pdu |= (dci_pdu_rel15->ndi & 1) << (dci_size - pos); + LOG_D(MAC, "NDI %d (%d bits)=> %d (0x%lx)\n", dci_pdu_rel15->ndi, 1, dci_size - pos, *dci_pdu); + // Redundancy version 2bit + pos += 2; + *dci_pdu |= (dci_pdu_rel15->rv & 0x3) << (dci_size - pos); + LOG_D(MAC, "RV %d (%d bits)=> %d (0x%lx)\n", dci_pdu_rel15->rv, 2, dci_size - pos, *dci_pdu); + // HARQ process number 4bit + pos += 4; + *dci_pdu |= ((dci_pdu_rel15->harq_pid & 0xf) << (dci_size - pos)); + LOG_D(MAC, "HARQ_PID %d (%d bits)=> %d (0x%lx)\n", dci_pdu_rel15->harq_pid, 4, dci_size - pos, *dci_pdu); + // Downlink assignment index 2bit + pos += 2; + *dci_pdu |= ((dci_pdu_rel15->dai[0].val & 3) << (dci_size - pos)); + LOG_D(MAC, "DAI %d (%d bits)=> %d (0x%lx)\n", dci_pdu_rel15->dai[0].val, 2, dci_size - pos, *dci_pdu); + // TPC command for scheduled PUCCH 2bit + pos += 2; + *dci_pdu |= ((dci_pdu_rel15->tpc & 3) << (dci_size - pos)); + LOG_D(MAC, "TPC %d (%d bits)=> %d (0x%lx)\n", dci_pdu_rel15->tpc, 2, dci_size - pos, *dci_pdu); + // PUCCH resource indicator 3bit + pos += 3; + *dci_pdu |= ((dci_pdu_rel15->pucch_resource_indicator & 0x7) << (dci_size - pos)); + LOG_D(MAC, + "PUCCH RI %d (%d bits)=> %d (0x%lx)\n", + dci_pdu_rel15->pucch_resource_indicator, + 3, + dci_size - pos, + *dci_pdu); + // PDSCH-to-HARQ_feedback timing indicator 3bit + pos += 3; + *dci_pdu |= ((dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.val & 0x7) << (dci_size - pos)); + LOG_D(MAC, + "PDSCH to HARQ TI %d (%d bits)=> %d (0x%lx)\n", + dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.val, + 3, + dci_size - pos, + *dci_pdu); + } // end else + break; - // reserved 15 bits + case NR_RNTI_P: + // Short Messages Indicator – 2 bits + for (int i = 0; i < 2; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->short_messages_indicator >> (1 - i)) & 1) << (dci_size - pos++); + // Short Messages – 8 bits + for (int i = 0; i < 8; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->short_messages >> (7 - i)) & 1) << (dci_size - pos++); + // Freq domain assignment 0-16 bit + fsize = (int)ceil(log2((N_RB * (N_RB + 1)) >> 1)); + for (int i = 0; i < fsize; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val >> (fsize - i - 1)) & 1) << (dci_size - pos++); + // Time domain assignment 4 bit + for (int i = 0; i < 4; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->time_domain_assignment.val >> (3 - i)) & 1) << (dci_size - pos++); + // VRB to PRB mapping 1 bit + *dci_pdu |= ((uint64_t)dci_pdu_rel15->vrb_to_prb_mapping.val & 1) << (dci_size - pos++); + // MCS 5 bit + for (int i = 0; i < 5; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->mcs >> (4 - i)) & 1) << (dci_size - pos++); + // TB scaling 2 bit + for (int i = 0; i < 2; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->tb_scaling >> (1 - i)) & 1) << (dci_size - pos++); + break; - LOG_D(PHY,"dci_size = %i\n", dci_size); - LOG_D(PHY,"fsize = %i\n", fsize); - LOG_D(PHY,"dci_pdu_rel15->frequency_domain_assignment.val = %i\n", dci_pdu_rel15->frequency_domain_assignment.val); - LOG_D(PHY,"dci_pdu_rel15->time_domain_assignment.val = %i\n", dci_pdu_rel15->time_domain_assignment.val); - LOG_D(PHY,"dci_pdu_rel15->vrb_to_prb_mapping.val = %i\n", dci_pdu_rel15->vrb_to_prb_mapping.val); - LOG_D(PHY,"dci_pdu_rel15->mcs = %i\n", dci_pdu_rel15->mcs); - LOG_D(PHY,"dci_pdu_rel15->rv = %i\n", dci_pdu_rel15->rv); - LOG_D(PHY,"dci_pdu_rel15->system_info_indicator = %i\n", dci_pdu_rel15->system_info_indicator); + case NR_RNTI_SI: + pos = 1; + // Freq domain assignment 0-16 bit + fsize = (int)ceil(log2((N_RB * (N_RB + 1)) >> 1)); + LOG_D(PHY, "fsize = %i\n", fsize); + for (int i = 0; i < fsize; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val >> (fsize - i - 1)) & 1) << (dci_size - pos++); + LOG_D(PHY, "dci_pdu_rel15->frequency_domain_assignment.val = %i\n", dci_pdu_rel15->frequency_domain_assignment.val); + // Time domain assignment 4 bit + for (int i = 0; i < 4; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->time_domain_assignment.val >> (3 - i)) & 1) << (dci_size - pos++); + LOG_D(PHY, "dci_pdu_rel15->time_domain_assignment.val = %i\n", dci_pdu_rel15->time_domain_assignment.val); + // VRB to PRB mapping 1 bit + *dci_pdu |= ((uint64_t)dci_pdu_rel15->vrb_to_prb_mapping.val & 1) << (dci_size - pos++); + LOG_D(PHY, "dci_pdu_rel15->vrb_to_prb_mapping.val = %i\n", dci_pdu_rel15->vrb_to_prb_mapping.val); + // MCS 5bit //bit over 32, so dci_pdu ++ + for (int i = 0; i < 5; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->mcs >> (4 - i)) & 1) << (dci_size - pos++); + LOG_D(PHY, "dci_pdu_rel15->mcs = %i\n", dci_pdu_rel15->mcs); + // Redundancy version 2bit + for (int i = 0; i < 2; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->rv >> (1 - i)) & 1) << (dci_size - pos++); + LOG_D(PHY, "dci_pdu_rel15->rv = %i\n", dci_pdu_rel15->rv); + // System information indicator 1bit + *dci_pdu |= ((uint64_t)dci_pdu_rel15->system_info_indicator&1)<<(dci_size-pos++); + LOG_D(PHY, "dci_pdu_rel15->system_info_indicator = %i\n", dci_pdu_rel15->system_info_indicator); + break; - break; - - case NR_RNTI_TC: - // indicating a DL DCI format 1bit - *dci_pdu |= ((uint64_t)dci_pdu_rel15->format_indicator&1)<<(dci_size-pos++); - // Freq domain assignment 0-16 bit - fsize = (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) ); - for (int i=0; i<fsize; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val>>(fsize-i-1))&1)<<(dci_size-pos++); - // Time domain assignment 4 bit - for (int i=0; i<4; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->time_domain_assignment.val>>(3-i))&1)<<(dci_size-pos++); - // VRB to PRB mapping 1 bit - *dci_pdu |= ((uint64_t)dci_pdu_rel15->vrb_to_prb_mapping.val&1)<<(dci_size-pos++); - // MCS 5bit //bit over 32, so dci_pdu ++ - for (int i=0; i<5; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->mcs>>(4-i))&1)<<(dci_size-pos++); - // New data indicator 1bit - *dci_pdu |= ((uint64_t)dci_pdu_rel15->ndi&1)<<(dci_size-pos++); - // Redundancy version 2bit - for (int i=0; i<2; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->rv>>(1-i))&1)<<(dci_size-pos++); - // HARQ process number 4bit - for (int i=0; i<4; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->harq_pid>>(3-i))&1)<<(dci_size-pos++); - - // Downlink assignment index – 2 bits - for (int i=0; i<2; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->dai[0].val>>(1-i))&1)<<(dci_size-pos++); - - // TPC command for scheduled PUCCH – 2 bits - for (int i=0; i<2; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->tpc>>(1-i))&1)<<(dci_size-pos++); - - - // LOG_D(MAC, "DCI PDU: [0]->0x%08llx \t [1]->0x%08llx \t [2]->0x%08llx \t [3]->0x%08llx\n", - // dci_pdu[0], dci_pdu[1], dci_pdu[2], dci_pdu[3]); - - - // PDSCH-to-HARQ_feedback timing indicator – 3 bits - for (int i=0; i<3; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.val>>(2-i))&1)<<(dci_size-pos++); - - break; - } + case NR_RNTI_TC: + // indicating a DL DCI format 1bit + *dci_pdu |= ((uint64_t)dci_pdu_rel15->format_indicator & 1) << (dci_size - pos++); + // Freq domain assignment 0-16 bit + fsize = (int)ceil(log2((N_RB * (N_RB + 1)) >> 1)); + for (int i = 0; i < fsize; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val >> (fsize - i - 1)) & 1) << (dci_size - pos++); + // Time domain assignment 4 bit + for (int i = 0; i < 4; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->time_domain_assignment.val >> (3 - i)) & 1) << (dci_size - pos++); + // VRB to PRB mapping 1 bit + *dci_pdu |= ((uint64_t)dci_pdu_rel15->vrb_to_prb_mapping.val & 1) << (dci_size - pos++); + // MCS 5bit //bit over 32, so dci_pdu ++ + for (int i = 0; i < 5; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->mcs >> (4 - i)) & 1) << (dci_size - pos++); + // New data indicator 1bit + *dci_pdu |= ((uint64_t)dci_pdu_rel15->ndi & 1) << (dci_size - pos++); + // Redundancy version 2bit + for (int i = 0; i < 2; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->rv >> (1 - i)) & 1) << (dci_size - pos++); + // HARQ process number 4bit + for (int i = 0; i < 4; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->harq_pid >> (3 - i)) & 1) << (dci_size - pos++); + // Downlink assignment index – 2 bits + for (int i = 0; i < 2; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->dai[0].val >> (1 - i)) & 1) << (dci_size - pos++); + // TPC command for scheduled PUCCH – 2 bits + for (int i = 0; i < 2; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->tpc >> (1 - i)) & 1) << (dci_size - pos++); + // PDSCH-to-HARQ_feedback timing indicator – 3 bits + for (int i = 0; i < 3; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.val >> (2 - i)) & 1) << (dci_size - pos++); break; - - case NR_UL_DCI_FORMAT_0_0: - switch(rnti_types[d]) - { - case NR_RNTI_C: - // indicating a DL DCI format 1bit - *dci_pdu |= ((uint64_t)dci_pdu_rel15->format_indicator&1)<<(dci_size-pos++); - // Freq domain assignment max 16 bit - fsize = (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) ); - for (int i=0; i<fsize; i++) - *dci_pdu |= ((dci_pdu_rel15->frequency_domain_assignment.val>>(fsize-i-1))&1)<<(dci_size-pos++); - // Time domain assignment 4bit - for (int i=0; i<4; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->time_domain_assignment.val>>(3-i))&1)<<(dci_size-pos++); - // Frequency hopping flag – 1 bit - *dci_pdu |= ((uint64_t)dci_pdu_rel15->frequency_hopping_flag.val&1)<<(dci_size-pos++); - // MCS 5 bit - for (int i=0; i<5; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->mcs>>(4-i))&1)<<(dci_size-pos++); - // New data indicator 1bit - *dci_pdu |= ((uint64_t)dci_pdu_rel15->ndi&1)<<(dci_size-pos++); - // Redundancy version 2bit - for (int i=0; i<2; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->rv>>(1-i))&1)<<(dci_size-pos++); - // HARQ process number 4bit - for (int i=0; i<4; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->harq_pid>>(3-i))&1)<<(dci_size-pos++); - - // TPC command for scheduled PUSCH – 2 bits - for (int i=0; i<2; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->tpc>>(1-i))&1)<<(dci_size-pos++); - - // Padding bits - for(int a = pos;a<32;a++) - *dci_pdu |= ((uint64_t)dci_pdu_rel15->padding&1)<<(dci_size-pos++); - - // UL/SUL indicator – 1 bit - /* commented for now (RK): need to get this from BWP descriptor - if (cfg->pucch_config.pucch_GroupHopping.value) - *dci_pdu |= ((uint64_t)dci_pdu_rel15->ul_sul_indicator.val&1)<<(dci_size-pos++); - */ - break; - - case NFAPI_NR_RNTI_TC: - - // indicating a DL DCI format 1bit - *dci_pdu |= (dci_pdu_rel15->format_indicator&1)<<(dci_size-pos++); - // Freq domain assignment max 16 bit - fsize = (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) ); - for (int i=0; i<fsize; i++) - *dci_pdu |= ((dci_pdu_rel15->frequency_domain_assignment.val>>(fsize-i-1))&1)<<(dci_size-pos++); - // Time domain assignment 4bit - for (int i=0; i<4; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->time_domain_assignment.val>>(3-i))&1)<<(dci_size-pos++); - // Frequency hopping flag – 1 bit - *dci_pdu |= ((uint64_t)dci_pdu_rel15->frequency_hopping_flag.val&1)<<(dci_size-pos++); - // MCS 5 bit - for (int i=0; i<5; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->mcs>>(4-i))&1)<<(dci_size-pos++); - // New data indicator 1bit - *dci_pdu |= ((uint64_t)dci_pdu_rel15->ndi&1)<<(dci_size-pos++); - // Redundancy version 2bit - for (int i=0; i<2; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->rv>>(1-i))&1)<<(dci_size-pos++); - // HARQ process number 4bit - for (int i=0; i<4; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->harq_pid>>(3-i))&1)<<(dci_size-pos++); - - // TPC command for scheduled PUSCH – 2 bits - for (int i=0; i<2; i++) - *dci_pdu |= (((uint64_t)dci_pdu_rel15->tpc>>(1-i))&1)<<(dci_size-pos++); - - // Padding bits - for(int a = pos;a<32;a++) - *dci_pdu |= ((uint64_t)dci_pdu_rel15->padding&1)<<(dci_size-pos++); - - // UL/SUL indicator – 1 bit - /* - commented for now (RK): need to get this information from BWP descriptor - if (cfg->pucch_config.pucch_GroupHopping.value) - *dci_pdu |= ((uint64_t)dci_pdu_rel15->ul_sul_indicator.val&1)<<(dci_size-pos++); - */ - break; - - } + } + break; + + case NR_UL_DCI_FORMAT_0_0: + switch (rnti_type) { + case NR_RNTI_C: + // indicating a DL DCI format 1bit + *dci_pdu |= ((uint64_t)dci_pdu_rel15->format_indicator & 1) << (dci_size - pos++); + // Freq domain assignment max 16 bit + fsize = (int)ceil(log2((N_RB * (N_RB + 1)) >> 1)); + for (int i = 0; i < fsize; i++) + *dci_pdu |= ((dci_pdu_rel15->frequency_domain_assignment.val >> (fsize - i - 1)) & 1) << (dci_size - pos++); + // Time domain assignment 4bit + for (int i = 0; i < 4; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->time_domain_assignment.val >> (3 - i)) & 1) << (dci_size - pos++); + // Frequency hopping flag – 1 bit + *dci_pdu |= ((uint64_t)dci_pdu_rel15->frequency_hopping_flag.val & 1) << (dci_size - pos++); + // MCS 5 bit + for (int i = 0; i < 5; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->mcs >> (4 - i)) & 1) << (dci_size - pos++); + // New data indicator 1bit + *dci_pdu |= ((uint64_t)dci_pdu_rel15->ndi & 1) << (dci_size - pos++); + // Redundancy version 2bit + for (int i = 0; i < 2; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->rv >> (1 - i)) & 1) << (dci_size - pos++); + // HARQ process number 4bit + for (int i = 0; i < 4; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->harq_pid >> (3 - i)) & 1) << (dci_size - pos++); + // TPC command for scheduled PUSCH – 2 bits + for (int i = 0; i < 2; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->tpc >> (1 - i)) & 1) << (dci_size - pos++); + // Padding bits + for (int a = pos; a < 32; a++) + *dci_pdu |= ((uint64_t)dci_pdu_rel15->padding & 1) << (dci_size - pos++); + // UL/SUL indicator – 1 bit + /* commented for now (RK): need to get this from BWP descriptor + if (cfg->pucch_config.pucch_GroupHopping.value) + *dci_pdu |= + ((uint64_t)dci_pdu_rel15->ul_sul_indicator.val&1)<<(dci_size-pos++); + */ break; - case NR_UL_DCI_FORMAT_0_1: - switch(rnti_types[d]) - { - case NR_RNTI_C: - // Indicating a DL DCI format 1bit - pos=1; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->format_indicator&0x1)<<(dci_size-pos); - - // Carrier indicator - pos+=dci_pdu_rel15->carrier_indicator.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->carrier_indicator.val&((1<<dci_pdu_rel15->carrier_indicator.nbits)-1))<<(dci_size-pos); - - // UL/SUL Indicator - pos+=dci_pdu_rel15->ul_sul_indicator.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->ul_sul_indicator.val&((1<<dci_pdu_rel15->ul_sul_indicator.nbits)-1))<<(dci_size-pos); - - // BWP indicator - pos+=dci_pdu_rel15->bwp_indicator.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->bwp_indicator.val&((1<<dci_pdu_rel15->bwp_indicator.nbits)-1))<<(dci_size-pos); - - // Frequency domain resource assignment - pos+=dci_pdu_rel15->frequency_domain_assignment.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val&((1<<dci_pdu_rel15->frequency_domain_assignment.nbits)-1)) << (dci_size-pos); - - // Time domain resource assignment - pos+=dci_pdu_rel15->time_domain_assignment.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->time_domain_assignment.val&((1<<dci_pdu_rel15->time_domain_assignment.nbits)-1)) << (dci_size-pos); - - // Frequency hopping - pos+=dci_pdu_rel15->frequency_hopping_flag.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->frequency_hopping_flag.val&((1<<dci_pdu_rel15->frequency_hopping_flag.nbits)-1)) << (dci_size-pos); - - // MCS 5bit - pos+=5; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->mcs&0x1f)<<(dci_size-pos); - - // New data indicator 1bit - pos+=1; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->ndi&0x1)<<(dci_size-pos); - - // Redundancy version 2bit - pos+=2; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->rv&0x3)<<(dci_size-pos); - - // HARQ process number 4bit - pos+=4; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->harq_pid&0xf)<<(dci_size-pos); - - // 1st Downlink assignment index - pos+=dci_pdu_rel15->dai[0].nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->dai[0].val&((1<<dci_pdu_rel15->dai[0].nbits)-1))<<(dci_size-pos); - - // 2nd Downlink assignment index - pos+=dci_pdu_rel15->dai[1].nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->dai[1].val&((1<<dci_pdu_rel15->dai[1].nbits)-1))<<(dci_size-pos); - - // TPC command for scheduled PUSCH 2bit - pos+=2; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->tpc&0x3)<<(dci_size-pos); - - // SRS resource indicator - pos+=dci_pdu_rel15->srs_resource_indicator.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->srs_resource_indicator.val&((1<<dci_pdu_rel15->srs_resource_indicator.nbits)-1))<<(dci_size-pos); - - // Precoding info and n. of layers - pos+=dci_pdu_rel15->precoding_information.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->precoding_information.val&((1<<dci_pdu_rel15->precoding_information.nbits)-1))<<(dci_size-pos); - - // Antenna ports - pos+=dci_pdu_rel15->antenna_ports.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->antenna_ports.val&((1<<dci_pdu_rel15->antenna_ports.nbits)-1))<<(dci_size-pos); - - // SRS request - pos+=dci_pdu_rel15->srs_request.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->srs_request.val&((1<<dci_pdu_rel15->srs_request.nbits)-1))<<(dci_size-pos); - - // CSI request - pos+=dci_pdu_rel15->csi_request.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->csi_request.val&((1<<dci_pdu_rel15->csi_request.nbits)-1))<<(dci_size-pos); - - // CBG transmission information - pos+=dci_pdu_rel15->cbgti.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->cbgti.val&((1<<dci_pdu_rel15->cbgti.nbits)-1))<<(dci_size-pos); - - // PTRS DMRS association - pos+=dci_pdu_rel15->ptrs_dmrs_association.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->ptrs_dmrs_association.val&((1<<dci_pdu_rel15->ptrs_dmrs_association.nbits)-1))<<(dci_size-pos); - - // Beta offset indicator - pos+=dci_pdu_rel15->beta_offset_indicator.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->beta_offset_indicator.val&((1<<dci_pdu_rel15->beta_offset_indicator.nbits)-1))<<(dci_size-pos); - - // DMRS sequence initialization - pos+=dci_pdu_rel15->dmrs_sequence_initialization.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->dmrs_sequence_initialization.val&((1<<dci_pdu_rel15->dmrs_sequence_initialization.nbits)-1))<<(dci_size-pos); - - // UL-SCH indicator - pos+=1; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->ulsch_indicator&0x1)<<(dci_size-pos); - - break; - } + case NFAPI_NR_RNTI_TC: + // indicating a DL DCI format 1bit + *dci_pdu |= (dci_pdu_rel15->format_indicator & 1) << (dci_size - pos++); + // Freq domain assignment max 16 bit + fsize = (int)ceil(log2((N_RB * (N_RB + 1)) >> 1)); + for (int i = 0; i < fsize; i++) + *dci_pdu |= ((dci_pdu_rel15->frequency_domain_assignment.val >> (fsize - i - 1)) & 1) << (dci_size - pos++); + // Time domain assignment 4bit + for (int i = 0; i < 4; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->time_domain_assignment.val >> (3 - i)) & 1) << (dci_size - pos++); + // Frequency hopping flag – 1 bit + *dci_pdu |= ((uint64_t)dci_pdu_rel15->frequency_hopping_flag.val & 1) << (dci_size - pos++); + // MCS 5 bit + for (int i = 0; i < 5; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->mcs >> (4 - i)) & 1) << (dci_size - pos++); + // New data indicator 1bit + *dci_pdu |= ((uint64_t)dci_pdu_rel15->ndi & 1) << (dci_size - pos++); + // Redundancy version 2bit + for (int i = 0; i < 2; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->rv >> (1 - i)) & 1) << (dci_size - pos++); + // HARQ process number 4bit + for (int i = 0; i < 4; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->harq_pid >> (3 - i)) & 1) << (dci_size - pos++); + // TPC command for scheduled PUSCH – 2 bits + for (int i = 0; i < 2; i++) + *dci_pdu |= (((uint64_t)dci_pdu_rel15->tpc >> (1 - i)) & 1) << (dci_size - pos++); + // Padding bits + for (int a = pos; a < 32; a++) + *dci_pdu |= ((uint64_t)dci_pdu_rel15->padding & 1) << (dci_size - pos++); + // UL/SUL indicator – 1 bit + /* + commented for now (RK): need to get this information from BWP descriptor + if (cfg->pucch_config.pucch_GroupHopping.value) + *dci_pdu |= + ((uint64_t)dci_pdu_rel15->ul_sul_indicator.val&1)<<(dci_size-pos++); + */ break; + } + break; - case NR_DL_DCI_FORMAT_1_1: + case NR_UL_DCI_FORMAT_0_1: + switch (rnti_type) { + case NR_RNTI_C: // Indicating a DL DCI format 1bit - pos=1; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->format_indicator&0x1)<<(dci_size-pos); - + pos = 1; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->format_indicator & 0x1) << (dci_size - pos); // Carrier indicator - pos+=dci_pdu_rel15->carrier_indicator.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->carrier_indicator.val&((1<<dci_pdu_rel15->carrier_indicator.nbits)-1))<<(dci_size-pos); - + pos += dci_pdu_rel15->carrier_indicator.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->carrier_indicator.val & ((1 << dci_pdu_rel15->carrier_indicator.nbits) - 1)) << (dci_size - pos); + // UL/SUL Indicator + pos += dci_pdu_rel15->ul_sul_indicator.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->ul_sul_indicator.val & ((1 << dci_pdu_rel15->ul_sul_indicator.nbits) - 1)) << (dci_size - pos); // BWP indicator - pos+=dci_pdu_rel15->bwp_indicator.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->bwp_indicator.val&((1<<dci_pdu_rel15->bwp_indicator.nbits)-1))<<(dci_size-pos); - + pos += dci_pdu_rel15->bwp_indicator.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->bwp_indicator.val & ((1 << dci_pdu_rel15->bwp_indicator.nbits) - 1)) << (dci_size - pos); // Frequency domain resource assignment - pos+=dci_pdu_rel15->frequency_domain_assignment.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val&((1<<dci_pdu_rel15->frequency_domain_assignment.nbits)-1)) << (dci_size-pos); - + pos += dci_pdu_rel15->frequency_domain_assignment.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val & ((1 << dci_pdu_rel15->frequency_domain_assignment.nbits) - 1)) << (dci_size - pos); // Time domain resource assignment - pos+=dci_pdu_rel15->time_domain_assignment.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->time_domain_assignment.val&((1<<dci_pdu_rel15->time_domain_assignment.nbits)-1)) << (dci_size-pos); - - // VRB-to-PRB mapping - pos+=dci_pdu_rel15->vrb_to_prb_mapping.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->vrb_to_prb_mapping.val&((1<<dci_pdu_rel15->vrb_to_prb_mapping.nbits)-1))<<(dci_size-pos); - - // PRB bundling size indicator - pos+=dci_pdu_rel15->prb_bundling_size_indicator.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->prb_bundling_size_indicator.val&((1<<dci_pdu_rel15->prb_bundling_size_indicator.nbits)-1))<<(dci_size-pos); - - // Rate matching indicator - pos+=dci_pdu_rel15->rate_matching_indicator.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->rate_matching_indicator.val&((1<<dci_pdu_rel15->rate_matching_indicator.nbits)-1))<<(dci_size-pos); - - // ZP CSI-RS trigger - pos+=dci_pdu_rel15->zp_csi_rs_trigger.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->zp_csi_rs_trigger.val&((1<<dci_pdu_rel15->zp_csi_rs_trigger.nbits)-1)) << (dci_size-pos); - - //TB1 + pos += dci_pdu_rel15->time_domain_assignment.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->time_domain_assignment.val & ((1 << dci_pdu_rel15->time_domain_assignment.nbits) - 1)) << (dci_size - pos); + // Frequency hopping + pos += dci_pdu_rel15->frequency_hopping_flag.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->frequency_hopping_flag.val & ((1 << dci_pdu_rel15->frequency_hopping_flag.nbits) - 1)) << (dci_size - pos); // MCS 5bit - pos+=5; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->mcs&0x1f)<<(dci_size-pos); - - // New data indicator 1bit - pos+=1; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->ndi&0x1)<<(dci_size-pos); - - // Redundancy version 2bit - pos+=2; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->rv&0x3)<<(dci_size-pos); - - //TB2 - // MCS 5bit - pos+=dci_pdu_rel15->mcs2.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->mcs2.val&((1<<dci_pdu_rel15->mcs2.nbits)-1))<<(dci_size-pos); - + pos += 5; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->mcs & 0x1f) << (dci_size - pos); // New data indicator 1bit - pos+=dci_pdu_rel15->ndi2.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->ndi2.val&((1<<dci_pdu_rel15->ndi2.nbits)-1))<<(dci_size-pos); - + pos += 1; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->ndi & 0x1) << (dci_size - pos); // Redundancy version 2bit - pos+=dci_pdu_rel15->rv2.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->rv2.val&((1<<dci_pdu_rel15->rv2.nbits)-1))<<(dci_size-pos); - + pos += 2; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->rv & 0x3) << (dci_size - pos); // HARQ process number 4bit - pos+=4; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->harq_pid&0xf)<<(dci_size-pos); - - // Downlink assignment index - pos+=dci_pdu_rel15->dai[0].nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->dai[0].val&((1<<dci_pdu_rel15->dai[0].nbits)-1))<<(dci_size-pos); - - // TPC command for scheduled PUCCH 2bit - pos+=2; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->tpc&0x3)<<(dci_size-pos); - - // PUCCH resource indicator 3bit - pos+=3; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->pucch_resource_indicator&0x7)<<(dci_size-pos); - - // PDSCH-to-HARQ_feedback timing indicator - pos+=dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.val&((1<<dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.nbits)-1))<<(dci_size-pos); - + pos += 4; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->harq_pid & 0xf) << (dci_size - pos); + // 1st Downlink assignment index + pos += dci_pdu_rel15->dai[0].nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->dai[0].val & ((1 << dci_pdu_rel15->dai[0].nbits) - 1)) << (dci_size - pos); + // 2nd Downlink assignment index + pos += dci_pdu_rel15->dai[1].nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->dai[1].val & ((1 << dci_pdu_rel15->dai[1].nbits) - 1)) << (dci_size - pos); + // TPC command for scheduled PUSCH 2bit + pos += 2; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->tpc & 0x3) << (dci_size - pos); + // SRS resource indicator + pos += dci_pdu_rel15->srs_resource_indicator.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->srs_resource_indicator.val & ((1 << dci_pdu_rel15->srs_resource_indicator.nbits) - 1)) << (dci_size - pos); + // Precoding info and n. of layers + pos += dci_pdu_rel15->precoding_information.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->precoding_information.val & ((1 << dci_pdu_rel15->precoding_information.nbits) - 1)) << (dci_size - pos); // Antenna ports - pos+=dci_pdu_rel15->antenna_ports.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->antenna_ports.val&((1<<dci_pdu_rel15->antenna_ports.nbits)-1))<<(dci_size-pos); - - // TCI - pos+=dci_pdu_rel15->transmission_configuration_indication.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->transmission_configuration_indication.val&((1<<dci_pdu_rel15->transmission_configuration_indication.nbits)-1))<<(dci_size-pos); - + pos += dci_pdu_rel15->antenna_ports.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->antenna_ports.val & ((1 << dci_pdu_rel15->antenna_ports.nbits) - 1)) << (dci_size - pos); // SRS request - pos+=dci_pdu_rel15->srs_request.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->srs_request.val&((1<<dci_pdu_rel15->srs_request.nbits)-1))<<(dci_size-pos); - + pos += dci_pdu_rel15->srs_request.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->srs_request.val & ((1 << dci_pdu_rel15->srs_request.nbits) - 1)) << (dci_size - pos); + // CSI request + pos += dci_pdu_rel15->csi_request.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->csi_request.val & ((1 << dci_pdu_rel15->csi_request.nbits) - 1)) << (dci_size - pos); // CBG transmission information - pos+=dci_pdu_rel15->cbgti.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->cbgti.val&((1<<dci_pdu_rel15->cbgti.nbits)-1))<<(dci_size-pos); - - // CBG flushing out information - pos+=dci_pdu_rel15->cbgfi.nbits; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->cbgfi.val&((1<<dci_pdu_rel15->cbgfi.nbits)-1))<<(dci_size-pos); - - // DMRS sequence init - pos+=1; - *dci_pdu |= ((uint64_t)dci_pdu_rel15->dmrs_sequence_initialization.val&0x1)<<(dci_size-pos); + pos += dci_pdu_rel15->cbgti.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->cbgti.val & ((1 << dci_pdu_rel15->cbgti.nbits) - 1)) << (dci_size - pos); + // PTRS DMRS association + pos += dci_pdu_rel15->ptrs_dmrs_association.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->ptrs_dmrs_association.val & ((1 << dci_pdu_rel15->ptrs_dmrs_association.nbits) - 1)) << (dci_size - pos); + // Beta offset indicator + pos += dci_pdu_rel15->beta_offset_indicator.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->beta_offset_indicator.val & ((1 << dci_pdu_rel15->beta_offset_indicator.nbits) - 1)) << (dci_size - pos); + // DMRS sequence initialization + pos += dci_pdu_rel15->dmrs_sequence_initialization.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->dmrs_sequence_initialization.val & ((1 << dci_pdu_rel15->dmrs_sequence_initialization.nbits) - 1)) << (dci_size - pos); + // UL-SCH indicator + pos += 1; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->ulsch_indicator & 0x1) << (dci_size - pos); + break; } - LOG_D(MAC, "DCI index %d has %d bits and the payload is %lx\n", d, dci_size, *dci_pdu); - } -} - - - /* - int nr_is_dci_opportunity(nfapi_nr_search_space_t search_space, - nfapi_nr_coreset_t coreset, - uint16_t frame, - uint16_t slot, - nfapi_nr_config_request_scf_t cfg) { - - AssertFatal(search_space.coreset_id==coreset.coreset_id, "Invalid association of coreset(%d) and search space(%d)\n", - search_space.search_space_id, coreset.coreset_id); - - uint8_t is_dci_opportunity=0; - uint16_t Ks=search_space.slot_monitoring_periodicity; - uint16_t Os=search_space.slot_monitoring_offset; - uint8_t Ts=search_space.duration; - - if (((frame*get_spf(&cfg) + slot - Os)%Ks)<Ts) - is_dci_opportunity=1; + break; - return is_dci_opportunity; + case NR_DL_DCI_FORMAT_1_1: + // Indicating a DL DCI format 1bit + pos = 1; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->format_indicator & 0x1) << (dci_size - pos); + // Carrier indicator + pos += dci_pdu_rel15->carrier_indicator.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->carrier_indicator.val & ((1 << dci_pdu_rel15->carrier_indicator.nbits) - 1)) << (dci_size - pos); + // BWP indicator + pos += dci_pdu_rel15->bwp_indicator.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->bwp_indicator.val & ((1 << dci_pdu_rel15->bwp_indicator.nbits) - 1)) << (dci_size - pos); + // Frequency domain resource assignment + pos += dci_pdu_rel15->frequency_domain_assignment.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->frequency_domain_assignment.val & ((1 << dci_pdu_rel15->frequency_domain_assignment.nbits) - 1)) << (dci_size - pos); + // Time domain resource assignment + pos += dci_pdu_rel15->time_domain_assignment.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->time_domain_assignment.val & ((1 << dci_pdu_rel15->time_domain_assignment.nbits) - 1)) << (dci_size - pos); + // VRB-to-PRB mapping + pos += dci_pdu_rel15->vrb_to_prb_mapping.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->vrb_to_prb_mapping.val & ((1 << dci_pdu_rel15->vrb_to_prb_mapping.nbits) - 1)) << (dci_size - pos); + // PRB bundling size indicator + pos += dci_pdu_rel15->prb_bundling_size_indicator.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->prb_bundling_size_indicator.val & ((1 << dci_pdu_rel15->prb_bundling_size_indicator.nbits) - 1)) << (dci_size - pos); + // Rate matching indicator + pos += dci_pdu_rel15->rate_matching_indicator.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->rate_matching_indicator.val & ((1 << dci_pdu_rel15->rate_matching_indicator.nbits) - 1)) << (dci_size - pos); + // ZP CSI-RS trigger + pos += dci_pdu_rel15->zp_csi_rs_trigger.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->zp_csi_rs_trigger.val & ((1 << dci_pdu_rel15->zp_csi_rs_trigger.nbits) - 1)) << (dci_size - pos); + // TB1 + // MCS 5bit + pos += 5; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->mcs & 0x1f) << (dci_size - pos); + // New data indicator 1bit + pos += 1; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->ndi & 0x1) << (dci_size - pos); + // Redundancy version 2bit + pos += 2; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->rv & 0x3) << (dci_size - pos); + // TB2 + // MCS 5bit + pos += dci_pdu_rel15->mcs2.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->mcs2.val & ((1 << dci_pdu_rel15->mcs2.nbits) - 1)) << (dci_size - pos); + // New data indicator 1bit + pos += dci_pdu_rel15->ndi2.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->ndi2.val & ((1 << dci_pdu_rel15->ndi2.nbits) - 1)) << (dci_size - pos); + // Redundancy version 2bit + pos += dci_pdu_rel15->rv2.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->rv2.val & ((1 << dci_pdu_rel15->rv2.nbits) - 1)) << (dci_size - pos); + // HARQ process number 4bit + pos += 4; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->harq_pid & 0xf) << (dci_size - pos); + // Downlink assignment index + pos += dci_pdu_rel15->dai[0].nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->dai[0].val & ((1 << dci_pdu_rel15->dai[0].nbits) - 1)) << (dci_size - pos); + // TPC command for scheduled PUCCH 2bit + pos += 2; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->tpc & 0x3) << (dci_size - pos); + // PUCCH resource indicator 3bit + pos += 3; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->pucch_resource_indicator & 0x7) << (dci_size - pos); + // PDSCH-to-HARQ_feedback timing indicator + pos += dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.val & ((1 << dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.nbits) - 1)) << (dci_size - pos); + // Antenna ports + pos += dci_pdu_rel15->antenna_ports.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->antenna_ports.val & ((1 << dci_pdu_rel15->antenna_ports.nbits) - 1)) << (dci_size - pos); + // TCI + pos += dci_pdu_rel15->transmission_configuration_indication.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->transmission_configuration_indication.val & ((1 << dci_pdu_rel15->transmission_configuration_indication.nbits) - 1)) << (dci_size - pos); + // SRS request + pos += dci_pdu_rel15->srs_request.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->srs_request.val & ((1 << dci_pdu_rel15->srs_request.nbits) - 1)) << (dci_size - pos); + // CBG transmission information + pos += dci_pdu_rel15->cbgti.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->cbgti.val & ((1 << dci_pdu_rel15->cbgti.nbits) - 1)) << (dci_size - pos); + // CBG flushing out information + pos += dci_pdu_rel15->cbgfi.nbits; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->cbgfi.val & ((1 << dci_pdu_rel15->cbgfi.nbits) - 1)) << (dci_size - pos); + // DMRS sequence init + pos += 1; + *dci_pdu |= ((uint64_t)dci_pdu_rel15->dmrs_sequence_initialization.val & 0x1) << (dci_size - pos); + } + LOG_D(MAC, "DCI has %d bits and the payload is %lx\n", dci_size, *dci_pdu); } -*/ int get_spf(nfapi_nr_config_request_scf_t *cfg) { @@ -1779,35 +1442,105 @@ int extract_length(int startSymbolAndLength) { /* * Dump the UL or DL UE_info into LOG_T(MAC) */ -void dump_nr_ue_list(NR_UE_list_t *listP) { +void dump_nr_list(NR_list_t *listP) +{ for (int j = listP->head; j >= 0; j = listP->next[j]) - LOG_T(MAC, "DL list node %d => %d\n", j, listP->next[j]); + LOG_T(MAC, "NR list node %d => %d\n", j, listP->next[j]); +} + +/* + * Create a new NR_list + */ +void create_nr_list(NR_list_t *list, int len) +{ + list->head = -1; + list->next = calloc(len, sizeof(*list->next)); + AssertFatal(list, "cannot calloc() memory for NR_list_t->next\n"); + for (int i = 0; i < len; ++i) + list->next[i] = -1; + list->tail = -1; + list->len = len; +} + +/* + * Destroy an NR_list + */ +void destroy_nr_list(NR_list_t *list) +{ + free(list->next); } /* - * Add a UE to NR_UE_list listP + * Add an ID to an NR_list at the end, traversing the whole list. Note: + * add_tail_nr_list() is a faster alternative, but this implementation ensures + * we do not add an existing ID. */ -inline void add_nr_ue_list(NR_UE_list_t *listP, int UE_id) { +void add_nr_list(NR_list_t *listP, int id) +{ int *cur = &listP->head; while (*cur >= 0) { - AssertFatal(*cur != UE_id, "UE_id %d already in NR_UE_list!\n", UE_id); + AssertFatal(*cur != id, "id %d already in NR_UE_list!\n", id); cur = &listP->next[*cur]; } - *cur = UE_id; + *cur = id; + if (listP->next[id] < 0) + listP->tail = id; } /* - * Remove a UE from NR_UE_list listP + * Remove an ID from an NR_list */ -static inline void remove_nr_ue_list(NR_UE_list_t *listP, int UE_id) { +void remove_nr_list(NR_list_t *listP, int id) +{ int *cur = &listP->head; - while (*cur != -1 && *cur != UE_id) + int *prev = &listP->head; + while (*cur != -1 && *cur != id) { + prev = cur; cur = &listP->next[*cur]; - AssertFatal(*cur != -1, "UE %d not found in UE_list\n", UE_id); + } + AssertFatal(*cur != -1, "ID %d not found in UE_list\n", id); int *next = &listP->next[*cur]; *cur = listP->next[*cur]; *next = -1; - return; + listP->tail = *prev >= 0 && listP->next[*prev] >= 0 ? listP->tail : *prev; +} + +/* + * Add an ID to the tail of the NR_list in O(1). Note that there is + * corresponding remove_tail_nr_list(), as we cannot set the tail backwards and + * therefore need to go through the whole list (use remove_nr_list()) + */ +void add_tail_nr_list(NR_list_t *listP, int id) +{ + int *last = listP->tail < 0 ? &listP->head : &listP->next[listP->tail]; + *last = id; + listP->next[id] = -1; + listP->tail = id; +} + +/* + * Add an ID to the front of the NR_list in O(1) + */ +void add_front_nr_list(NR_list_t *listP, int id) +{ + const int ohead = listP->head; + listP->head = id; + listP->next[id] = ohead; + if (listP->tail < 0) + listP->tail = id; +} + +/* + * Remove an ID from the front of the NR_list in O(1) + */ +void remove_front_nr_list(NR_list_t *listP) +{ + AssertFatal(listP->head >= 0, "Nothing to remove\n"); + const int ohead = listP->head; + listP->head = listP->next[ohead]; + listP->next[ohead] = -1; + if (listP->head < 0) + listP->tail = -1; } int find_nr_UE_id(module_id_t mod_idP, rnti_t rntiP) @@ -1860,20 +1593,35 @@ int find_nr_RA_id(module_id_t mod_idP, int CC_idP, rnti_t rntiP) { return -1; } -//------------------------------------------------------------------------------ -int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP){ +int get_nrofHARQ_ProcessesForPDSCH(e_NR_PDSCH_ServingCellConfig__nrofHARQ_ProcessesForPDSCH n) +{ + switch (n) { + case NR_PDSCH_ServingCellConfig__nrofHARQ_ProcessesForPDSCH_n2: + return 2; + case NR_PDSCH_ServingCellConfig__nrofHARQ_ProcessesForPDSCH_n4: + return 4; + case NR_PDSCH_ServingCellConfig__nrofHARQ_ProcessesForPDSCH_n6: + return 6; + case NR_PDSCH_ServingCellConfig__nrofHARQ_ProcessesForPDSCH_n10: + return 10; + case NR_PDSCH_ServingCellConfig__nrofHARQ_ProcessesForPDSCH_n12: + return 12; + case NR_PDSCH_ServingCellConfig__nrofHARQ_ProcessesForPDSCH_n16: + return 16; + default: + return 8; + } +} +//------------------------------------------------------------------------------ +int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP, NR_CellGroupConfig_t *secondaryCellGroup) +{ NR_UE_info_t *UE_info = &RC.nrmac[mod_idP]->UE_info; - NR_COMMON_channels_t *cc = RC.nrmac[mod_idP]->common_channels; - NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - int num_slots_ul = scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots; - if (scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols>0) - num_slots_ul++; - LOG_W(MAC, "[gNB %d] Adding UE with rnti %x (num_UEs %d)\n", + LOG_I(MAC, "[gNB %d] Adding UE with rnti %x (num_UEs %d)\n", mod_idP, rntiP, UE_info->num_UEs); - dump_nr_ue_list(&UE_info->list); + dump_nr_list(&UE_info->list); for (int i = 0; i < MAX_MOBILES_PER_GNB; i++) { if (UE_info->active[i]) @@ -1883,38 +1631,65 @@ int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP){ UE_info->num_UEs++; UE_info->active[UE_id] = true; UE_info->rnti[UE_id] = rntiP; - add_nr_ue_list(&UE_info->list, UE_id); + UE_info->secondaryCellGroup[UE_id] = secondaryCellGroup; + add_nr_list(&UE_info->list, UE_id); + memset(&UE_info->mac_stats[UE_id], 0, sizeof(NR_mac_stats_t)); set_Y(UE_info->Y[UE_id], rntiP); - memset((void *) &UE_info->UE_sched_ctrl[UE_id], - 0, - sizeof(NR_UE_sched_ctrl_t)); - UE_info->UE_sched_ctrl[UE_id].ta_frame = 0; - UE_info->UE_sched_ctrl[UE_id].ta_update = 31; - UE_info->UE_sched_ctrl[UE_id].ta_apply = false; - UE_info->UE_sched_ctrl[UE_id].ul_rssi = 0; + compute_csi_bitlen(secondaryCellGroup, UE_info, UE_id); + NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + memset(sched_ctrl, 0, sizeof(*sched_ctrl)); + sched_ctrl->ta_frame = 0; + sched_ctrl->ta_update = 31; + sched_ctrl->ta_apply = false; + sched_ctrl->ul_rssi = 0; /* set illegal time domain allocation to force recomputation of all fields */ - UE_info->UE_sched_ctrl[UE_id].pusch_save.time_domain_allocation = -1; - UE_info->UE_sched_ctrl[UE_id].sched_pucch = (NR_sched_pucch **)malloc(num_slots_ul*sizeof(NR_sched_pucch *)); - for (int s=0; s<num_slots_ul;s++) - UE_info->UE_sched_ctrl[UE_id].sched_pucch[s] = (NR_sched_pucch *)malloc(2*sizeof(NR_sched_pucch)); - - for (int k=0; k<num_slots_ul; k++) { - for (int l=0; l<2; l++) - memset((void *) &UE_info->UE_sched_ctrl[UE_id].sched_pucch[k][l], - 0, - sizeof(NR_sched_pucch)); - } + sched_ctrl->pusch_save.time_domain_allocation = -1; + const NR_ServingCellConfig_t *servingCellConfig = secondaryCellGroup->spCellConfig->spCellConfigDedicated; + + /* Set default BWPs */ + const struct NR_ServingCellConfig__downlinkBWP_ToAddModList *bwpList = servingCellConfig->downlinkBWP_ToAddModList; + AssertFatal(bwpList->list.count == 1, + "downlinkBWP_ToAddModList has %d BWP!\n", + bwpList->list.count); + const int bwp_id = 1; + sched_ctrl->active_bwp = bwpList->list.array[bwp_id - 1]; + const struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList = servingCellConfig->uplinkConfig->uplinkBWP_ToAddModList; + AssertFatal(ubwpList->list.count == 1, + "uplinkBWP_ToAddModList has %d BWP!\n", + ubwpList->list.count); + sched_ctrl->active_ubwp = ubwpList->list.array[bwp_id - 1]; + + /* get Number of HARQ processes for this UE */ + AssertFatal(servingCellConfig->pdsch_ServingCellConfig->present == NR_SetupRelease_PDSCH_ServingCellConfig_PR_setup, + "no pdsch-ServingCellConfig found for UE %d\n", + UE_id); + const NR_PDSCH_ServingCellConfig_t *pdsch = servingCellConfig->pdsch_ServingCellConfig->choice.setup; + const int nrofHARQ = pdsch->nrofHARQ_ProcessesForPDSCH ? + get_nrofHARQ_ProcessesForPDSCH(*pdsch->nrofHARQ_ProcessesForPDSCH) : 8; + // add all available DL HARQ processes for this UE + create_nr_list(&sched_ctrl->available_dl_harq, nrofHARQ); + for (int harq = 0; harq < nrofHARQ; harq++) + add_tail_nr_list(&sched_ctrl->available_dl_harq, harq); + create_nr_list(&sched_ctrl->feedback_dl_harq, nrofHARQ); + create_nr_list(&sched_ctrl->retrans_dl_harq, nrofHARQ); + + // add all available UL HARQ processes for this UE + create_nr_list(&sched_ctrl->available_ul_harq, 16); + for (int harq = 0; harq < 16; harq++) + add_tail_nr_list(&sched_ctrl->available_ul_harq, harq); + create_nr_list(&sched_ctrl->feedback_ul_harq, 16); + create_nr_list(&sched_ctrl->retrans_ul_harq, 16); LOG_I(MAC, "gNB %d] Add NR UE_id %d : rnti %x\n", mod_idP, UE_id, rntiP); - dump_nr_ue_list(&UE_info->list); + dump_nr_list(&UE_info->list); return (UE_id); } // printf("MAC: cannot add new UE for rnti %x\n", rntiP); LOG_E(MAC, "error in add_new_ue(), could not find space in UE_info, Dumping UE list\n"); - dump_nr_ue_list(&UE_info->list); + dump_nr_list(&UE_info->list); return -1; } @@ -1942,11 +1717,14 @@ void mac_remove_nr_ue(module_id_t mod_id, rnti_t rnti) UE_info->num_UEs--; UE_info->active[UE_id] = FALSE; UE_info->rnti[UE_id] = 0; - remove_nr_ue_list(&UE_info->list, UE_id); - free(UE_info->UE_sched_ctrl[UE_id].sched_pucch); - memset((void *) &UE_info->UE_sched_ctrl[UE_id], - 0, - sizeof(NR_UE_sched_ctrl_t)); + remove_nr_list(&UE_info->list, UE_id); + NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + destroy_nr_list(&sched_ctrl->available_dl_harq); + destroy_nr_list(&sched_ctrl->feedback_dl_harq); + destroy_nr_list(&sched_ctrl->retrans_dl_harq); + destroy_nr_list(&sched_ctrl->available_ul_harq); + destroy_nr_list(&sched_ctrl->feedback_ul_harq); + destroy_nr_list(&sched_ctrl->retrans_ul_harq); LOG_I(MAC, "[gNB %d] Remove NR UE_id %d : rnti %x\n", mod_id, UE_id, @@ -2024,6 +1802,30 @@ void get_pdsch_to_harq_feedback(int Mod_idP, } +bool find_free_CCE(module_id_t module_id, + sub_frame_t slot, + int UE_id){ + NR_UE_sched_ctrl_t *sched_ctrl = &RC.nrmac[module_id]->UE_info.UE_sched_ctrl[UE_id]; + uint8_t nr_of_candidates; + find_aggregation_candidates(&sched_ctrl->aggregation_level, + &nr_of_candidates, + sched_ctrl->search_space); + const int cid = sched_ctrl->coreset->controlResourceSetId; + const uint16_t Y = RC.nrmac[module_id]->UE_info.Y[UE_id][cid][slot]; + const int m = RC.nrmac[module_id]->UE_info.num_pdcch_cand[UE_id][cid]; + sched_ctrl->cce_index = allocate_nr_CCEs(RC.nrmac[module_id], + sched_ctrl->active_bwp, + sched_ctrl->coreset, + sched_ctrl->aggregation_level, + Y, + m, + nr_of_candidates); + if (sched_ctrl->cce_index < 0) + return false; + + RC.nrmac[module_id]->UE_info.num_pdcch_cand[UE_id][cid]++; + return true; +} /*void fill_nfapi_coresets_and_searchspaces(NR_CellGroupConfig_t *cg, nfapi_nr_coreset_t *coreset, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index ec5195ec5beacf7c19ff9f40ed5f483da4f4e115..f0a20d8e6f78c14aa86f410fc197e28922a90217 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -34,64 +34,72 @@ extern RAN_CONTEXT_t RC; +void nr_fill_nfapi_pucch(module_id_t mod_id, + frame_t frame, + sub_frame_t slot, + const NR_sched_pucch_t *pucch, + int UE_id) +{ + NR_UE_info_t *UE_info = &RC.nrmac[mod_id]->UE_info; + + nfapi_nr_ul_tti_request_t *future_ul_tti_req = + &RC.nrmac[mod_id]->UL_tti_req_ahead[0][pucch->ul_slot]; + AssertFatal(future_ul_tti_req->SFN == pucch->frame + && future_ul_tti_req->Slot == pucch->ul_slot, + "future UL_tti_req's frame.slot %d.%d does not match PUCCH %d.%d\n", + future_ul_tti_req->SFN, + future_ul_tti_req->Slot, + pucch->frame, + pucch->ul_slot); + future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE; + future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_pucch_pdu_t); + nfapi_nr_pucch_pdu_t *pucch_pdu = &future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pucch_pdu; + memset(pucch_pdu, 0, sizeof(nfapi_nr_pucch_pdu_t)); + future_ul_tti_req->n_pdus += 1; + + LOG_D(MAC, + "%4d.%2d Scheduling pucch reception in %4d.%2d: bits SR %d, ACK %d, CSI %d on res %d\n", + frame, + slot, + pucch->frame, + pucch->ul_slot, + pucch->sr_flag, + pucch->dai_c, + pucch->csi_bits, + pucch->resource_indicator); + + NR_ServingCellConfigCommon_t *scc = RC.nrmac[mod_id]->common_channels->ServingCellConfigCommon; + nr_configure_pucch(pucch_pdu, + scc, + UE_info->UE_sched_ctrl[UE_id].active_ubwp, + UE_info->rnti[UE_id], + pucch->resource_indicator, + pucch->csi_bits, + pucch->dai_c, + pucch->sr_flag); +} + void nr_schedule_pucch(int Mod_idP, - int UE_id, - int nr_ulmix_slots, frame_t frameP, sub_frame_t slotP) { 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); + const NR_list_t *UE_list = &UE_info->list; - for (int k=0; k<nr_ulmix_slots; k++) { - for (int l=0; l<2; l++) { - NR_sched_pucch *curr_pucch = &UE_info->UE_sched_ctrl[UE_id].sched_pucch[k][l]; + for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { + NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + const int n = sizeof(sched_ctrl->sched_pucch) / sizeof(*sched_ctrl->sched_pucch); + for (int i = 0; i < n; i++) { + NR_sched_pucch_t *curr_pucch = &UE_info->UE_sched_ctrl[UE_id].sched_pucch[i]; const uint16_t O_ack = curr_pucch->dai_c; const uint16_t O_csi = curr_pucch->csi_bits; - const uint8_t O_sr = 0; // no SR in PUCCH implemented for now + const uint8_t O_sr = curr_pucch->sr_flag; if (O_ack + O_csi + O_sr == 0 || frameP != curr_pucch->frame || slotP != curr_pucch->ul_slot) continue; - nfapi_nr_ul_tti_request_t *future_ul_tti_req = - &RC.nrmac[Mod_idP]->UL_tti_req_ahead[0][curr_pucch->ul_slot]; - AssertFatal(future_ul_tti_req->SFN == curr_pucch->frame - && future_ul_tti_req->Slot == curr_pucch->ul_slot, - "future UL_tti_req's frame.slot %d.%d does not match PUCCH %d.%d\n", - future_ul_tti_req->SFN, - future_ul_tti_req->Slot, - curr_pucch->frame, - curr_pucch->ul_slot); - future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE; - future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_pucch_pdu_t); - nfapi_nr_pucch_pdu_t *pucch_pdu = &future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pucch_pdu; - memset(pucch_pdu, 0, sizeof(nfapi_nr_pucch_pdu_t)); - future_ul_tti_req->n_pdus += 1; - - LOG_D(MAC, - "%4d.%2d Scheduling pucch reception in %4d.%2d: bits SR %d, ACK %d, CSI %d, k %d l %d\n", - frameP, - slotP, - curr_pucch->frame, - curr_pucch->ul_slot, - O_sr, - O_ack, - O_csi, - k, l); - - NR_ServingCellConfigCommon_t *scc = RC.nrmac[Mod_idP]->common_channels->ServingCellConfigCommon; - nr_configure_pucch(pucch_pdu, - scc, - UE_info->UE_sched_ctrl[UE_id].active_ubwp, - UE_info->rnti[UE_id], - curr_pucch->resource_indicator, - O_csi, - O_ack, - O_sr); - - memset(&UE_info->UE_sched_ctrl[UE_id].sched_pucch[k][l], - 0, - sizeof(NR_sched_pucch)); + nr_fill_nfapi_pucch(Mod_idP, frameP, slotP, curr_pucch, UE_id); + memset(curr_pucch, 0, sizeof(*curr_pucch)); } } } @@ -172,107 +180,136 @@ void compute_csi_bitlen (NR_CellGroupConfig_t *secondaryCellGroup, NR_UE_info_t } -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; +uint16_t nr_get_csi_bitlen(const nr_csi_report_t *csi_report) +{ + const CRI_SSBRI_RSRP_bitlen_t *bitlen = &csi_report->CSI_report_bitlen[0]; + return bitlen->cri_ssbri_bitlen * bitlen->nb_ssbri_cri + + bitlen->rsrp_bitlen + + bitlen->diff_rsrp_bitlen * (bitlen->nb_ssbri_cri - 1) * csi_report->nb_of_csi_ssb_report; } 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) { + sub_frame_t slot) +{ + NR_ServingCellConfigCommon_t *scc = + RC.nrmac[Mod_idP]->common_channels->ServingCellConfigCommon; + const int n_slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; 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)-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; + NR_list_t *UE_list = &UE_info->list; + for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { + const NR_CellGroupConfig_t *secondaryCellGroup = UE_info->secondaryCellGroup[UE_id]; + NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + const NR_CSI_MeasConfig_t *csi_measconfig = secondaryCellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup; + AssertFatal(csi_measconfig->csi_ReportConfigToAddModList->list.count > 0, + "NO CSI report configuration available"); + NR_PUCCH_Config_t *pucch_Config = sched_ctrl->active_ubwp->bwp_Dedicated->pucch_Config->choice.setup; + + for (int csi_report_id = 0; csi_report_id < csi_measconfig->csi_ReportConfigToAddModList->list.count; csi_report_id++){ + const NR_CSI_ReportConfig_t *csirep = csi_measconfig->csi_ReportConfigToAddModList->list.array[csi_report_id]; + + AssertFatal(csirep->reportConfigType.choice.periodic, + "Only periodic CSI reporting is implemented currently\n"); + int period, offset; + csi_period_offset(csirep, &period, &offset); + const int 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) + continue; + LOG_D(MAC, "CSI in frame %d slot %d\n", frame, sched_slot); + + const NR_PUCCH_CSI_Resource_t *pucchcsires = csirep->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list.array[0]; + const NR_PUCCH_ResourceSet_t *pucchresset = pucch_Config->resourceSetToAddModList->list.array[1]; // set with formats >1 + const int n = pucchresset->resourceList.list.count; + int res_index = 0; + for (; res_index < n; res_index++) + if (*pucchresset->resourceList.list.array[res_index] == pucchcsires->pucch_Resource) + break; + AssertFatal(res_index < n, + "CSI resource not found among PUCCH resources\n"); + + // find free PUCCH that is in order with possibly existing PUCCH + // schedulings (other CSI, SR) + NR_sched_pucch_t *curr_pucch = &sched_ctrl->sched_pucch[2]; + AssertFatal(curr_pucch->csi_bits == 0 + && !curr_pucch->sr_flag + && curr_pucch->dai_c == 0, + "PUCCH not free at index 2 for UE %04x\n", + UE_info->rnti[UE_id]); + curr_pucch->frame = frame; + curr_pucch->ul_slot = sched_slot; + curr_pucch->resource_indicator = res_index; + curr_pucch->csi_bits += + nr_get_csi_bitlen(&UE_info->csi_report_template[UE_id][csi_report_id]); // 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"); - } + uint16_t *vrb_map_UL = &RC.nrmac[Mod_idP]->common_channels[0].vrb_map_UL[sched_slot * MAX_BWP_SIZE]; + const int m = pucch_Config->resourceToAddModList->list.count; + for (int j = 0; j < m; j++) { + NR_PUCCH_Resource_t *pucchres = pucch_Config->resourceToAddModList->list.array[j]; + if (pucchres->pucch_ResourceId != *pucchresset->resourceList.list.array[res_index]) + continue; + int start = pucchres->startingPRB; + int len = 1; + uint64_t mask = 0; + switch(pucchres->format.present){ + case NR_PUCCH_Resource__format_PR_format2: + len = pucchres->format.choice.format2->nrofPRBs; + mask = ((1 << pucchres->format.choice.format2->nrofSymbols) - 1) << pucchres->format.choice.format2->startingSymbolIndex; + curr_pucch->simultaneous_harqcsi = pucch_Config->format2->choice.setup->simultaneousHARQ_ACK_CSI; + break; + case NR_PUCCH_Resource__format_PR_format3: + len = pucchres->format.choice.format3->nrofPRBs; + mask = ((1 << pucchres->format.choice.format3->nrofSymbols) - 1) << pucchres->format.choice.format3->startingSymbolIndex; + curr_pucch->simultaneous_harqcsi = pucch_Config->format3->choice.setup->simultaneousHARQ_ACK_CSI; + break; + case NR_PUCCH_Resource__format_PR_format4: + mask = ((1 << pucchres->format.choice.format4->nrofSymbols) - 1) << pucchres->format.choice.format4->startingSymbolIndex; + curr_pucch->simultaneous_harqcsi = pucch_Config->format4->choice.setup->simultaneousHARQ_ACK_CSI; + break; + default: + AssertFatal(0, "Invalid PUCCH format type\n"); + } + // verify resources are free + for (int i = start; i < start + len; ++i) { + vrb_map_UL[i] |= mask; } + AssertFatal(!curr_pucch->simultaneous_harqcsi, + "UE %04x has simultaneous HARQ/CSI configured, but we don't support that\n", + UE_info->rnti[UE_id]); } - 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; } } } +static void handle_dl_harq(module_id_t mod_id, + int UE_id, + int8_t harq_pid, + bool success) +{ + NR_UE_info_t *UE_info = &RC.nrmac[mod_id]->UE_info; + NR_UE_harq_t *harq = &UE_info->UE_sched_ctrl[UE_id].harq_processes[harq_pid]; + harq->feedback_slot = -1; + harq->is_waiting = false; + if (success) { + add_tail_nr_list(&UE_info->UE_sched_ctrl[UE_id].available_dl_harq, harq_pid); + harq->round = 0; + harq->ndi ^= 1; + } else if (harq->round == MAX_HARQ_ROUNDS) { + add_tail_nr_list(&UE_info->UE_sched_ctrl[UE_id].available_dl_harq, harq_pid); + harq->round = 0; + harq->ndi ^= 1; + NR_mac_stats_t *stats = &UE_info->mac_stats[UE_id]; + stats->dlsch_errors++; + LOG_D(MAC, "retransmission error for UE %d (total %d)\n", UE_id, stats->dlsch_errors); + } else { + add_tail_nr_list(&UE_info->UE_sched_ctrl[UE_id].retrans_dl_harq, harq_pid); + harq->round++; + } +} void handle_nr_uci_pucch_0_1(module_id_t mod_id, frame_t frame, @@ -292,50 +329,36 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, uci_01->ul_cqi, 30); - // TODO - int max_harq_rounds = 4; // TODO define macro + NR_ServingCellConfigCommon_t *scc = RC.nrmac[mod_id]->common_channels->ServingCellConfigCommon; + const int num_slots = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; if (((uci_01->pduBitmap >> 1) & 0x01)) { - // 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 ((slot - 1) == sched_ctrl->harq_processes[harq_idx].feedback_slot) { - sched_ctrl->harq_processes[harq_idx].feedback_slot = -1; - 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; - UE_info->mac_stats[UE_id].dlsch_errors++; - } - break; - } - // if feedback slot processing is aborted - else if (sched_ctrl->harq_processes[harq_idx].feedback_slot != -1 - && (slot - 1) > sched_ctrl->harq_processes[harq_idx].feedback_slot - && sched_ctrl->harq_processes[harq_idx].is_waiting) { - sched_ctrl->harq_processes[harq_idx].feedback_slot = -1; - 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; - } + const uint8_t harq_value = uci_01->harq->harq_list[harq_bit].harq_value; + const uint8_t harq_confidence = uci_01->harq->harq_confidence_level; + const int feedback_slot = (slot - 1 + num_slots) % num_slots; + /* In case of realtime problems: we can only identify a HARQ process by + * timing. If the HARQ process's feedback_slot is not the one we + * expected, we assume that processing has been aborted and we need to + * skip this HARQ process, which is what happens in the loop below. If + * you don't experience real-time problems, you might simply revert the + * commit that introduced these changes. */ + int8_t pid = sched_ctrl->feedback_dl_harq.head; + DevAssert(pid >= 0); + while (sched_ctrl->harq_processes[pid].feedback_slot != feedback_slot) { + LOG_W(MAC, + "expected feedback slot %d, but found %d instead\n", + sched_ctrl->harq_processes[pid].feedback_slot, + feedback_slot); + remove_front_nr_list(&sched_ctrl->feedback_dl_harq); + handle_dl_harq(mod_id, UE_id, pid, 0); + pid = sched_ctrl->feedback_dl_harq.head; + DevAssert(pid >= 0); } + remove_front_nr_list(&sched_ctrl->feedback_dl_harq); + NR_UE_harq_t *harq = &sched_ctrl->harq_processes[pid]; + DevAssert(harq->is_waiting); + handle_dl_harq(mod_id, UE_id, pid, harq_value == 1 && harq_confidence == 0); } } } @@ -358,130 +381,243 @@ void handle_nr_uci_pucch_2_3_4(module_id_t mod_id, uci_234->ul_cqi, 30); - // TODO - int max_harq_rounds = 4; // TODO define macro + NR_ServingCellConfigCommon_t *scc = RC.nrmac[mod_id]->common_channels->ServingCellConfigCommon; + const int num_slots = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; if ((uci_234->pduBitmap >> 1) & 0x01) { - 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 ((slot - 1) == sched_ctrl->harq_processes[harq_idx].feedback_slot) { - // TODO add some confidence level for when there is no CRC - sched_ctrl->harq_processes[harq_idx].feedback_slot = -1; - 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; - UE_info->mac_stats[UE_id].dlsch_errors++; - } - break; - } - // if feedback slot processing is aborted - else if (sched_ctrl->harq_processes[harq_idx].feedback_slot != -1 - && (slot - 1) > sched_ctrl->harq_processes[harq_idx].feedback_slot - && sched_ctrl->harq_processes[harq_idx].is_waiting) { - sched_ctrl->harq_processes[harq_idx].feedback_slot = -1; - 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; - } + const int acknack = ((uci_234->harq.harq_payload[harq_bit >> 3]) >> harq_bit) & 0x01; + const int feedback_slot = (slot - 1 + num_slots) % num_slots; + /* In case of realtime problems: we can only identify a HARQ process by + * timing. If the HARQ process's feedback_slot is not the one we + * expected, we assume that processing has been aborted and we need to + * skip this HARQ process, which is what happens in the loop below. If + * you don't experience real-time problems, you might simply revert the + * commit that introduced these changes. */ + int8_t pid = sched_ctrl->feedback_dl_harq.head; + DevAssert(pid >= 0); + while (sched_ctrl->harq_processes[pid].feedback_slot != feedback_slot) { + LOG_W(MAC, + "expected feedback slot %d, but found %d instead\n", + sched_ctrl->harq_processes[pid].feedback_slot, + feedback_slot); + remove_front_nr_list(&sched_ctrl->feedback_dl_harq); + handle_dl_harq(mod_id, UE_id, pid, 0); + pid = sched_ctrl->feedback_dl_harq.head; + DevAssert(pid >= 0); } + remove_front_nr_list(&sched_ctrl->feedback_dl_harq); + NR_UE_harq_t *harq = &sched_ctrl->harq_processes[pid]; + DevAssert(harq->is_waiting); + handle_dl_harq(mod_id, UE_id, pid, uci_234->harq.harq_crc != 1 && acknack); } } } // function to update pucch scheduling parameters in UE list when a USS DL is scheduled -void nr_acknack_scheduling(int Mod_idP, +bool nr_acknack_scheduling(int mod_id, 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; + frame_t frame, + sub_frame_t slot) +{ + const NR_ServingCellConfigCommon_t *scc = RC.nrmac[mod_id]->common_channels->ServingCellConfigCommon; + const int n_slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; + const NR_TDD_UL_DL_Pattern_t *tdd = &scc->tdd_UL_DL_ConfigurationCommon->pattern1; + const int nr_ulmix_slots = tdd->nrofUplinkSlots + (tdd->nrofUplinkSymbols != 0); + const int nr_mix_slots = tdd->nrofDownlinkSymbols != 0 || tdd->nrofUplinkSymbols != 0; + const int nr_slots_period = tdd->nrofDownlinkSlots + tdd->nrofUplinkSlots + nr_mix_slots; + const int first_ul_slot_tdd = tdd->nrofDownlinkSlots + nr_slots_period * (slot / nr_slots_period); + const int CC_id = 0; + + AssertFatal(slot < first_ul_slot_tdd + (tdd->nrofUplinkSymbols != 0), + "cannot handle multiple TDD periods (yet): slot %d first_ul_slot_tdd %d nrofUplinkSlots %ld\n", + slot, + first_ul_slot_tdd, + tdd->nrofUplinkSlots); + + /* for the moment, we consider: + * * only pucch_sched[0] holds HARQ (and SR) + * * we do not multiplex with CSI, which is always in pucch_sched[2] + * * SR uses format 0 and is allocated in the first UL (mixed) slot (and not + * later) + * * that the PUCCH resource set 0 (for up to 2 bits) points to the first N + * PUCCH resources, where N is the number of resources in the PUCCH + * resource set. This is used in pucch_index_used, which counts the used + * resources by index, and not by their ID! */ + NR_UE_sched_ctrl_t *sched_ctrl = &RC.nrmac[mod_id]->UE_info.UE_sched_ctrl[UE_id]; + NR_sched_pucch_t *pucch = &sched_ctrl->sched_pucch[0]; + AssertFatal(pucch->csi_bits == 0, + "%s(): csi_bits %d in sched_pucch[0]\n", + __func__, + pucch->csi_bits); + + const int max_acknacks = 2; + AssertFatal(pucch->dai_c + pucch->sr_flag <= max_acknacks, + "illegal number of bits in PUCCH of UE %d\n", + UE_id); + /* if the currently allocated PUCCH of this UE is full, allocate it */ + if (pucch->sr_flag + pucch->dai_c == max_acknacks) { + /* advance the UL slot information in PUCCH by one so we won't schedule in + * the same slot again */ + const int f = pucch->frame; + const int s = pucch->ul_slot; + nr_fill_nfapi_pucch(mod_id, frame, slot, pucch, UE_id); + memset(pucch, 0, sizeof(*pucch)); + pucch->frame = s == n_slots_frame - 1 ? (f + 1) % 1024 : f; + pucch->ul_slot = (s + 1) % n_slots_frame; + // we assume that only two indices over the array sched_pucch exist + const NR_sched_pucch_t *csi_pucch = &sched_ctrl->sched_pucch[2]; + // skip the CSI PUCCH if it is present and if in the next frame/slot + if (csi_pucch->csi_bits > 0 + && csi_pucch->frame == pucch->frame + && csi_pucch->ul_slot == pucch->ul_slot) { + AssertFatal(!csi_pucch->simultaneous_harqcsi, + "%s(): %d.%d cannot handle simultaneous_harqcsi, but found for UE %d\n", + __func__, + pucch->frame, + pucch->ul_slot, + UE_id); + nr_fill_nfapi_pucch(mod_id, frame, slot, csi_pucch, UE_id); + pucch->frame = s >= n_slots_frame - 2 ? (f + 1) % 1024 : f; + pucch->ul_slot = (s + 2) % n_slots_frame; + } } - // 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; + /* if the UE's next PUCCH occasion is after the possible UL slots (within the + * same frame) or wrapped around to the next frame, then we assume there is + * no possible PUCCH allocation anymore */ + if ((pucch->frame == frame + && (pucch->ul_slot >= first_ul_slot_tdd + nr_ulmix_slots)) + || (pucch->frame == frame + 1)) + return false; // 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; - } - } - } - } + uint8_t pdsch_to_harq_feedback[8]; + get_pdsch_to_harq_feedback(mod_id, UE_id, ss_type, pdsch_to_harq_feedback); + + /* there is a scheduled SR or HARQ. Check whether we can use it for this + * ACKNACK */ + if (pucch->sr_flag + pucch->dai_c > 0) { + /* this UE already has a PUCCH occasion */ + DevAssert(pucch->frame == frame); + + // Find the right timing_indicator value. + int i = 0; + while (i < 8) { + if (pdsch_to_harq_feedback[i] == pucch->ul_slot - slot) + break; + ++i; + } + if (i >= 8) { + // we cannot reach this timing anymore, allocate and try again + const int f = pucch->frame; + const int s = pucch->ul_slot; + const int n_slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; + nr_fill_nfapi_pucch(mod_id, frame, slot, pucch, UE_id); + memset(pucch, 0, sizeof(*pucch)); + pucch->frame = s == n_slots_frame - 1 ? (f + 1) % 1024 : f; + pucch->ul_slot = (s + 1) % n_slots_frame; + return nr_acknack_scheduling(mod_id, UE_id, frame, slot); + } + + pucch->timing_indicator = i; + pucch->dai_c++; + // retain old resource indicator, and we are good + return true; + } + + /* we need to find a new PUCCH occasion */ + + NR_PUCCH_Config_t *pucch_Config = sched_ctrl->active_ubwp->bwp_Dedicated->pucch_Config->choice.setup; + DevAssert(pucch_Config->resourceToAddModList->list.count > 0); + DevAssert(pucch_Config->resourceSetToAddModList->list.count > 0); + const int n_res = pucch_Config->resourceSetToAddModList->list.array[0]->resourceList.list.count; + int *pucch_index_used = RC.nrmac[mod_id]->pucch_index_used[sched_ctrl->active_ubwp->bwp_Id]; + + /* if time information is outdated (e.g., last PUCCH occasion in last frame), + * set to first possible UL occasion in this frame. Note that if such UE is + * scheduled a lot and used all AckNacks, pucch->frame might have been + * wrapped around to next frame */ + if (frame != pucch->frame || pucch->ul_slot < first_ul_slot_tdd) { + DevAssert(pucch->sr_flag + pucch->dai_c == 0); + AssertFatal(frame + 1 != pucch->frame, + "frame wrap around not handled in %s() yet\n", + __func__); + pucch->frame = frame; + pucch->ul_slot = first_ul_slot_tdd; + } + + // increase to first slot in which PUCCH resources are available + while (pucch_index_used[pucch->ul_slot] >= n_res) { + pucch->ul_slot++; + /* if there is no free resource anymore, abort search */ + if ((pucch->frame == frame + && pucch->ul_slot >= first_ul_slot_tdd + nr_ulmix_slots) + || (pucch->frame == frame + 1)) { + LOG_E(MAC, + "%4d.%2d no free PUCCH resources anymore while searching for UE %d\n", + frame, + slot, + UE_id); + return false; } } - AssertFatal(1==0,"No Uplink slot available in accordance to allowed timing indicator\n"); + + // advance ul_slot if it is not reachable by UE + pucch->ul_slot = max(pucch->ul_slot, slot + pdsch_to_harq_feedback[0]); + + // Find the right timing_indicator value. + int i = 0; + while (i < 8) { + if (pdsch_to_harq_feedback[i] == pucch->ul_slot - slot) + break; + ++i; + } + if (i >= 8) { + LOG_W(MAC, + "%4d.%2d could not find pdsch_to_harq_feedback for UE %d: earliest " + "ack slot %d\n", + frame, + slot, + UE_id, + pucch->ul_slot); + return false; + } + pucch->timing_indicator = i; // index in the list of timing indicators + + pucch->dai_c++; + const int pucch_res = pucch_index_used[pucch->ul_slot]; + pucch->resource_indicator = pucch_res; + pucch_index_used[pucch->ul_slot] += 1; + AssertFatal(pucch_index_used[pucch->ul_slot] <= n_res, + "UE %d in %4d.%2d: pucch_index_used is %d (%d available)\n", + UE_id, + pucch->frame, + pucch->ul_slot, + pucch_index_used[pucch->ul_slot], + n_res); + + /* verify that at that slot and symbol, resources are free. We only do this + * for initialCyclicShift 0 (we assume it always has that one), so other + * initialCyclicShifts can overlap with ICS 0!*/ + const NR_PUCCH_Resource_t *resource = + pucch_Config->resourceToAddModList->list.array[pucch_res]; + DevAssert(resource->format.present == NR_PUCCH_Resource__format_PR_format0); + if (resource->format.choice.format0->initialCyclicShift == 0) { + uint16_t *vrb_map_UL = &RC.nrmac[mod_id]->common_channels[CC_id].vrb_map_UL[pucch->ul_slot * MAX_BWP_SIZE]; + const uint16_t symb = 1 << resource->format.choice.format0->startingSymbolIndex; + AssertFatal((vrb_map_UL[resource->startingPRB] & symb) == 0, + "symbol %x is not free for PUCCH alloc in vrb_map_UL at RB %ld and slot %d\n", + symb, resource->startingPRB, pucch->ul_slot); + vrb_map_UL[resource->startingPRB] |= symb; + } + return true; } -void csi_period_offset(NR_CSI_ReportConfig_t *csirep, +void csi_period_offset(const NR_CSI_ReportConfig_t *csirep, int *period, int *offset) { NR_CSI_ReportPeriodicityAndOffset_PR p_and_o = csirep->reportConfigType.choice.periodic->reportSlotConfig.present; @@ -532,24 +668,6 @@ void csi_period_offset(NR_CSI_ReportConfig_t *csirep, } } - -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, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 1911eb07fb980f6d1f963318902ff5f63e4a02b0..6a266d006f7f95d0d0cf875d3fb2be6c9907b988 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -33,6 +33,33 @@ #include "executables/softmodem-common.h" #include "common/utils/nr/nr_common.h" +//38.321 Table 6.1.3.1-1 +const uint32_t NR_SHORT_BSR_TABLE[32] = { + 0, 10, 14, 20, 28, 38, 53, 74, + 102, 142, 198, 276, 384, 535, 745, 1038, + 1446, 2014, 2806, 3909, 5446, 7587, 10570, 14726, +20516, 28581, 39818, 55474, 77284, 107669, 150000, 300000 +}; + +//38.321 Table 6.1.3.1-2 +const uint32_t NR_LONG_BSR_TABLE[256] ={ + 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 25, 26, + 28, 30, 32, 34, 36, 38, 40, 43, 46, 49, 52, 55, 59, 62, 66, 71, + 75, 80, 85, 91, 97, 103, 110, 117, 124, 132, 141, 150, 160, 170, 181, 193, + 205, 218, 233, 248, 264, 281, 299, 318, 339, 361, 384, 409, 436, 464, 494, 526, + 560, 597, 635, 677, 720, 767, 817, 870, 926, 987, 1051, 1119, 1191, 1269, 1351, 1439, + 1532, 1631, 1737, 1850, 1970, 2098, 2234, 2379, 2533, 2698, 2873, 3059, 3258, 3469, 3694, 3934, + 4189, 4461, 4751, 5059, 5387, 5737, 6109, 6506, 6928, 7378, 7857, 8367, 8910, 9488, 10104, 10760, + 11458, 12202, 12994, 13838, 14736, 15692, 16711, 17795, 18951, 20181, 21491, 22885, 24371, 25953, 27638, 29431, + 31342, 33376, 35543, 37850, 40307, 42923, 45709, 48676, 51836, 55200, 58784, 62599, 66663, 70990, 75598, 80505, + 85730, 91295, 97221, 103532, 110252, 117409, 125030, 133146, 141789, 150992, 160793, 171231, 182345, 194182, 206786, 220209, + 234503, 249725, 265935, 283197, 301579, 321155, 342002, 364202, 387842, 413018, 439827, 468377, 498780, 531156, 565634, 602350, + 641449, 683087, 727427, 774645, 824928, 878475, 935498, 996222, 1060888, 1129752, 1203085, 1281179, 1364342, 1452903, 1547213, 1647644, + 1754595, 1868488, 1989774, 2118933, 2256475, 2402946, 2558924, 2725027, 2901912, 3090279, 3290873, 3504487, 3731968, 3974215, 4232186, 4506902, + 4799451, 5110989, 5442750, 5796046, 6172275, 6572925, 6999582, 7453933, 7937777, 8453028, 9001725, 9586039, 10208280, 10870913, 11576557, 12328006, +13128233, 13980403, 14887889, 15854280, 16883401, 17979324, 19146385, 20389201, 21712690, 23122088, 24622972, 26221280, 27923336, 29735875, 31666069, 33721553, +35910462, 38241455, 40723756, 43367187, 46182206, 49179951, 52372284, 55771835, 59392055, 63247269, 67352729, 71724679, 76380419, 81338368, 162676736, 4294967295 +}; void nr_process_mac_pdu( module_id_t module_idP, @@ -51,6 +78,13 @@ void nr_process_mac_pdu( uint16_t mac_ce_len, mac_subheader_len, mac_sdu_len; + NR_UE_info_t *UE_info = &RC.nrmac[module_idP]->UE_info; + int UE_id = find_nr_UE_id(module_idP, rnti); + if (UE_id == -1) { + LOG_E(MAC, "%s() UE_id == -1\n",__func__); + return; + } + NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; // For both DL/UL-SCH // Except: // - UL/DL-SCH: fixed-size MAC CE(known by LCID) @@ -84,6 +118,9 @@ void nr_process_mac_pdu( LOG_D(MAC, "LCID received at gNB side: %d \n", rx_lcid); + unsigned char *ce_ptr; + int n_Lcg = 0; + switch(rx_lcid){ // MAC CE @@ -97,21 +134,26 @@ void nr_process_mac_pdu( case UL_SCH_LCID_CONFIGURED_GRANT_CONFIRMATION: // 38.321 Ch6.1.3.7 break; - case UL_SCH_LCID_S_BSR: - //38.321 section 6.1.3.1 - //fixed length - mac_ce_len =1; - /* Extract short BSR value */ - break; + case UL_SCH_LCID_S_BSR: case UL_SCH_LCID_S_TRUNCATED_BSR: //38.321 section 6.1.3.1 //fixed length mac_ce_len =1; - /* Extract short truncated BSR value */ + /* Extract short BSR value */ + ce_ptr = &pdu_ptr[mac_subheader_len]; + NR_BSR_SHORT *bsr_s = (NR_BSR_SHORT *) ce_ptr; + sched_ctrl->estimated_ul_buffer = 0; + sched_ctrl->estimated_ul_buffer = NR_SHORT_BSR_TABLE[bsr_s->Buffer_size]; + LOG_D(MAC, "SHORT BSR, LCG ID %d, BS Index %d, BS value < %d, est buf %d\n", + bsr_s->LcgID, + bsr_s->Buffer_size, + NR_SHORT_BSR_TABLE[bsr_s->Buffer_size], + sched_ctrl->estimated_ul_buffer); break; case UL_SCH_LCID_L_BSR: + case UL_SCH_LCID_L_TRUNCATED_BSR: //38.321 section 6.1.3.1 //variable length mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->L; @@ -121,20 +163,26 @@ void nr_process_mac_pdu( mac_subheader_len = 3; } /* Extract long BSR value */ - break; + ce_ptr = &pdu_ptr[mac_subheader_len]; + NR_BSR_LONG *bsr_l = (NR_BSR_LONG *) ce_ptr; + sched_ctrl->estimated_ul_buffer = 0; - case UL_SCH_LCID_L_TRUNCATED_BSR: - //38.321 section 6.1.3.1 - //variable length - mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->L; - mac_subheader_len = 2; - if(((NR_MAC_SUBHEADER_SHORT *)pdu_ptr)->F){ - mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pdu_ptr)->L2)<<8; - mac_subheader_len = 3; - } - /* Extract long truncated BSR value */ - break; + n_Lcg = bsr_l->LcgID7 + bsr_l->LcgID6 + bsr_l->LcgID5 + bsr_l->LcgID4 + + bsr_l->LcgID3 + bsr_l->LcgID2 + bsr_l->LcgID1 + bsr_l->LcgID0; + LOG_D(MAC, "LONG BSR, LCG ID(7-0) %d/%d/%d/%d/%d/%d/%d/%d\n", + bsr_l->LcgID7, bsr_l->LcgID6, bsr_l->LcgID5, bsr_l->LcgID4, + bsr_l->LcgID3, bsr_l->LcgID2, bsr_l->LcgID1, bsr_l->LcgID0); + + for (int n = 0; n < n_Lcg; n++){ + LOG_D(MAC, "LONG BSR, %d/%d (n/n_Lcg), BS Index %d, BS value < %d", + n, n_Lcg, pdu_ptr[mac_subheader_len + 1 + n], + NR_LONG_BSR_TABLE[pdu_ptr[mac_subheader_len + 1 + n]]); + sched_ctrl->estimated_ul_buffer += + NR_LONG_BSR_TABLE[pdu_ptr[mac_subheader_len + 1 + n]]; + } + + break; case UL_SCH_LCID_C_RNTI: //38.321 section 6.1.3.2 @@ -230,17 +278,28 @@ void nr_process_mac_pdu( 1, NULL); + /* Updated estimated buffer when receiving data */ + if (sched_ctrl->estimated_ul_buffer >= mac_sdu_len) + sched_ctrl->estimated_ul_buffer -= mac_sdu_len; + else + sched_ctrl->estimated_ul_buffer = 0; + break; default: - return; - break; + LOG_D(MAC, "Received unknown MAC header (LCID = 0x%02x)\n", rx_lcid); + return; + break; } pdu_ptr += ( mac_subheader_len + mac_ce_len + mac_sdu_len ); pdu_len -= ( mac_subheader_len + mac_ce_len + mac_sdu_len ); if (pdu_len < 0) { LOG_E(MAC, "%s() residual mac pdu length < 0!, pdu_len: %d\n", __func__, pdu_len); + LOG_E(MAC, "MAC PDU "); + for (int i = 0; i < 20; i++) // Only printf 1st - 20nd bytes + printf("%02x ", pdu_ptr[i]); + printf("\n"); return; } } @@ -259,45 +318,51 @@ void handle_nr_ul_harq(module_id_t mod_id, NR_UE_info_t *UE_info = &RC.nrmac[mod_id]->UE_info; NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; - int max_harq_rounds = 4; // TODO define macro - uint8_t hrq_id = crc_pdu->harq_id; - NR_UE_ul_harq_t *cur_harq = &sched_ctrl->ul_harq_processes[hrq_id]; - if (cur_harq->state==ACTIVE_SCHED) { - if (!crc_pdu->tb_crc_status) { - cur_harq->ndi ^= 1; - cur_harq->round = 0; - cur_harq->state = INACTIVE; // passed -> make inactive. can be used by scheduder for next grant - LOG_D(MAC, - "Ulharq id %d crc passed for RNTI %04x\n", - hrq_id, - crc_pdu->rnti); - } else { - cur_harq->round++; - cur_harq->state = ACTIVE_NOT_SCHED; - LOG_D(MAC, - "Ulharq id %d crc failed for RNTI %04x\n", - hrq_id, - crc_pdu->rnti); - } - - if (!(cur_harq->round<max_harq_rounds)) { - cur_harq->ndi ^= 1; - cur_harq->state = INACTIVE; // failed after 4 rounds -> make inactive - cur_harq->round = 0; - LOG_D(MAC, - "RNTI %04x: Ulharq id %d crc failed in all rounds\n", - crc_pdu->rnti, - hrq_id); - UE_info->mac_stats[UE_id].ulsch_errors++; - } - return; - } else + int8_t harq_pid = sched_ctrl->feedback_ul_harq.head; + while (crc_pdu->harq_id != harq_pid || harq_pid < 0) { LOG_W(MAC, - "Incorrect ULSCH HARQ PID %d or invalid state %d for RNTI %04x " - "(ignore this warning for RA)\n", - hrq_id, - cur_harq->state, + "Unexpected ULSCH HARQ PID %d (have %d) for RNTI %04x (ignore this warning for RA)\n", + crc_pdu->harq_id, + harq_pid, + crc_pdu->rnti); + if (harq_pid < 0) + return; + + remove_front_nr_list(&sched_ctrl->feedback_ul_harq); + sched_ctrl->ul_harq_processes[harq_pid].round++; + add_tail_nr_list(&sched_ctrl->retrans_ul_harq, harq_pid); + harq_pid = sched_ctrl->feedback_ul_harq.head; + } + remove_front_nr_list(&sched_ctrl->feedback_ul_harq); + NR_UE_ul_harq_t *harq = &sched_ctrl->ul_harq_processes[harq_pid]; + DevAssert(harq->is_waiting); + harq->feedback_slot = -1; + harq->is_waiting = false; + if (!crc_pdu->tb_crc_status) { + harq->ndi ^= 1; + harq->round = 0; + LOG_D(MAC, + "Ulharq id %d crc passed for RNTI %04x\n", + harq_pid, + crc_pdu->rnti); + add_tail_nr_list(&sched_ctrl->available_ul_harq, harq_pid); + } else if (harq->round == MAX_HARQ_ROUNDS) { + harq->ndi ^= 1; + harq->round = 0; + LOG_D(MAC, + "RNTI %04x: Ulharq id %d crc failed in all rounds\n", + crc_pdu->rnti, + harq_pid); + UE_info->mac_stats[UE_id].ulsch_errors++; + add_tail_nr_list(&sched_ctrl->available_ul_harq, harq_pid); + } else { + harq->round++; + LOG_D(MAC, + "Ulharq id %d crc failed for RNTI %04x\n", + harq_pid, crc_pdu->rnti); + add_tail_nr_list(&sched_ctrl->retrans_ul_harq, harq_pid); + } } /* @@ -313,25 +378,21 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP, const uint16_t timing_advance, const uint8_t ul_cqi, const uint16_t rssi){ - int current_rnti = 0, UE_id = -1, harq_pid = 0; - gNB_MAC_INST *gNB_mac = NULL; - NR_UE_info_t *UE_info = NULL; - NR_UE_sched_ctrl_t *UE_scheduling_control = NULL; - - current_rnti = rntiP; - UE_id = find_nr_UE_id(gnb_mod_idP, current_rnti); - gNB_mac = RC.nrmac[gnb_mod_idP]; - UE_info = &gNB_mac->UE_info; - int target_snrx10 = gNB_mac->pusch_target_snrx10; - - if (sduP != NULL) { - T(T_GNB_MAC_UL_PDU_WITH_DATA, T_INT(gnb_mod_idP), T_INT(CC_idP), - T_INT(rntiP), T_INT(frameP), T_INT(slotP), T_INT(-1) /* harq_pid */, - T_BUFFER(sduP, sdu_lenP)); - } + gNB_MAC_INST *gNB_mac = RC.nrmac[gnb_mod_idP]; + NR_UE_info_t *UE_info = &gNB_mac->UE_info; + + const int current_rnti = rntiP; + const int UE_id = find_nr_UE_id(gnb_mod_idP, current_rnti); + const int target_snrx10 = gNB_mac->pusch_target_snrx10; if (UE_id != -1) { - UE_scheduling_control = &(UE_info->UE_sched_ctrl[UE_id]); + NR_UE_sched_ctrl_t *UE_scheduling_control = &UE_info->UE_sched_ctrl[UE_id]; + const int8_t harq_pid = UE_scheduling_control->feedback_ul_harq.head; + + if (sduP) + T(T_GNB_MAC_UL_PDU_WITH_DATA, T_INT(gnb_mod_idP), T_INT(CC_idP), + T_INT(rntiP), T_INT(frameP), T_INT(slotP), T_INT(harq_pid), + T_BUFFER(sduP, sdu_lenP)); UE_info->mac_stats[UE_id].ulsch_total_bytes_rx += sdu_lenP; LOG_D(MAC, "[gNB %d][PUSCH %d] CC_id %d %d.%d Received ULSCH sdu from PHY (rnti %x, UE_id %d) ul_cqi %d sduP %p\n", @@ -371,15 +432,30 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP, if (sduP != NULL){ LOG_D(MAC, "Received PDU at MAC gNB \n"); + + UE_scheduling_control->sched_ul_bytes -= UE_info->mac_stats[UE_id].ulsch_current_bytes; + if (UE_scheduling_control->sched_ul_bytes < 0) + UE_scheduling_control->sched_ul_bytes = 0; + nr_process_mac_pdu(gnb_mod_idP, current_rnti, CC_idP, frameP, sduP, sdu_lenP); } else { - + NR_UE_ul_harq_t *cur_harq = &UE_scheduling_control->ul_harq_processes[harq_pid]; + /* reduce sched_ul_bytes when cur_harq->round == 3 */ + if (cur_harq->round == 3){ + UE_scheduling_control->sched_ul_bytes -= UE_info->mac_stats[UE_id].ulsch_current_bytes; + if (UE_scheduling_control->sched_ul_bytes < 0) + UE_scheduling_control->sched_ul_bytes = 0; + } } } else { if (!sduP) // check that CRC passed return; + T(T_GNB_MAC_UL_PDU_WITH_DATA, T_INT(gnb_mod_idP), T_INT(CC_idP), + T_INT(rntiP), T_INT(frameP), T_INT(slotP), T_INT(-1) /* harq_pid */, + T_BUFFER(sduP, sdu_lenP)); + /* we don't know this UE (yet). Check whether there is a ongoing RA (Msg 3) * and check the corresponding UE's RNTI match, in which case we activate * it. */ @@ -396,21 +472,8 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP, current_rnti); continue; } - const int UE_id = add_new_nr_ue(gnb_mod_idP, ra->rnti); - UE_info->secondaryCellGroup[UE_id] = ra->secondaryCellGroup; - compute_csi_bitlen(ra->secondaryCellGroup, UE_info, UE_id); + const int UE_id = add_new_nr_ue(gnb_mod_idP, ra->rnti, ra->secondaryCellGroup); UE_info->UE_beam_index[UE_id] = ra->beam_id; - struct NR_ServingCellConfig__downlinkBWP_ToAddModList *bwpList = ra->secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList; - AssertFatal(bwpList->list.count == 1, - "downlinkBWP_ToAddModList has %d BWP!\n", - bwpList->list.count); - const int bwp_id = 1; - UE_info->UE_sched_ctrl[UE_id].active_bwp = bwpList->list.array[bwp_id - 1]; - struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList = ra->secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList; - AssertFatal(ubwpList->list.count == 1, - "uplinkBWP_ToAddModList has %d BWP!\n", - ubwpList->list.count); - UE_info->UE_sched_ctrl[UE_id].active_ubwp = ubwpList->list.array[bwp_id - 1]; LOG_I(MAC, "[gNB %d][RAPROC] PUSCH with TC_RNTI %x received correctly, " "adding UE MAC Context UE_id %d/RNTI %04x\n", @@ -446,30 +509,256 @@ long get_K2(NR_BWP_Uplink_t *ubwp, int time_domain_assignment, int mu) { return 3; } -int8_t select_ul_harq_pid(NR_UE_sched_ctrl_t *sched_ctrl) { - const uint8_t max_ul_harq_pids = 3; // temp: for testing - // schedule active harq processes - for (uint8_t hrq_id = 0; hrq_id < max_ul_harq_pids; hrq_id++) { - NR_UE_ul_harq_t *cur_harq = &sched_ctrl->ul_harq_processes[hrq_id]; - if (cur_harq->state == ACTIVE_NOT_SCHED) { - LOG_D(MAC, "Found ulharq id %d, scheduling it for retransmission\n", hrq_id); - return hrq_id; +int next_list_entry_looped(NR_list_t *list, int UE_id) +{ + if (UE_id < 0) + return list->head; + return list->next[UE_id] < 0 ? list->head : list->next[UE_id]; +} + +float ul_thr_ue[MAX_MOBILES_PER_GNB]; +int bsr0ue = -1; +void pf_ul(module_id_t module_id, + frame_t frame, + sub_frame_t slot, + int num_slots_per_tdd, + NR_list_t *UE_list, + int n_rb_sched, + uint8_t *rballoc_mask, + int max_num_ue) { + + const int CC_id = 0; + const int tda = 1; + NR_ServingCellConfigCommon_t *scc = RC.nrmac[module_id]->common_channels[CC_id].ServingCellConfigCommon; + NR_UE_info_t *UE_info = &RC.nrmac[module_id]->UE_info; + const int min_rb = 5; + float coeff_ue[MAX_MOBILES_PER_GNB]; + // UEs that could be scheduled + int ue_array[MAX_MOBILES_PER_GNB]; + NR_list_t UE_sched = { .head = -1, .next = ue_array, .tail = -1, .len = MAX_MOBILES_PER_GNB }; + + /* Hack: currently, we do not have SR, and need to schedule UEs continuously. + * To keep the wasted resources low, we switch UEs to be scheduled in a + * round-robin fashion below, and only schedule a UE with BSR=0 if it is the + * selected one */ + bsr0ue = next_list_entry_looped(UE_list, bsr0ue); + + /* Loop UE_list to calculate throughput and coeff */ + for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { + NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + int rbStart = NRRIV2PRBOFFSET(sched_ctrl->active_bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + const uint16_t bwpSize = NRRIV2BW(sched_ctrl->active_ubwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + + /* Calculate throughput */ + const float a = 0.0005f; // corresponds to 200ms window + const uint32_t b = UE_info->mac_stats[UE_id].ulsch_current_bytes; + ul_thr_ue[UE_id] = (1 - a) * ul_thr_ue[UE_id] + a * b; + + /* Save PUSCH field */ + /* we want to avoid a lengthy deduction of DMRS and other parameters in + * every TTI if we can save it, so check whether dci_format, TDA, or + * num_dmrs_cdm_grps_no_data has changed and only then recompute */ + sched_ctrl->sched_pusch.time_domain_allocation = tda; + sched_ctrl->search_space = get_searchspace(sched_ctrl->active_bwp, NR_SearchSpace__searchSpaceType_PR_ue_Specific); + sched_ctrl->coreset = get_coreset(sched_ctrl->active_bwp, sched_ctrl->search_space, 1 /* dedicated */); + const long f = sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats; + const int dci_format = f ? NR_UL_DCI_FORMAT_0_1 : NR_UL_DCI_FORMAT_0_0; + const uint8_t num_dmrs_cdm_grps_no_data = 1; + NR_sched_pusch_save_t *ps = &sched_ctrl->pusch_save; + if (ps->time_domain_allocation != tda + || ps->dci_format != dci_format + || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) + nr_save_pusch_fields(scc, sched_ctrl->active_ubwp, dci_format, tda, num_dmrs_cdm_grps_no_data, ps); + + /* Check if retransmission is necessary */ + sched_ctrl->sched_pusch.ul_harq_pid = sched_ctrl->retrans_ul_harq.head; + if (sched_ctrl->sched_pusch.ul_harq_pid >= 0) { + /* RETRANSMISSION: Allocate retransmission*/ + /* Find free CCE */ + bool freeCCE = find_free_CCE(module_id, slot, UE_id); + if (!freeCCE) { + LOG_D(MAC, "%4d.%2d no free CCE for retransmission UL DCI UE %04x\n", frame, slot, UE_info->rnti[UE_id]); + continue; + } + /* reduce max_num_ue once we are sure UE can be allocated, i.e., has CCE */ + max_num_ue--; + if (max_num_ue < 0) + return; + + /* Save shced_frame and sched_slot before overwrite by previous PUSCH filed */ + NR_UE_ul_harq_t *cur_harq = &sched_ctrl->ul_harq_processes[sched_ctrl->sched_pusch.ul_harq_pid]; + cur_harq->sched_pusch.frame = sched_ctrl->sched_pusch.frame; + cur_harq->sched_pusch.slot = sched_ctrl->sched_pusch.slot; + /* Get previous PSUCH filed info */ + sched_ctrl->sched_pusch = cur_harq->sched_pusch; + NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; + LOG_D(MAC, "%4d.%2d Allocate UL retransmission UE %d/RNTI %04x sched %4d.%2d (%d RBs)\n", + frame, slot, UE_id, UE_info->rnti[UE_id], + sched_pusch->frame, sched_pusch->slot, + sched_pusch->rbSize); + + while (rbStart < bwpSize && !rballoc_mask[rbStart]) rbStart++; + if (rbStart + sched_pusch->rbSize >= bwpSize) { + LOG_W(MAC, "cannot allocate UL data for UE %d/RNTI %04x: no resources\n", + UE_id, UE_info->rnti[UE_id]); + return; + } + sched_pusch->rbStart = rbStart; + /* no need to recompute the TBS, it will be the same */ + + /* Mark the corresponding RBs as used */ + n_rb_sched -= sched_pusch->rbSize; + for (int rb = 0; rb < sched_ctrl->sched_pusch.rbSize; rb++) + rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] = 0; + + continue; + } + + /* Calculate TBS from MCS */ + NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; + const int mcs = 9; + sched_pusch->mcs = mcs; + sched_pusch->R = nr_get_code_rate_ul(mcs, ps->mcs_table); + sched_pusch->Qm = nr_get_Qm_ul(mcs, ps->mcs_table); + if (ps->pusch_Config->tp_pi2BPSK + && ((ps->mcs_table == 3 && mcs < 2) || (ps->mcs_table == 4 && mcs < 6))) { + sched_pusch->R >>= 1; + sched_pusch->Qm <<= 1; + } + + /* Check BSR and schedule UE if it is zero to avoid starvation, since we do + * not have SR (yet) */ + if (sched_ctrl->estimated_ul_buffer - sched_ctrl->sched_ul_bytes <= 0) { + if (UE_id != bsr0ue) + continue; + /* if no data, pre-allocate 5RB */ + bool freeCCE = find_free_CCE(module_id, slot, UE_id); + if (!freeCCE) { + LOG_D(MAC, "%4d.%2d no free CCE for UL DCI UE %04x (BSR 0)\n", frame, slot, UE_info->rnti[UE_id]); + continue; + } + /* reduce max_num_ue once we are sure UE can be allocated, i.e., has CCE */ + max_num_ue--; + if (max_num_ue < 0) + return; + + while (rbStart < bwpSize && !rballoc_mask[rbStart]) rbStart++; + if (rbStart + min_rb >= bwpSize) { + LOG_W(MAC, "cannot allocate UL data for UE %d/RNTI %04x: no resources\n", + UE_id, UE_info->rnti[UE_id]); + return; + } + sched_pusch->rbStart = rbStart; + sched_pusch->rbSize = min_rb; + sched_pusch->tb_size = nr_compute_tbs(sched_pusch->Qm, + sched_pusch->R, + sched_pusch->rbSize, + ps->nrOfSymbols, + ps->N_PRB_DMRS * ps->num_dmrs_symb, + 0, // nb_rb_oh + 0, + 1 /* NrOfLayers */) + >> 3; + + /* Mark the corresponding RBs as used */ + n_rb_sched -= sched_pusch->rbSize; + for (int rb = 0; rb < sched_ctrl->sched_pusch.rbSize; rb++) + rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] = 0; + + continue; } + + /* Create UE_sched for UEs eligibale for new data transmission*/ + add_tail_nr_list(&UE_sched, UE_id); + + /* Calculate coefficient*/ + const uint32_t tbs = nr_compute_tbs(sched_pusch->Qm, + sched_pusch->R, + 1, // rbSize + ps->nrOfSymbols, + ps->N_PRB_DMRS * ps->num_dmrs_symb, + 0, // nb_rb_oh + 0, + 1 /* NrOfLayers */) + >> 3; + coeff_ue[UE_id] = (float) tbs / ul_thr_ue[UE_id]; + LOG_D(MAC,"b %d, ul_thr_ue[%d] %f, tbs %d, coeff_ue[%d] %f\n", + b, UE_id, ul_thr_ue[UE_id], tbs, UE_id, coeff_ue[UE_id]); } - // schedule new harq processes - for (uint8_t hrq_id=0; hrq_id < max_ul_harq_pids; hrq_id++) { - NR_UE_ul_harq_t *cur_harq = &sched_ctrl->ul_harq_processes[hrq_id]; - if (cur_harq->state == INACTIVE) { - LOG_D(MAC, "Found new ulharq id %d, scheduling it\n", hrq_id); - return hrq_id; + + /* Loop UE_sched to find max coeff and allocate transmission */ + while (UE_sched.head >= 0 && max_num_ue> 0 && n_rb_sched > 0) { + /* Find max coeff */ + int *max = &UE_sched.head; /* Find max coeff: assume head is max */ + int *p = &UE_sched.next[*max]; + while (*p >= 0) { + /* Find max coeff: if the current one has larger coeff, save for later */ + if (coeff_ue[*p] > coeff_ue[*max]) + max = p; + p = &UE_sched.next[*p]; } + /* Find max coeff: remove the max one: do not use remove_nr_list() since it + * goes through the whole list every time. Note that UE_sched.tail might + * not be set correctly anymore */ + const int UE_id = *max; + p = &UE_sched.next[*max]; + *max = UE_sched.next[*max]; + *p = -1; + + bool freeCCE = find_free_CCE(module_id, slot, UE_id); + if (!freeCCE) { + LOG_D(MAC, "%4d.%2d no free CCE for UL DCI UE %04x\n", frame, slot, UE_info->rnti[UE_id]); + continue; + } + + /* reduce max_num_ue once we are sure UE can be allocated, i.e., has CCE */ + max_num_ue--; + if (max_num_ue < 0) + return; + + NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + int rbStart = NRRIV2PRBOFFSET(sched_ctrl->active_bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + const uint16_t bwpSize = NRRIV2BW(sched_ctrl->active_ubwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; + + + while (rbStart < bwpSize && !rballoc_mask[rbStart]) rbStart++; + sched_pusch->rbStart = rbStart; + if (rbStart + min_rb >= bwpSize) { + LOG_W(MAC, "cannot allocate UL data for UE %d/RNTI %04x: no resources\n", + UE_id, UE_info->rnti[UE_id]); + return; + } + + /* Calculate the current scheduling bytes */ + const int B = cmax(sched_ctrl->estimated_ul_buffer - sched_ctrl->sched_ul_bytes, 0); + uint16_t rbSize = min_rb - 1; + do { + rbSize++; + sched_pusch->rbSize = rbSize; + sched_pusch->tb_size = nr_compute_tbs(sched_pusch->Qm, + sched_pusch->R, + sched_pusch->rbSize, + sched_ctrl->pusch_save.nrOfSymbols, + sched_ctrl->pusch_save.N_PRB_DMRS * sched_ctrl->pusch_save.num_dmrs_symb, + 0, // nb_rb_oh + 0, + 1 /* NrOfLayers */) + >> 3; + } while (rbStart + rbSize < bwpSize && rballoc_mask[rbStart+rbSize] && + sched_pusch->tb_size < B); + LOG_D(MAC,"rbSize %d, TBS %d, est buf %d, sched_ul %d, B %d\n", + rbSize, sched_pusch->tb_size, sched_ctrl->estimated_ul_buffer, sched_ctrl->sched_ul_bytes, B); + + /* Mark the corresponding RBs as used */ + n_rb_sched -= sched_pusch->rbSize; + for (int rb = 0; rb < sched_ctrl->sched_pusch.rbSize; rb++) + rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] = 0; } - LOG_E(MAC, "All UL HARQ processes are busy. Cannot schedule ULSCH\n"); - return -1; } -void nr_simple_ulsch_preprocessor(module_id_t module_id, +bool nr_simple_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t slot, int num_slots_per_tdd, @@ -480,17 +769,14 @@ void nr_simple_ulsch_preprocessor(module_id_t module_id, const int mu = scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing; NR_UE_info_t *UE_info = &nr_mac->UE_info; - AssertFatal(UE_info->num_UEs <= 1, - "%s() cannot handle more than one UE, but found %d\n", - __func__, - UE_info->num_UEs); if (UE_info->num_UEs == 0) - return; + return false; - const int UE_id = 0; const int CC_id = 0; - NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + /* NOT support different K2 in here, Get the K2 for first UE */ + int UE_id = UE_info->list.head; + NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; const int tda = 1; const struct NR_PUSCH_TimeDomainResourceAllocationList *tdaList = sched_ctrl->active_ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; @@ -498,94 +784,59 @@ void nr_simple_ulsch_preprocessor(module_id_t module_id, "time domain assignment %d >= %d\n", tda, tdaList->list.count); + int K2 = get_K2(sched_ctrl->active_ubwp, tda, mu); - const int sched_frame = frame + (slot + K2 >= num_slots_per_tdd); - const int sched_slot = (slot + K2) % num_slots_per_tdd; + const int sched_frame = frame + (slot + K2 >= nr_slots_per_frame[mu]); + const int sched_slot = (slot + K2) % nr_slots_per_frame[mu]; if (!is_xlsch_in_slot(ulsch_in_slot_bitmap, sched_slot)) - return; - - /* get first, largest unallocated region */ - uint16_t *vrb_map_UL = - &RC.nrmac[module_id]->common_channels[CC_id].vrb_map_UL[sched_slot * 275]; - uint16_t rbStart = 0; - while (vrb_map_UL[rbStart]) rbStart++; - const uint16_t bwpSize = NRRIV2BW(sched_ctrl->active_ubwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - uint16_t rbSize = 1; - while (rbStart + rbSize < bwpSize && !vrb_map_UL[rbStart+rbSize]) - rbSize++; + return false; sched_ctrl->sched_pusch.slot = sched_slot; sched_ctrl->sched_pusch.frame = sched_frame; - const int target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific; - sched_ctrl->search_space = get_searchspace(sched_ctrl->active_bwp, target_ss); - uint8_t nr_of_candidates; - find_aggregation_candidates(&sched_ctrl->aggregation_level, - &nr_of_candidates, - sched_ctrl->search_space); - sched_ctrl->coreset = get_coreset( - sched_ctrl->active_bwp, sched_ctrl->search_space, 1 /* dedicated */); - const int cid = sched_ctrl->coreset->controlResourceSetId; - const uint16_t Y = UE_info->Y[UE_id][cid][slot]; - const int m = UE_info->num_pdcch_cand[UE_id][cid]; - sched_ctrl->cce_index = allocate_nr_CCEs(RC.nrmac[module_id], - sched_ctrl->active_bwp, - sched_ctrl->coreset, - sched_ctrl->aggregation_level, - Y, - m, - nr_of_candidates); - if (sched_ctrl->cce_index < 0) { - LOG_E(MAC, "%s(): CCE list not empty, couldn't schedule PUSCH\n", __func__); - return; - } - UE_info->num_pdcch_cand[UE_id][cid]++; - - sched_ctrl->sched_pusch.time_domain_allocation = tda; - const long f = sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats; - const int dci_format = f ? NR_UL_DCI_FORMAT_0_1 : NR_UL_DCI_FORMAT_0_0; - const uint8_t num_dmrs_cdm_grps_no_data = 1; - /* we want to avoid a lengthy deduction of DMRS and other parameters in - * every TTI if we can save it, so check whether dci_format, TDA, or - * num_dmrs_cdm_grps_no_data has changed and only then recompute */ - NR_sched_pusch_save_t *ps = &sched_ctrl->pusch_save; - if (ps->time_domain_allocation != tda - || ps->dci_format != dci_format - || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data) - nr_save_pusch_fields(scc, - sched_ctrl->active_ubwp, - dci_format, - tda, - num_dmrs_cdm_grps_no_data, - ps); - - const int mcs = 9; - NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; - sched_pusch->mcs = mcs; - sched_pusch->rbStart = rbStart; - sched_pusch->rbSize = rbSize; - - /* Calculate TBS from MCS */ - sched_pusch->R = nr_get_code_rate_ul(mcs, ps->mcs_table); - sched_pusch->Qm = nr_get_Qm_ul(mcs, ps->mcs_table); - if (ps->pusch_Config->tp_pi2BPSK - && ((ps->mcs_table == 3 && mcs < 2) || (ps->mcs_table == 4 && mcs < 6))) { - sched_pusch->R >>= 1; - sched_pusch->Qm <<= 1; + /* Confirm all the UE have same K2 as the first UE */ + for (UE_id = UE_info->list.next[UE_id]; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) { + NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + AssertFatal(K2 == get_K2(sched_ctrl->active_ubwp, tda, mu), + "Different K2, %d(UE%d) != %ld(UE%d)\n", K2, 0, get_K2(sched_ctrl->active_ubwp, tda, mu), UE_id); + sched_ctrl->sched_pusch.slot = sched_slot; + sched_ctrl->sched_pusch.frame = sched_frame; } - sched_pusch->tb_size = nr_compute_tbs(sched_pusch->Qm, - sched_pusch->R, - sched_pusch->rbSize, - ps->nrOfSymbols, - ps->N_PRB_DMRS * ps->num_dmrs_symb, - 0, // nb_rb_oh - 0, - 1 /* NrOfLayers */) - >> 3; - /* mark the corresponding RBs as used */ - for (int rb = 0; rb < sched_ctrl->sched_pusch.rbSize; rb++) - vrb_map_UL[rb + sched_ctrl->sched_pusch.rbStart] = 1; + /* Change vrb_map_UL to rballoc_mask */ + uint16_t *vrb_map_UL = + &RC.nrmac[module_id]->common_channels[CC_id].vrb_map_UL[sched_slot * MAX_BWP_SIZE]; + const uint16_t bwpSize = NRRIV2BW(sched_ctrl->active_ubwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + int st = 0, e = 0, len = 0; + for (int i = 0; i < bwpSize; i++) { + while (vrb_map_UL[i] == 1) + i++; + st = i; + while (vrb_map_UL[i] == 0) + i++; + if (i - st > len) { + len = i - st; + e = i - 1; + } + } + st = e - len + 1; + + uint8_t rballoc_mask[bwpSize]; + + /* Calculate mask: if any RB in vrb_map_UL is blocked (1), the current RB will be 0 */ + for (int i = 0; i < bwpSize; i++) + rballoc_mask[i] = i >= st && i <= e; + + /* proportional fair scheduling algorithm */ + pf_ul(module_id, + frame, + slot, + num_slots_per_tdd, + &UE_info->list, + len, + rballoc_mask, + 2); + return true; } void nr_schedule_ulsch(module_id_t module_id, @@ -594,14 +845,32 @@ void nr_schedule_ulsch(module_id_t module_id, int num_slots_per_tdd, int ul_slots, uint64_t ulsch_in_slot_bitmap) { - RC.nrmac[module_id]->pre_processor_ul( + /* Uplink data ONLY can be scheduled when the current slot is downlink slot, + * because we have to schedule the DCI0 first before schedule uplink data */ + if (is_xlsch_in_slot(ulsch_in_slot_bitmap, slot)) { + LOG_D(MAC, "Current slot %d is NOT DL slot, cannot schedule DCI0 for UL data\n", slot); + return; + } + bool do_sched = RC.nrmac[module_id]->pre_processor_ul( module_id, frame, slot, num_slots_per_tdd, ulsch_in_slot_bitmap); + if (!do_sched) + return; + + const int CC_id = 0; + nfapi_nr_ul_dci_request_t *ul_dci_req = &RC.nrmac[module_id]->UL_dci_req[CC_id]; + ul_dci_req->SFN = frame; + ul_dci_req->Slot = slot; + /* a PDCCH PDU groups DCIs per BWP and CORESET. Save a pointer to each + * allocated PDCCH so we can easily allocate UE's DCIs independent of any + * CORESET order */ + nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_bwp_coreset[MAX_NUM_BWP][MAX_NUM_CORESET] = {0}; NR_ServingCellConfigCommon_t *scc = RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon; NR_UE_info_t *UE_info = &RC.nrmac[module_id]->UE_info; - const NR_UE_list_t *UE_list = &UE_info->list; + const NR_list_t *UE_list = &UE_info->list; for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + UE_info->mac_stats[UE_id].ulsch_current_bytes = 0; /* dynamic PUSCH values (RB alloc, MCS, hence R, Qm, TBS) that change in * every TTI are pre-populated by the preprocessor and used below */ NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; @@ -610,11 +879,29 @@ void nr_schedule_ulsch(module_id_t module_id, uint16_t rnti = UE_info->rnti[UE_id]; - int8_t harq_id = select_ul_harq_pid(sched_ctrl); - if (harq_id < 0) return; + int8_t harq_id = sched_pusch->ul_harq_pid; + if (harq_id < 0) { + /* PP has not selected a specific HARQ Process, get a new one */ + harq_id = sched_ctrl->available_ul_harq.head; + AssertFatal(harq_id >= 0, + "no free HARQ process available for UE %d\n", + UE_id); + remove_front_nr_list(&sched_ctrl->available_ul_harq); + sched_pusch->ul_harq_pid = harq_id; + } else { + /* PP selected a specific HARQ process. Check whether it will be a new + * transmission or a retransmission, and remove from the corresponding + * list */ + if (sched_ctrl->ul_harq_processes[harq_id].round == 0) + remove_nr_list(&sched_ctrl->available_ul_harq, harq_id); + else + remove_nr_list(&sched_ctrl->retrans_ul_harq, harq_id); + } NR_UE_ul_harq_t *cur_harq = &sched_ctrl->ul_harq_processes[harq_id]; - cur_harq->state = ACTIVE_SCHED; - cur_harq->last_tx_slot = sched_pusch->slot; + DevAssert(!cur_harq->is_waiting); + add_tail_nr_list(&sched_ctrl->feedback_ul_harq, harq_id); + cur_harq->feedback_slot = sched_pusch->slot; + cur_harq->is_waiting = true; int rnti_types[2] = { NR_RNTI_C, 0 }; @@ -627,6 +914,9 @@ void nr_schedule_ulsch(module_id_t module_id, UE_info->mac_stats[UE_id].ulsch_rounds[cur_harq->round]++; if (cur_harq->round == 0) { UE_info->mac_stats[UE_id].ulsch_total_bytes_scheduled += sched_pusch->tb_size; + /* Save information on MCS, TBS etc for the current initial transmission + * so we have access to it when retransmitting */ + cur_harq->sched_pusch = *sched_pusch; } else { LOG_D(MAC, "%d.%2d UL retransmission RNTI %04x sched %d.%2d HARQ PID %d round %d NDI %d\n", @@ -639,6 +929,8 @@ void nr_schedule_ulsch(module_id_t module_id, cur_harq->round, cur_harq->ndi); } + UE_info->mac_stats[UE_id].ulsch_current_bytes = sched_pusch->tb_size; + sched_ctrl->sched_ul_bytes += sched_pusch->tb_size; LOG_D(MAC, "%4d.%2d RNTI %04x UL sched %4d.%2d start %d RBS %d MCS %d TBS %d HARQ PID %d round %d NDI %d\n", @@ -781,51 +1073,59 @@ void nr_schedule_ulsch(module_id_t module_id, pusch_pdu->pdu_bit_map &= ~PUSCH_PDU_BITMAP_PUSCH_PTRS; // disable PUSCH PTRS } - nfapi_nr_ul_dci_request_t *ul_dci_req = &RC.nrmac[module_id]->UL_dci_req[0]; - ul_dci_req->SFN = frame; - ul_dci_req->Slot = slot; - nfapi_nr_ul_dci_request_pdus_t *ul_dci_request_pdu = &ul_dci_req->ul_dci_pdu_list[ul_dci_req->numPdus]; - memset(ul_dci_request_pdu, 0, sizeof(nfapi_nr_ul_dci_request_pdus_t)); - ul_dci_request_pdu->PDUType = NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE; - ul_dci_request_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdcch_pdu)); - nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = &ul_dci_request_pdu->pdcch_pdu.pdcch_pdu_rel15; - ul_dci_req->numPdus += 1; + /* look up the PDCCH PDU for this BWP and CORESET. If it does not exist, + * create it */ + const int bwpid = sched_ctrl->active_bwp->bwp_Id; + const int coresetid = sched_ctrl->coreset->controlResourceSetId; + nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu = pdcch_pdu_bwp_coreset[bwpid][coresetid]; + if (!pdcch_pdu) { + nfapi_nr_ul_dci_request_pdus_t *ul_dci_request_pdu = &ul_dci_req->ul_dci_pdu_list[ul_dci_req->numPdus]; + memset(ul_dci_request_pdu, 0, sizeof(nfapi_nr_ul_dci_request_pdus_t)); + ul_dci_request_pdu->PDUType = NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE; + ul_dci_request_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdcch_pdu)); + pdcch_pdu = &ul_dci_request_pdu->pdcch_pdu.pdcch_pdu_rel15; + ul_dci_req->numPdus += 1; + nr_configure_pdcch(pdcch_pdu, sched_ctrl->search_space, sched_ctrl->coreset, scc, sched_ctrl->active_bwp); + pdcch_pdu_bwp_coreset[bwpid][coresetid] = pdcch_pdu; + } LOG_D(MAC,"Configuring ULDCI/PDCCH in %d.%d\n", frame,slot); - nr_configure_pdcch(RC.nrmac[0], - pdcch_pdu_rel15, - rnti, - sched_ctrl->search_space, - sched_ctrl->coreset, - scc, - sched_ctrl->active_bwp, - sched_ctrl->aggregation_level, - sched_ctrl->cce_index); - - dci_pdu_rel15_t dci_pdu_rel15[MAX_DCI_CORESET]; - memset(dci_pdu_rel15, 0, sizeof(dci_pdu_rel15)); + /* Fill PDCCH DL DCI PDU */ + nfapi_nr_dl_dci_pdu_t *dci_pdu = &pdcch_pdu->dci_pdu[pdcch_pdu->numDlDci]; + pdcch_pdu->numDlDci++; + dci_pdu->RNTI = rnti; + if (sched_ctrl->coreset->pdcch_DMRS_ScramblingID && + sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_ue_Specific) { + dci_pdu->ScramblingId = *sched_ctrl->coreset->pdcch_DMRS_ScramblingID; + dci_pdu->ScramblingRNTI = rnti; + } else { + dci_pdu->ScramblingId = *scc->physCellId; + dci_pdu->ScramblingRNTI = 0; + } + dci_pdu->AggregationLevel = sched_ctrl->aggregation_level; + dci_pdu->CceIndex = sched_ctrl->cce_index; + dci_pdu->beta_PDCCH_1_0 = 0; + dci_pdu->powerControlOffsetSS = 1; + + dci_pdu_rel15_t uldci_payload; + memset(&uldci_payload, 0, sizeof(uldci_payload)); NR_CellGroupConfig_t *secondaryCellGroup = UE_info->secondaryCellGroup[UE_id]; const int n_ubwp = secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count; - // NOTE: below functions assume that dci_formats is an array corresponding - // to all UL DCIs in the PDCCH, but for us it is a simple int. So before - // having multiple UEs, the below need to be changed (IMO the functions - // should fill for one DCI only and not handle all of them). config_uldci(sched_ctrl->active_ubwp, pusch_pdu, - pdcch_pdu_rel15, - &dci_pdu_rel15[0], - &ps->dci_format, + &uldci_payload, + ps->dci_format, ps->time_domain_allocation, UE_info->UE_sched_ctrl[UE_id].tpc0, n_ubwp, sched_ctrl->active_bwp->bwp_Id); fill_dci_pdu_rel15(scc, secondaryCellGroup, - pdcch_pdu_rel15, - dci_pdu_rel15, - &ps->dci_format, - rnti_types, + dci_pdu, + &uldci_payload, + ps->dci_format, + rnti_types[0], pusch_pdu->bwp_size, sched_ctrl->active_bwp->bwp_Id); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index a8dbec98f588fca335d3c7b1635495ac9a726bc3..26d29f9412815a4e778887a9cd909869bb1cda10 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -64,21 +64,9 @@ void clear_nr_nfapi_information(gNB_MAC_INST * gNB, void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame_rxP, sub_frame_t slot_rxP); -int nr_generate_dlsch_pdu(module_id_t Mod_idP, - NR_UE_sched_ctrl_t *ue_sched_ctl, - unsigned char *sdus_payload, - unsigned char *mac_pdu, - unsigned char num_sdus, - unsigned short *sdu_lengths, - unsigned char *sdu_lcids, - unsigned char drx_cmd, - unsigned char *ue_cont_res_id, - unsigned short post_padding); - void nr_schedule_ue_spec(module_id_t module_id, frame_t frame, - sub_frame_t slot, - int num_slots_per_tdd); + sub_frame_t slot); void schedule_control_sib1(module_id_t module_id, int CC_id, @@ -92,8 +80,7 @@ void schedule_nr_sib1(module_id_t module_idP, frame_t frameP, sub_frame_t subfra /* \brief default preprocessor */ void nr_simple_dlsch_preprocessor(module_id_t module_id, frame_t frame, - sub_frame_t slot, - int num_slots_per_tdd); + sub_frame_t slot); void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP, uint8_t slots_per_frame); @@ -105,7 +92,7 @@ void nr_schedule_ulsch(module_id_t module_id, int ul_slots, uint64_t ulsch_in_slot_bitmap); -void nr_simple_ulsch_preprocessor(module_id_t module_id, +bool nr_simple_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t slot, int num_slots_per_tdd, @@ -159,11 +146,10 @@ uint16_t nr_mac_compute_RIV(uint16_t N_RB_DL, uint16_t RBstart, uint16_t Lcrbs); * freq resources */ void nr_preprocessor_phytest(module_id_t module_id, frame_t frame, - sub_frame_t slot, - int num_slots_per_tdd); + sub_frame_t slot); /* \brief UL preprocessor for phytest: schedules UE_id 0 with fixed MCS on a * fixed set of resources */ -void nr_ul_preprocessor_phytest(module_id_t module_id, +bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_t slot, int num_slots_per_tdd, @@ -173,22 +159,6 @@ void nr_schedule_css_dlsch_phytest(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP); -void nr_fill_nfapi_dl_pdu(int Mod_id, - nfapi_nr_dl_tti_request_body_t *dl_req, - rnti_t rnti, - NR_CellGroupConfig_t *secondaryCellGroup, - NR_UE_sched_ctrl_t *sched_ctrl, - NR_sched_pucch *pucch_sched, - nfapi_nr_dmrs_type_e dmrsConfigType, - uint16_t R, - uint8_t Qm, - uint32_t tbs, - int StartSymbolIndex, - int NrOfSymbols, - int harq_pid, - int ndi, - int round); - void handle_nr_uci_pucch_0_1(module_id_t mod_id, frame_t frame, sub_frame_t slot, @@ -199,40 +169,30 @@ void handle_nr_uci_pucch_2_3_4(module_id_t mod_id, const nfapi_nr_uci_pucch_pdu_format_2_3_4_t *uci_234); -void config_uldci(NR_BWP_Uplink_t *ubwp, - nfapi_nr_pusch_pdu_t *pusch_pdu, - nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15, +void config_uldci(const NR_BWP_Uplink_t *ubwp, + const nfapi_nr_pusch_pdu_t *pusch_pdu, dci_pdu_rel15_t *dci_pdu_rel15, - int *dci_formats, - int time_domain_assignment, uint8_t tpc, - int n_ubwp, int bwp_id); + int dci_format, + int time_domain_assignment, + uint8_t tpc, + int n_ubwp, + int bwp_id); void nr_schedule_pucch(int Mod_idP, - int UE_id, - int nr_ulmix_slots, frame_t frameP, sub_frame_t slotP); -void csi_period_offset(NR_CSI_ReportConfig_t *csirep, +void csi_period_offset(const NR_CSI_ReportConfig_t *csirep, int *period, int *offset); void nr_csi_meas_reporting(int Mod_idP, - int UE_id, frame_t frameP, - sub_frame_t slotP, - int slots_per_tdd, - int ul_slots, - int n_slots_frame); + sub_frame_t slotP); -void nr_acknack_scheduling(int Mod_idP, +bool 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); - -int get_pucch_resource(NR_UE_info_t *UE_info,int UE_id,int k,int l); + sub_frame_t slotP); void get_pdsch_to_harq_feedback(int Mod_idP, int UE_id, @@ -271,26 +231,22 @@ void find_search_space(int ss_type, NR_BWP_Downlink_t *bwp, NR_SearchSpace_t *ss); -void nr_configure_pdcch(gNB_MAC_INST *nr_mac, - nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu, - uint16_t rnti, +void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu, NR_SearchSpace_t *ss, NR_ControlResourceSet_t *coreset, NR_ServingCellConfigCommon_t *scc, - NR_BWP_Downlink_t *bwp, - uint8_t aggregation_level, - int CCEIndex); + NR_BWP_Downlink_t *bwp); -void fill_dci_pdu_rel15(NR_ServingCellConfigCommon_t *scc, - NR_CellGroupConfig_t *secondaryCellGroup, - nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15, +void fill_dci_pdu_rel15(const NR_ServingCellConfigCommon_t *scc, + const NR_CellGroupConfig_t *secondaryCellGroup, + nfapi_nr_dl_dci_pdu_t *pdcch_dci_pdu, dci_pdu_rel15_t *dci_pdu_rel15, - int *dci_formats, - int *rnti_types, + int dci_formats, + int rnti_types, int N_RB, int bwp_id); -void prepare_dci(NR_CellGroupConfig_t *secondaryCellGroup, +void prepare_dci(const NR_CellGroupConfig_t *secondaryCellGroup, dci_pdu_rel15_t *dci_pdu_rel15, nr_dci_format_t format, int bwp_id); @@ -337,14 +293,21 @@ int NRRIV2BW(int locationAndBandwidth,int N_RB); int NRRIV2PRBOFFSET(int locationAndBandwidth,int N_RB); -void dump_nr_ue_list(NR_UE_list_t *listP); -void add_nr_ue_list(NR_UE_list_t *listP, int UE_id); +/* Functions to manage an NR_list_t */ +void dump_nr_list(NR_list_t *listP); +void create_nr_list(NR_list_t *listP, int len); +void destroy_nr_list(NR_list_t *list); +void add_nr_list(NR_list_t *listP, int id); +void remove_nr_list(NR_list_t *listP, int id); +void add_tail_nr_list(NR_list_t *listP, int id); +void add_front_nr_list(NR_list_t *listP, int id); +void remove_front_nr_list(NR_list_t *listP); int find_nr_UE_id(module_id_t mod_idP, rnti_t rntiP); int find_nr_RA_id(module_id_t mod_idP, int CC_idP, rnti_t rntiP); -int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP); +int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP, NR_CellGroupConfig_t *secondaryCellGroup); void mac_remove_nr_ue(module_id_t mod_id, rnti_t rnti); @@ -438,4 +401,5 @@ int16_t ssb_index_from_prach(module_id_t module_idP, void find_SSB_and_RO_available(module_id_t module_idP); +bool find_free_CCE(module_id_t module_id, sub_frame_t slot, int UE_id); #endif /*__LAYER2_NR_MAC_PROTO_H__*/ diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index 78a0dbb649ddbd8af9646e644b9fd60836d53bf5..8dc1303801a349378d3180dd23b6f3dfc45951f4 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -113,18 +113,9 @@ void mac_top_init_gNB(void) UE_info = &nrmac->UE_info; UE_info->num_UEs = 0; - UE_info->list.head = -1; + create_nr_list(&UE_info->list, MAX_MOBILES_PER_GNB); for (list_el = 0; list_el < MAX_MOBILES_PER_GNB; list_el++) { - UE_info->list.next[list_el] = -1; UE_info->active[list_el] = false; - for (int list_harq = 0; list_harq < NR_MAX_NB_HARQ_PROCESSES; list_harq++) { - UE_info->UE_sched_ctrl[list_el].harq_processes[list_harq].round = 0; - UE_info->UE_sched_ctrl[list_el].harq_processes[list_harq].ndi = 0; - UE_info->UE_sched_ctrl[list_el].harq_processes[list_harq].is_waiting = 0; - UE_info->UE_sched_ctrl[list_el].ul_harq_processes[list_harq].round = 0; - UE_info->UE_sched_ctrl[list_el].ul_harq_processes[list_harq].ndi = 0; - UE_info->UE_sched_ctrl[list_el].ul_harq_processes[list_harq].state = 0; - } } } diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 5f14a9db78702f8b0003952781c99e5869f2dc28..bca974a00f08644028788cbc97a99cc67844c293 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -75,10 +75,20 @@ #define MAX_NUM_BWP 2 #define MAX_NUM_CORESET 2 #define MAX_NUM_CCE 90 +#define MAX_HARQ_ROUNDS 4 /*!\brief Maximum number of random access process */ #define NR_NB_RA_PROC_MAX 4 #define MAX_NUM_OF_SSB 64 +/*! \brief NR_list_t is a "list" (of users, HARQ processes, slices, ...). + * Especially useful in the scheduler and to keep "classes" of users. */ +typedef struct { + int head; + int *next; + int tail; + int len; +} NR_list_t; + typedef enum { RA_IDLE = 0, Msg2 = 1, @@ -282,7 +292,7 @@ typedef struct NR_sched_pucch { uint8_t dai_c; uint8_t timing_indicator; uint8_t resource_indicator; -} NR_sched_pucch; +} NR_sched_pucch_t; /* this struct is a helper: as long as the TDA and DCI format remain the same * over the same uBWP and search space, there is no need to recalculate all @@ -326,13 +336,20 @@ typedef struct NR_sched_pusch { uint16_t R; uint8_t Qm; uint32_t tb_size; + + /// UL HARQ PID to use for this UE, or -1 for "any new" + int8_t ul_harq_pid; } NR_sched_pusch_t; typedef struct NR_UE_harq { - uint8_t is_waiting; + bool is_waiting; uint8_t ndi; uint8_t round; uint16_t feedback_slot; + + /* Transport block to be sent using this HARQ process */ + uint32_t tb[16384]; + uint32_t tb_size; } NR_UE_harq_t; typedef struct NR_UE_old_sched { @@ -350,10 +367,13 @@ typedef enum { } NR_UL_harq_states_t; typedef struct NR_UE_ul_harq { + bool is_waiting; uint8_t ndi; uint8_t round; - uint16_t last_tx_slot; - NR_UL_harq_states_t state; + uint16_t feedback_slot; + + /// sched_pusch keeps information on MCS etc used for the initial transmission + NR_sched_pusch_t sched_pusch; } NR_UE_ul_harq_t; @@ -387,10 +407,12 @@ typedef struct { /// the currently active BWP in UL NR_BWP_Uplink_t *active_ubwp; - NR_sched_pucch **sched_pucch; - /// selected PUCCH index, if scheduled - int pucch_sched_idx; - int pucch_occ_idx; + /// PUCCH scheduling information. Array of three, we assume for the moment: + /// HARQ in the first field, SR in second, CSI in third (as fixed by RRC + /// conf., i.e. if actually present). The order is important for + /// nr_acknack_scheduling()! + NR_sched_pucch_t sched_pucch[3]; + NR_sched_pusch_save_t pusch_save; NR_sched_pusch_t sched_pusch; @@ -404,6 +426,11 @@ typedef struct { uint16_t rbSize; uint16_t rbStart; + /// uplink bytes that are currently scheduled + int sched_ul_bytes; + /// estimation of the UL buffer size + int estimated_ul_buffer; + // time-domain allocation for scheduled RBs int time_domain_allocation; @@ -414,6 +441,8 @@ typedef struct { /// Retransmission-related information NR_UE_ret_info_t retInfo[NR_MAX_NB_HARQ_PROCESSES]; + /// DL HARQ PID to use for this UE, or -1 for "any new" + int8_t dl_harq_pid; uint16_t ta_frame; int16_t ta_update; @@ -421,8 +450,22 @@ typedef struct { uint8_t tpc0; uint8_t tpc1; uint16_t ul_rssi; + /// information about every HARQ process NR_UE_harq_t harq_processes[NR_MAX_NB_HARQ_PROCESSES]; + /// HARQ processes that are free + NR_list_t available_dl_harq; + /// HARQ processes that await feedback + NR_list_t feedback_dl_harq; + /// HARQ processes that await retransmission + NR_list_t retrans_dl_harq; + /// information about every UL HARQ process NR_UE_ul_harq_t ul_harq_processes[NR_MAX_NB_HARQ_PROCESSES]; + /// UL HARQ processes that are free + NR_list_t available_ul_harq; + /// UL HARQ processes that await feedback + NR_list_t feedback_ul_harq; + /// UL HARQ processes that await retransmission + NR_list_t retrans_ul_harq; int dummy; NR_UE_mac_ce_ctrl_t UE_mac_ce_ctrl;// MAC CE related information } NR_UE_sched_ctrl_t; @@ -438,22 +481,15 @@ typedef struct { int dlsch_rounds[8]; int dlsch_errors; int dlsch_total_bytes; + int dlsch_current_bytes; int ulsch_rounds[8]; int ulsch_errors; int ulsch_total_bytes_scheduled; int ulsch_total_bytes_rx; + int ulsch_current_bytes; } NR_mac_stats_t; - -/*! \brief UNR_E_list_t is a "list" of users within UE_info_t. Especial useful in - * the scheduler and to keep "classes" of users. */ -typedef struct { - int head; - int next[MAX_MOBILES_PER_GNB]; -} NR_UE_list_t; - - /*! \brief UE list used by gNB to order UEs/CC for scheduling*/ #define MAX_CSI_REPORTCONFIG 48 typedef struct { @@ -461,7 +497,7 @@ typedef struct { nr_csi_report_t csi_report_template[MAX_MOBILES_PER_GNB][MAX_CSI_REPORTCONFIG]; NR_UE_sched_ctrl_t UE_sched_ctrl[MAX_MOBILES_PER_GNB]; NR_mac_stats_t mac_stats[MAX_MOBILES_PER_GNB]; - NR_UE_list_t list; + NR_list_t list; int num_UEs; bool active[MAX_MOBILES_PER_GNB]; @@ -477,9 +513,8 @@ typedef struct { typedef void (*nr_pp_impl_dl)(module_id_t mod_id, frame_t frame, - sub_frame_t slot, - int num_slots_per_tdd); -typedef void (*nr_pp_impl_ul)(module_id_t mod_id, + sub_frame_t slot); +typedef bool (*nr_pp_impl_ul)(module_id_t mod_id, frame_t frame, sub_frame_t slot, int num_slots_per_tdd, @@ -510,6 +545,10 @@ typedef struct gNB_MAC_INST_s { nfapi_nr_config_request_scf_t config[NFAPI_CC_MAX]; /// NFAPI DL Config Request Structure nfapi_nr_dl_tti_request_t DL_req[NFAPI_CC_MAX]; + /// a PDCCH PDU groups DCIs per BWP and CORESET. The following structure + /// keeps pointers to PDCCH PDUs within DL_req so that we can easily track + /// PDCCH PDUs per CC/BWP/CORESET + nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_idx[NFAPI_CC_MAX][MAX_NUM_BWP][MAX_NUM_CORESET]; /// NFAPI UL TTI Request Structure, simple pointer into structure /// UL_tti_req_ahead for current frame/slot nfapi_nr_ul_tti_request_t *UL_tti_req[NFAPI_CC_MAX]; @@ -550,6 +589,10 @@ typedef struct gNB_MAC_INST_s { time_stats_t schedule_pch; /// CCE lists int cce_list[MAX_NUM_BWP][MAX_NUM_CORESET][MAX_NUM_CCE]; + /// PUCCH: keep track of the resources has already been used by saving the + /// highest index not yet been used in a given slot. Dynamically allocated + /// so we can have it for every slot as a function of the numerology + int *pucch_index_used[MAX_NUM_BWP]; /// DL preprocessor for differentiated scheduling nr_pp_impl_dl pre_processor_dl; diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index 0e6fd614a03b032836f664708db4716a0e48fa20..6195a91ea26037c7585768b6fde262223d24c8ee 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -220,7 +220,7 @@ static void *enb_tun_read_thread(void *_) exit(1); } -printf("\n\n\n########## nas_sock_fd read returns len %d\n", len); + LOG_D(PDCP, "%s(): nas_sock_fd read returns len %d\n", __func__, len); nr_pdcp_manager_lock(nr_pdcp_ue_manager); rnti = nr_pdcp_get_first_rnti(nr_pdcp_ue_manager); @@ -264,7 +264,7 @@ static void *ue_tun_read_thread(void *_) exit(1); } -printf("\n\n\n########## nas_sock_fd read returns len %d\n", len); + LOG_D(PDCP, "%s(): nas_sock_fd read returns len %d\n", __func__, len); nr_pdcp_manager_lock(nr_pdcp_ue_manager); rnti = nr_pdcp_get_first_rnti(nr_pdcp_ue_manager); diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c index 804f1e8a743e2451b33804b23993e0bc40e4b6f4..1d4efc1e264b19a25b5b5ffc4feb11d6ba933249 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c @@ -1581,7 +1581,7 @@ void nr_rlc_entity_am_recv_sdu(nr_rlc_entity_t *_entity, } if (entity->tx_size + size > entity->tx_maxsize) { - LOG_D(RLC, "%s:%d:%s: warning: SDU rejected, SDU buffer full\n", + LOG_E(RLC, "%s:%d:%s: warning: SDU rejected, SDU buffer full\n", __FILE__, __LINE__, __FUNCTION__); return; } diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c index d3503742ad03819b2b46e8ab03a79723719cc8b4..9c139624ebddeb846e6c4d26546e4f80c24556fd 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c @@ -668,8 +668,8 @@ static void add_srb(int rnti, struct LTE_SRB_ToAddMod *s) poll_byte = -1; max_retx_threshold = 8; sn_field_length = 12; - nr_rlc_am = new_nr_rlc_entity_am(100000, - 100000, + nr_rlc_am = new_nr_rlc_entity_am(10000000, + 10000000, deliver_sdu, ue, successful_delivery, ue, max_retx_reached, ue, @@ -751,8 +751,8 @@ static void add_drb_am(int rnti, struct NR_DRB_ToAddMod *s, NR_RLC_BearerConfig_ if (ue->drb[drb_id-1] != NULL) { LOG_W(RLC, "%s:%d:%s: DRB %d already exists for UE with RNTI %d, do nothing\n", __FILE__, __LINE__, __FUNCTION__, drb_id, rnti); } else { - nr_rlc_am = new_nr_rlc_entity_am(100000, - 100000, + nr_rlc_am = new_nr_rlc_entity_am(10000000, + 10000000, deliver_sdu, ue, successful_delivery, ue, max_retx_reached, ue, @@ -823,8 +823,8 @@ static void add_drb_um(int rnti, struct NR_DRB_ToAddMod *s, NR_RLC_BearerConfig_ if (ue->drb[drb_id-1] != NULL) { LOG_W(RLC, "DEBUG add_drb_um %s:%d:%s: warning DRB %d already exist for ue %d, do nothing\n", __FILE__, __LINE__, __FUNCTION__, drb_id, rnti); } else { - nr_rlc_um = new_nr_rlc_entity_um(1000000, - 1000000, + nr_rlc_um = new_nr_rlc_entity_um(100000000, + 100000000, deliver_sdu, ue, t_reassembly, sn_field_length); diff --git a/openair2/NETWORK_DRIVER/LITE/device.c b/openair2/NETWORK_DRIVER/LITE/device.c index 854c3bcc997b07b4231b088a2eabd9215d8e6f42..59340784c1878dba848f180317bcb82227bd80db 100644 --- a/openair2/NETWORK_DRIVER/LITE/device.c +++ b/openair2/NETWORK_DRIVER/LITE/device.c @@ -316,7 +316,11 @@ void oai_nw_drv_change_rx_flags(struct net_device *dev, int flags) } //--------------------------------------------------------------------------- +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0) +void oai_nw_drv_tx_timeout(struct net_device *dev, unsigned int txqueue) +#else void oai_nw_drv_tx_timeout(struct net_device *dev) +#endif { //--------------------------------------------------------------------------- // Transmitter timeout, serious problems. diff --git a/openair2/NETWORK_DRIVER/MESH/device.c b/openair2/NETWORK_DRIVER/MESH/device.c index 181899cd6eca3f7a14f6c5cbe9e283e6ff268ec9..47c68466bdc77a0eb65c2936dab0d38e864ae0a1 100644 --- a/openair2/NETWORK_DRIVER/MESH/device.c +++ b/openair2/NETWORK_DRIVER/MESH/device.c @@ -297,10 +297,10 @@ int nas_change_mtu(struct net_device *dev, int mtu) } //--------------------------------------------------------------------------- -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,7,0) -void nas_tx_timeout(struct net_device *dev) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0) +void nas_tx_timeout(struct net_device *dev, unsigned int txqueue) #else -void nas_tx_timeout(struct net_device *dev, unsigned int x) +void nas_tx_timeout(struct net_device *dev) #endif { //--------------------------------------------------------------------------- diff --git a/openair2/NETWORK_DRIVER/UE_IP/device.c b/openair2/NETWORK_DRIVER/UE_IP/device.c index 32f9442747d3445c067a84ab716f0260c68c6df6..63184eb6da60ff04fbde92ce2e4217a07fc28593 100644 --- a/openair2/NETWORK_DRIVER/UE_IP/device.c +++ b/openair2/NETWORK_DRIVER/UE_IP/device.c @@ -302,7 +302,12 @@ void ue_ip_change_rx_flags(struct net_device *dev_pP, int flagsP) { } //--------------------------------------------------------------------------- -void ue_ip_tx_timeout(struct net_device *dev_pP) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0) +void ue_ip_tx_timeout(struct net_device *dev_pP, unsigned int txqueue) +#else +void ue_ip_tx_timeout(struct net_device *dev_pP) +#endif +{ //--------------------------------------------------------------------------- // Transmitter timeout, serious problems. ue_ip_priv_t *priv_p = netdev_priv(dev_pP); diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c index 7f98dd6a3ebf113050d8a557f8ce76c4a17486ee..b5cda6ecd63e2d19f8af88f85c86b466391b59b0 100644 --- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c @@ -104,6 +104,9 @@ void handle_nr_uci(NR_UL_IND_t *UL_info) } UL_info->uci_ind.num_ucis = 0; + // mark corresponding PUCCH resources as free + // NOTE: we just assume it is BWP ID 1, to be revised for multiple BWPs + RC.nrmac[mod_id]->pucch_index_used[1][slot] = 0; } diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c index adf3dfe2a8e81b888f0ccc029e76134a971eec17..aebdc2f1cc9b260dda194bbae0fcc96e3461ab87 100644 --- a/openair2/RRC/NR/rrc_gNB_reconfig.c +++ b/openair2/RRC/NR/rrc_gNB_reconfig.c @@ -1177,7 +1177,8 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco secondaryCellGroup->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup = pdsch_servingcellconfig; pdsch_servingcellconfig->codeBlockGroupTransmission = NULL; pdsch_servingcellconfig->xOverhead = NULL; - pdsch_servingcellconfig->nrofHARQ_ProcessesForPDSCH = NULL; + pdsch_servingcellconfig->nrofHARQ_ProcessesForPDSCH = calloc(1, sizeof(*pdsch_servingcellconfig->nrofHARQ_ProcessesForPDSCH)); + *pdsch_servingcellconfig->nrofHARQ_ProcessesForPDSCH = NR_PDSCH_ServingCellConfig__nrofHARQ_ProcessesForPDSCH_n16; pdsch_servingcellconfig->pucch_Cell= NULL; pdsch_servingcellconfig->ext1=calloc(1,sizeof(*pdsch_servingcellconfig->ext1)); pdsch_servingcellconfig->ext1->maxMIMO_Layers = calloc(1,sizeof(*pdsch_servingcellconfig->ext1->maxMIMO_Layers)); diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf index 1cd3b01b6c7aa6bfde7052ce0fb15b11a409f923..760689f653f19bb50f79afd99850d53a46784437 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf @@ -1,7 +1,6 @@ Active_gNBs = ( "gNB-Eurecom-5GNRBox"); # Asn1_verbosity, choice in: none, info, annoying Asn1_verbosity = "none"; -Num_Threads_PUSCH = 8; gNBs = ( @@ -234,6 +233,7 @@ L1s = ( { num_cc = 1; tr_n_preference = "local_mac"; + pusch_proc_threads = 8; } ); @@ -246,7 +246,7 @@ RUs = ( att_rx = 0; bands = [7]; max_pdschReferenceSignalPower = -27; - max_rxgain = 75; + max_rxgain = 50; eNB_instances = [0]; ##beamforming 1x2 matrix: 1 layer x 2 antennas bf_weights = [0x00007fff, 0x0000]; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf index e34b26150092b902660cdf8b9fb43ef7595e82ff..555af5835d368647559077be618610c792dfe52a 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf @@ -1,7 +1,6 @@ Active_gNBs = ( "gNB-Eurecom-5GNRBox"); # Asn1_verbosity, choice in: none, info, annoying Asn1_verbosity = "none"; -Num_Threads_PUSCH = 8; gNBs = ( @@ -250,6 +249,7 @@ L1s = ( { num_cc = 1; tr_n_preference = "local_mac"; + pusch_proc_threads = 8; } );