/* * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under * the OAI Public License, Version 1.0 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * * http://www.openairinterface.org/?page_id=698 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance: * contact@openairinterface.org */ /*! \file phy_procedures_lte_eNB.c * \brief Implementation of eNB procedures from 36.213 LTE specifications * \author R. Knopp, F. Kaltenberger, N. Nikaein, X. Foukas * \date 2011 * \version 0.1 * \company Eurecom * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr,navid.nikaein@eurecom.fr, x.foukas@sms.ed.ac.uk * \note * \warning */ #include "PHY/defs.h" #include "PHY/extern.h" #include "SCHED/defs.h" #include "SCHED/extern.h" #include "nfapi_interface.h" #include "fapi_l1.h" #include "UTIL/LOG/log.h" #include "UTIL/LOG/vcd_signal_dumper.h" #include "T.h" #include "assertions.h" #include "msc.h" #include <time.h> #if defined(ENABLE_ITTI) # include "intertask_interface.h" #endif void pmch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,PHY_VARS_RN *rn,relaying_type_t r_type) { #if defined(Rel10) || defined(Rel14) MCH_PDU *mch_pduP=NULL; MCH_PDU mch_pdu; // uint8_t sync_area=255; #endif int subframe = proc->subframe_tx; AssertFatal(1==0,"pmch not tested for the moment, exiting\n"); // This is DL-Cell spec pilots in Control region generate_pilots_slot(eNB, eNB->common_vars.txdataF, AMP, subframe<<1,1); #if defined(Rel10) || defined(Rel14) // if mcch is active, send regardless of the node type: eNB or RN // when mcch is active, MAC sched does not allow MCCH and MTCH multiplexing /* mch_pduP = mac_xface->get_mch_sdu(eNB->Mod_id, eNB->CC_id, proc->frame_tx, subframe); */ switch (r_type) { case no_relay: if ((mch_pduP->Pdu_size > 0) && (mch_pduP->sync_area == 0)) // TEST: only transmit mcch for sync area 0 LOG_D(PHY,"[eNB%"PRIu8"] Frame %d subframe %d : Got MCH pdu for MBSFN (MCS %"PRIu8", TBS %d) \n", eNB->Mod_id,proc->frame_tx,subframe,mch_pduP->mcs, eNB->dlsch_MCH->harq_processes[0]->TBS>>3); else { LOG_D(PHY,"[DeNB %"PRIu8"] Frame %d subframe %d : Do not transmit MCH pdu for MBSFN sync area %"PRIu8" (%s)\n", eNB->Mod_id,proc->frame_tx,subframe,mch_pduP->sync_area, (mch_pduP->Pdu_size == 0)? "Empty MCH PDU":"Let RN transmit for the moment"); mch_pduP = NULL; } break; case multicast_relay: if ((mch_pduP->Pdu_size > 0) && ((mch_pduP->mcch_active == 1) || mch_pduP->msi_active==1)) { LOG_D(PHY,"[RN %"PRIu8"] Frame %d subframe %d: Got the MCH PDU for MBSFN sync area %"PRIu8" (MCS %"PRIu8", TBS %"PRIu16")\n", rn->Mod_id,rn->frame, subframe, mch_pduP->sync_area,mch_pduP->mcs,mch_pduP->Pdu_size); } else if (rn->mch_avtive[subframe%5] == 1) { // SF2 -> SF7, SF3 -> SF8 mch_pduP= &mch_pdu; memcpy(&mch_pduP->payload, // could be a simple copy rn->dlsch_rn_MCH[subframe%5]->harq_processes[0]->b, rn->dlsch_rn_MCH[subframe%5]->harq_processes[0]->TBS>>3); mch_pduP->Pdu_size = (uint16_t) (rn->dlsch_rn_MCH[subframe%5]->harq_processes[0]->TBS>>3); mch_pduP->mcs = rn->dlsch_rn_MCH[subframe%5]->harq_processes[0]->mcs; LOG_D(PHY,"[RN %"PRIu8"] Frame %d subframe %d: Forward the MCH PDU for MBSFN received on SF %d sync area %"PRIu8" (MCS %"PRIu8", TBS %"PRIu16")\n", rn->Mod_id,rn->frame, subframe,subframe%5, rn->sync_area[subframe%5],mch_pduP->mcs,mch_pduP->Pdu_size); } else { mch_pduP=NULL; } rn->mch_avtive[subframe]=0; break; default: LOG_W(PHY,"[eNB %"PRIu8"] Frame %d subframe %d: unknown relaying type %d \n", eNB->Mod_id,proc->frame_tx,subframe,r_type); mch_pduP=NULL; break; }// switch if (mch_pduP) { fill_eNB_dlsch_MCH(eNB,mch_pduP->mcs,1,0); // Generate PMCH generate_mch(eNB,proc,(uint8_t*)mch_pduP->payload); } else { LOG_D(PHY,"[eNB/RN] Frame %d subframe %d: MCH not generated \n",proc->frame_tx,subframe); } #endif } void common_signal_procedures (PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) { LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; int **txdataF = eNB->common_vars.txdataF; uint8_t *pbch_pdu=&eNB->pbch_pdu[0]; int subframe = proc->subframe_tx; int frame = proc->frame_tx; LOG_D(PHY,"common_signal_procedures: frame %d, subframe %d\n",frame,subframe); // generate Cell-Specific Reference Signals for both slots VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_RS_TX,1); generate_pilots_slot(eNB, txdataF, AMP, subframe<<1,0); // check that 2nd slot is for DL if (subframe_select(fp,subframe) == SF_DL) generate_pilots_slot(eNB, txdataF, AMP, (subframe<<1)+1,0); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_RS_TX,0); // First half of PSS/SSS (FDD, slot 0) if (subframe == 0) { if (fp->frame_type == FDD) { generate_pss(txdataF, AMP, fp, (fp->Ncp==NORMAL) ? 6 : 5, 0); generate_sss(txdataF, AMP, fp, (fp->Ncp==NORMAL) ? 5 : 4, 0); } /// First half of SSS (TDD, slot 1) if (fp->frame_type == TDD) { generate_sss(txdataF, AMP, fp, (fp->Ncp==NORMAL) ? 6 : 5, 1); } // generate PBCH (Physical Broadcast CHannel) info /// generate PBCH if ((frame&3)==0) { AssertFatal(eNB->pbch_configured==1,"PBCH was not configured by MAC\n"); eNB->pbch_configured=0; } generate_pbch(&eNB->pbch, txdataF, AMP, fp, pbch_pdu, frame&3); } else if ((subframe == 1) && (fp->frame_type == TDD)){ generate_pss(txdataF, AMP, fp, 2, 2); } // Second half of PSS/SSS (FDD, slot 10) else if ((subframe == 5) && (fp->frame_type == FDD)) { generate_pss(txdataF, AMP, &eNB->frame_parms, (fp->Ncp==NORMAL) ? 6 : 5, 10); generate_sss(txdataF, AMP, &eNB->frame_parms, (fp->Ncp==NORMAL) ? 5 : 4, 10); } // Second-half of SSS (TDD, slot 11) else if ((subframe == 5) && (fp->frame_type == TDD)) { generate_sss(txdataF, AMP, fp, (fp->Ncp==NORMAL) ? 6 : 5, 11); } // Second half of PSS (TDD, slot 12) else if ((subframe == 6) && (fp->frame_type == TDD)) { generate_pss(txdataF, AMP, fp, 2, 12); } } void pdsch_procedures(PHY_VARS_eNB *eNB, eNB_rxtx_proc_t *proc, int harq_pid, LTE_eNB_DLSCH_t *dlsch, LTE_eNB_DLSCH_t *dlsch1, LTE_eNB_UE_stats *ue_stats, int ra_flag) { int frame=proc->frame_tx; int subframe=proc->subframe_tx; LTE_DL_eNB_HARQ_t *dlsch_harq=dlsch->harq_processes[harq_pid]; int input_buffer_length = dlsch_harq->TBS/8; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; if (dlsch->rnti == 0x02) {//frame < 200) { LOG_I(PHY, "[eNB %"PRIu8"][PDSCH %"PRIx16"/%"PRIu8"] Frame %d, subframe %d: Generating PDSCH/DLSCH with input size = %"PRIu16", pdsch_start %d, G %d, nb_rb %"PRIu16", rb0 %x, rb1 %x, TBS %"PRIu16", pmi_alloc %"PRIx64", rv %"PRIu8" (round %"PRIu8")\n", eNB->Mod_id, dlsch->rnti,harq_pid, frame, subframe, input_buffer_length, dlsch_harq->pdsch_start, get_G(fp, dlsch_harq->nb_rb, dlsch_harq->rb_alloc, dlsch_harq->Qm, dlsch_harq->Nl, dlsch_harq->pdsch_start, frame, subframe, dlsch_harq->mimo_mode==TM7?7:0), dlsch_harq->nb_rb, dlsch_harq->rb_alloc[0], dlsch_harq->rb_alloc[1], dlsch_harq->TBS, pmi2hex_2Ar1(dlsch_harq->pmi_alloc), dlsch_harq->rvidx, dlsch_harq->round); } #if defined(MESSAGE_CHART_GENERATOR_PHY) MSC_LOG_TX_MESSAGE( MSC_PHY_ENB,MSC_PHY_UE, NULL,0, "%05u:%02u PDSCH/DLSCH input size = %"PRIu16", G %d, nb_rb %"PRIu16", TBS %"PRIu16", pmi_alloc %"PRIx16", rv %"PRIu8" (round %"PRIu8")", frame, subframe, input_buffer_length, get_G(fp, dlsch_harq->nb_rb, dlsch_harq->rb_alloc, dlsch_harq->Qm, dlsch_harq->Nl, dlsch_harq->pdsch_start, frame, subframe, dlsch_harq->mimo_mode==TM7?7:0), dlsch_harq->nb_rb, dlsch_harq->TBS, pmi2hex_2Ar1(dlsch_harq->pmi_alloc), dlsch_harq->rvidx, dlsch_harq->round); #endif if (ue_stats) ue_stats->dlsch_sliding_cnt++; if (dlsch_harq->round == 0) { if (ue_stats) ue_stats->dlsch_trials[harq_pid][0]++; } else { ue_stats->dlsch_trials[harq_pid][dlsch_harq->round]++; #ifdef DEBUG_PHY_PROC #ifdef DEBUG_DLSCH LOG_D(PHY,"[eNB] This DLSCH is a retransmission\n"); #endif #endif } LOG_D(PHY,"Generating DLSCH/PDSCH %d\n",ra_flag); // 36-212 start_meas(&eNB->dlsch_encoding_stats); AssertFatal(dlsch_harq->pdu!=NULL,"dlsch_harq->pdu == NULL (rnti %x)\n",dlsch->rnti); eNB->te(eNB, dlsch_harq->pdu, dlsch_harq->pdsch_start, dlsch, frame,subframe, &eNB->dlsch_rate_matching_stats, &eNB->dlsch_turbo_encoding_stats, &eNB->dlsch_interleaving_stats); stop_meas(&eNB->dlsch_encoding_stats); // 36-211 start_meas(&eNB->dlsch_scrambling_stats); dlsch_scrambling(fp, 0, dlsch, harq_pid, get_G(fp, dlsch_harq->nb_rb, dlsch_harq->rb_alloc, dlsch_harq->Qm, dlsch_harq->Nl, dlsch_harq->pdsch_start, frame,subframe, 0), 0, frame, subframe<<1); stop_meas(&eNB->dlsch_scrambling_stats); start_meas(&eNB->dlsch_modulation_stats); dlsch_modulation(eNB, eNB->common_vars.txdataF, AMP, subframe, dlsch_harq->pdsch_start, dlsch, dlsch1); stop_meas(&eNB->dlsch_modulation_stats); dlsch->active = 0; dlsch_harq->round++; } void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, eNB_rxtx_proc_t *proc, relaying_type_t r_type, PHY_VARS_RN *rn, int do_meas) { UNUSED(rn); int frame=proc->frame_tx; int subframe=proc->subframe_tx; uint32_t i,aa; uint8_t harq_pid; int8_t UE_id=0; uint8_t num_pdcch_symbols=0; uint8_t num_dci=0; uint8_t ul_subframe; uint32_t ul_frame; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; LTE_UL_eNB_HARQ_t *ulsch_harq; int offset = eNB->CC_id;//proc == &eNB->proc.proc_rxtx[0] ? 0 : 1; if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)==SF_UL)) return; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_TX+offset,1); if (do_meas==1) start_meas(&eNB->phy_proc_tx); // clear the transmit data array for the current subframe for (aa=0; aa<fp->nb_antenna_ports_eNB; aa++) { memset(&eNB->common_vars.txdataF[aa][subframe*fp->ofdm_symbol_size*(fp->symbols_per_tti)], 0,fp->ofdm_symbol_size*(fp->symbols_per_tti)*sizeof(int32_t)); } if (is_pmch_subframe(frame,subframe,fp)) { pmch_procedures(eNB,proc,rn,r_type); } else { // this is not a pmch subframe, so generate PSS/SSS/PBCH common_signal_procedures(eNB,proc); } // clear existing ulsch dci allocations before applying info from MAC (this is table ul_subframe = pdcch_alloc2ul_subframe(fp,subframe); ul_frame = pdcch_alloc2ul_frame(fp,frame,subframe); // clear previous allocation information for all UEs for (i=0; i<NUMBER_OF_UE_MAX; i++) { if (eNB->dlsch[i][0]) eNB->dlsch[i][0]->subframe_tx[subframe] = 0; } /* save old HARQ information needed for PHICH generation */ for (i=0; i<NUMBER_OF_UE_MAX; i++) { harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe); if (eNB->ulsch[i]) { ulsch_harq = eNB->ulsch[i]->harq_processes[harq_pid]; /* Store first_rb and n_DMRS for correct PHICH generation below. * For PHICH generation we need "old" values of last scheduling * for this HARQ process. 'generate_eNB_dlsch_params' below will * overwrite first_rb and n_DMRS and 'generate_phich_top', done * after 'generate_eNB_dlsch_params', would use the "new" values * instead of the "old" ones. * * This has been tested for FDD only, may be wrong for TDD. * * TODO: maybe we should restructure the code to be sure it * is done correctly. The main concern is if the code * changes and first_rb and n_DMRS are modified before * we reach here, then the PHICH processing will be wrong, * using wrong first_rb and n_DMRS values to compute * ngroup_PHICH and nseq_PHICH. * * TODO: check if that works with TDD. */ if ((subframe_select(fp,ul_subframe)==SF_UL) || (fp->frame_type == FDD)) { ulsch_harq->previous_first_rb = ulsch_harq->first_rb; ulsch_harq->previous_n_DMRS = ulsch_harq->n_DMRS; } } } // num_pdcch_symbols = DCI_pdu->num_pdcch_symbols; num_pdcch_symbols = eNB->pdcch_vars[subframe&1].num_pdcch_symbols; num_dci = eNB->pdcch_vars[subframe&1].num_dci; // LOG_D(PHY,"num_pdcch_symbols %"PRIu8",(dci common %"PRIu8", dci uespec %"PRIu8"\n",num_pdcch_symbols, // DCI_pdu->Num_common_dci,DCI_pdu->Num_ue_spec_dci); LOG_D(PHY,"num_pdcch_symbols %"PRIu8",(number dci %"PRIu8"\n",num_pdcch_symbols, num_dci); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,num_pdcch_symbols); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,(frame*10)+subframe); if (num_dci > 0) LOG_D(PHY,"[eNB %"PRIu8"] Frame %d, subframe %d: Calling generate_dci_top (pdcch) (num_dci %"PRIu8")\n",eNB->Mod_id,frame, subframe, num_dci); generate_dci_top(num_pdcch_symbols, num_dci, &eNB->pdcch_vars[subframe&1].dci_alloc[0], 0, AMP, fp, eNB->common_vars.txdataF, subframe); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PDCCH_TX,0); // Now scan UE specific DLSCH LTE_eNB_DLSCH_t *dlsch0,*dlsch1; for (UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) { dlsch0 = eNB->dlsch[(uint8_t)UE_id][0]; dlsch1 = eNB->dlsch[(uint8_t)UE_id][1]; if ((dlsch0)&& (dlsch0->rnti>0)&& (dlsch0->active == 1)) { // get harq_pid harq_pid = dlsch0->harq_ids[subframe]; AssertFatal(harq_pid>=0,"harq_pid is negative\n"); // generate pdsch pdsch_procedures(eNB, proc, harq_pid, dlsch0, dlsch1, &eNB->UE_stats[(uint32_t)UE_id], 0); } else if ((dlsch0)&& (dlsch0->rnti>0)&& (dlsch0->active == 0)) { // clear subframe TX flag since UE is not scheduled for PDSCH in this subframe (so that we don't look for PUCCH later) dlsch0->subframe_tx[subframe]=0; } } generate_phich_top(eNB, proc, AMP); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_TX+offset,0); if (do_meas==1) stop_meas(&eNB->phy_proc_tx); } void prach_procedures(PHY_VARS_eNB *eNB, #ifdef Rel14 int br_flag #endif ) { uint16_t max_preamble[4],max_preamble_energy[4],max_preamble_delay[4]; uint16_t i; int frame,subframe; LTE_eNB_PRACH *prach_vars=NULL; #ifdef Rel14 if (br_flag==1) { subframe = eNB->proc.subframe_prach_br; frame = eNB->proc.frame_prach_br; pthread_mutex_lock(&eNB->UL_INFO_mutex); eNB->UL_INFO.rach_ind_br.number_of_preambles=0; pthread_mutex_unlock(&eNB->UL_INFO_mutex); } else #endif { pthread_mutex_lock(&eNB->UL_INFO_mutex); eNB->UL_INFO.rach_ind.number_of_preambles=0; pthread_mutex_unlock(&eNB->UL_INFO_mutex); subframe = eNB->proc.subframe_prach; frame = eNB->proc.frame_prach; } RU_t *ru; int aa=0; int ru_aa; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,1); for (i=0;i<eNB->num_RU;i++) { ru=eNB->RU_list[i]; for (ru_aa=0,aa=0;ru_aa<ru->nb_rx;ru_aa++,aa++) { eNB->prach_vars.rxsigF[0][aa] = eNB->RU_list[i]->prach_rxsigF[ru_aa]; #ifdef Rel14 int ce_level; if (br_flag==1) for (ce_level=0;ce_level<4;ce_level++) eNB->prach_vars_br.rxsigF[ce_level][aa] = eNB->RU_list[i]->prach_rxsigF_br[ce_level][ru_aa]; #endif } } rx_prach(eNB, eNB->RU_list[0], &max_preamble[0], &max_preamble_energy[0], &max_preamble_delay[0], frame, 0 #ifdef Rel14 ,br_flag #endif ); //#ifdef DEBUG_PHY_PROC LOG_D(PHY,"[RAPROC] Frame %d, subframe %d : Most likely preamble %d, energy %d dB delay %d\n", frame,subframe, max_preamble[0], max_preamble_energy[0]/10, max_preamble_delay[0]); //q#endif #ifdef Rel14 if (br_flag==1) { prach_vars = &eNB->prach_vars_br; int prach_mask; prach_mask = is_prach_subframe(&eNB->frame_parms,eNB->proc.frame_prach_br,eNB->proc.subframe_prach_br); eNB->UL_INFO.rach_ind_br.preamble_list = eNB->preamble_list_br; int ind=0; int ce_level=0; /* Save for later, it doesn't work for (int ind=0,ce_level=0;ce_level<4;ce_level++) { if ((eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[ce_level]==1)&& (prach_mask&(1<<(1+ce_level)) > 0) && // prach is active and CE level has finished its repetitions (eNB->prach_vars_br.repetition_number[ce_level]== eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[ce_level])) { */ if (eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[0]==1){ if (max_preamble_energy[0] > 350) { eNB->UL_INFO.rach_ind_br.number_of_preambles++; eNB->preamble_list_br[ind].preamble_rel8.timing_advance = max_preamble_delay[ind];// eNB->preamble_list_br[ind].preamble_rel8.preamble = max_preamble[ind]; // note: fid is implicitly 0 here, this is the rule for eMTC RA-RNTI from 36.321, Section 5.1.4 eNB->preamble_list_br[ind].preamble_rel8.rnti = 1+subframe+(eNB->prach_vars_br.first_frame[ce_level]%40); eNB->preamble_list_br[ind].instance_length = 0; //don't know exactly what this is eNB->preamble_list_br[ind].preamble_rel13.rach_resource_type = 1+ce_level; // CE Level LOG_D(PHY,"Filling NFAPI indication for RACH %d CELevel %d (mask %x) : TA %d, Preamble %d, rnti %x, rach_resource_type %d\n", ind, ce_level, prach_mask, eNB->preamble_list_br[ind].preamble_rel8.timing_advance, eNB->preamble_list_br[ind].preamble_rel8.preamble, eNB->preamble_list_br[ind].preamble_rel8.rnti, eNB->preamble_list_br[ind].preamble_rel13.rach_resource_type); } /* ind++; } } */// ce_level } } else #endif { if (max_preamble_energy[0] > 350) { LOG_D(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n", eNB->Mod_id, eNB->CC_id, frame, subframe, max_preamble[0], max_preamble_energy[0]/10, max_preamble_energy[0]%10, max_preamble_delay[0]); T(T_ENB_PHY_INITIATE_RA_PROCEDURE, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(max_preamble[0]), T_INT(max_preamble_energy[0]), T_INT(max_preamble_delay[0])); prach_vars = &eNB->prach_vars; pthread_mutex_lock(&eNB->UL_INFO_mutex); eNB->UL_INFO.rach_ind.number_of_preambles = 1; eNB->UL_INFO.rach_ind.preamble_list = eNB->preamble_list; eNB->preamble_list[0].preamble_rel8.timing_advance = max_preamble_delay[0]; eNB->preamble_list[0].preamble_rel8.preamble = max_preamble[0]; eNB->preamble_list[0].preamble_rel8.rnti = 1+subframe; // note: fid is implicitly 0 here eNB->preamble_list[0].preamble_rel13.rach_resource_type = 0; eNB->preamble_list[0].instance_length = 0; //don't know exactly what this is LOG_D(PHY,"Filling NFAPI indication for RACH : TA %d, Preamble %d, rnti %x, rach_resource_type %d\n", eNB->preamble_list[0].preamble_rel8.timing_advance, eNB->preamble_list[0].preamble_rel8.preamble, eNB->preamble_list[0].preamble_rel8.rnti, eNB->preamble_list[0].preamble_rel13.rach_resource_type); pthread_mutex_unlock(&eNB->UL_INFO_mutex); } // max_preamble_energy > 350 } // else br_flag /* mac_xface->initiate_ra_proc(eNB->Mod_id, eNB->CC_id, frame, preamble_max, preamble_delay_list[preamble_max]*update_TA/update_TA2, 0,subframe,0);*/ /* } else { MSC_LOG_EVENT(MSC_PHY_ENB, "0 RA Failed add user, too many"); LOG_I(PHY,"[eNB %d][RAPROC] frame %d, subframe %d: Unable to add user, max user count reached\n", eNB->Mod_id,frame, subframe); }*/ VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,0); } void srs_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) { LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; const int subframe = proc->subframe_rx; const int frame = proc->frame_rx; int i; if (is_srs_occasion_common(fp,frame,subframe)) { // Do SRS processing // check if there is SRS and we have to use shortened format // TODO: check for exceptions in transmission of SRS together with ACK/NACK for (i=0;i<NUMBER_OF_UE_MAX;i++) { if (eNB->soundingrs_ul_config_dedicated[i].active==1) { if (lte_srs_channel_estimation(fp, &eNB->common_vars, &eNB->srs_vars[i], &eNB->soundingrs_ul_config_dedicated[i], subframe, 0/*eNB_id*/)) { LOG_E(PHY,"problem processing SRS\n"); } eNB->soundingrs_ul_config_dedicated[i].active=0; } } } } void fill_sr_indication(PHY_VARS_eNB *eNB,uint16_t rnti,int frame,int subframe,uint32_t stat) { pthread_mutex_lock(&eNB->UL_INFO_mutex); nfapi_sr_indication_pdu_t *pdu = &eNB->UL_INFO.sr_ind.sr_pdu_list[eNB->UL_INFO.sr_ind.number_of_srs]; pdu->instance_length = 0; // don't know what to do with this // pdu->rx_ue_information.handle = handle; pdu->rx_ue_information.rnti = rnti; int SNRtimes10 = dB_fixed_times10(stat) - 200;//(10*eNB->measurements.n0_power_dB[0]); if (SNRtimes10 < -640) pdu->ul_cqi_information.ul_cqi=0; else if (SNRtimes10 > 635) pdu->ul_cqi_information.ul_cqi=255; else pdu->ul_cqi_information.ul_cqi=(640+SNRtimes10)/5; pdu->ul_cqi_information.channel = 0; eNB->UL_INFO.sr_ind.number_of_srs++; pthread_mutex_unlock(&eNB->UL_INFO_mutex); } void uci_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) { LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; uint8_t SR_payload = 0,pucch_b0b1[4][2]= {{0,0},{0,0},{0,0},{0,0}},harq_ack[4]={0,0,0,0}; int32_t metric[4]={0,0,0,0},metric_SR=0,max_metric; const int subframe = proc->subframe_rx; const int frame = proc->frame_rx; int i; LTE_eNB_UCI *uci; uint16_t tdd_multiplexing_mask=0; int res; for (i=0;i<NUMBER_OF_UE_MAX;i++) { uci = &eNB->uci_vars[i]; if ((uci->active == 1) && (uci->frame == frame) && (uci->subframe == subframe)) { LOG_D(PHY,"Frame %d, subframe %d: Running uci procedures (type %d) for %d \n",frame,subframe,uci->type,i); uci->active=0; // Null out PUCCH PRBs for noise measurement switch(fp->N_RB_UL) { case 6: eNB->rb_mask_ul[0] |= (0x1 | (1<<5)); //position 5 break; case 15: eNB->rb_mask_ul[0] |= (0x1 | (1<<14)); // position 14 break; case 25: eNB->rb_mask_ul[0] |= (0x1 | (1<<24)); // position 24 break; case 50: eNB->rb_mask_ul[0] |= 0x1; eNB->rb_mask_ul[1] |= (1<<17); // position 49 (49-32) break; case 75: eNB->rb_mask_ul[0] |= 0x1; eNB->rb_mask_ul[2] |= (1<<10); // position 74 (74-64) break; case 100: eNB->rb_mask_ul[0] |= 0x1; eNB->rb_mask_ul[3] |= (1<<3); // position 99 (99-96) break; default: LOG_E(PHY,"Unknown number for N_RB_UL %d\n",fp->N_RB_UL); break; } switch (uci->type) { case SR: case HARQ_SR: metric_SR = rx_pucch(eNB, uci->pucch_fmt, i, uci->n_pucch_1_0_sr[0], 0, // n2_pucch uci->srs_active, // shortened format &SR_payload, frame, subframe, PUCCH1_THRES); LOG_D(PHY,"[eNB %d][SR %x] Frame %d subframe %d Checking SR is %d (SR n1pucch is %d)\n", eNB->Mod_id, uci->rnti, frame, subframe, SR_payload, uci->n_pucch_1_0_sr[0]); if (uci->type == SR) { if (SR_payload == 1) { fill_sr_indication(eNB,uci->rnti,frame,subframe,metric_SR); return; } else { return; } } case HARQ: if (fp->frame_type == FDD) { LOG_D(PHY,"Frame %d Subframe %d Demodulating PUCCH (UCI %d) for ACK/NAK (uci->pucch_fmt %d,uci->type %d.uci->frame %d, uci->subframe %d): n1_pucch0 %d SR_payload %d\n", frame,subframe,i, uci->pucch_fmt,uci->type, uci->frame,uci->subframe,uci->n_pucch_1[0][0], SR_payload); metric[0] = rx_pucch(eNB, uci->pucch_fmt, i, uci->n_pucch_1[0][0], 0, //n2_pucch uci->srs_active, // shortened format pucch_b0b1[0], frame, subframe, PUCCH1a_THRES); /* cancel SR detection if reception on n1_pucch0 is better than on SR PUCCH resource index, otherwise send it up to MAC */ if (uci->type==HARQ_SR && metric[0] > metric_SR) SR_payload = 0; else if (SR_payload == 1) fill_sr_indication(eNB,uci->rnti,frame,subframe,metric_SR); if (uci->type==HARQ_SR && metric[0] <= metric_SR) { /* when transmitting ACK/NACK on SR PUCCH resource index, SR payload is always 1 */ SR_payload = 1; metric[0]=rx_pucch(eNB, uci->pucch_fmt, i, uci->n_pucch_1_0_sr[0], 0, //n2_pucch uci->srs_active, // shortened format pucch_b0b1[0], frame, subframe, PUCCH1a_THRES); } LOG_D(PHY,"[eNB %d][PDSCH %x] Frame %d subframe %d pucch1a (FDD) payload %d (metric %d)\n", eNB->Mod_id, uci->rnti, frame,subframe, pucch_b0b1[0][0],metric[0]); fill_uci_harq_indication(eNB,uci,frame,subframe,pucch_b0b1[0],0,0xffff); } else { // frame_type == TDD // if SR was detected, use the n1_pucch from SR if (SR_payload==1) { #ifdef DEBUG_PHY_PROC LOG_D(PHY,"[eNB %d][PDSCH %x] Frame %d subframe %d Checking ACK/NAK (%d,%d,%d,%d) format %d with SR\n",eNB->Mod_id, eNB->dlsch[UE_id][0]->rnti, frame,subframe, n1_pucch0,n1_pucch1,n1_pucch2,n1_pucch3,format); #endif metric[0] = rx_pucch(eNB, pucch_format1b, i, uci->n_pucch_1_0_sr[0], 0, //n2_pucch uci->srs_active, // shortened format pucch_b0b1[0], frame, subframe, PUCCH1a_THRES); } else { //using assigned pucch resources #ifdef DEBUG_PHY_PROC LOG_D(PHY,"[eNB %d][PDSCH %x] Frame %d subframe %d Checking ACK/NAK M=%d (%d,%d,%d,%d) format %d\n",eNB->Mod_id, eNB->dlsch[UE_id][0]->rnti, frame,subframe, uci->num_pucch_resources, uci->n_pucch_1[res][0], uci->n_pucch_1[res][1], uci->n_pucch_1[res][2], uci->n_pucch_1[res][3], uci->pucch_fmt); #endif for (res=0;res<uci->num_pucch_resources;res++) metric[res] = rx_pucch(eNB, uci->pucch_fmt, i, uci->n_pucch_1[res][0], 0, // n2_pucch uci->srs_active, // shortened format pucch_b0b1[res], frame, subframe, PUCCH1a_THRES); } if (SR_payload == 1) { // this implements Table 7.3.1 from 36.213 if (pucch_b0b1[0][0] == 4) { // there isn't a likely transmission harq_ack[0] = 4; // DTX } else if (pucch_b0b1[1][0] == 1 && pucch_b0b1[1][1] == 1) { // 1/4/7 ACKs harq_ack[0] = 1; } else if (pucch_b0b1[1][0] == 1 && pucch_b0b1[1][1] != 1) { // 2/5/8 ACKs harq_ack[0] = 2; } else if (pucch_b0b1[1][0] != 1 && pucch_b0b1[1][1] == 1) { // 3/6/9 ACKs harq_ack[0] = 3; } else if (pucch_b0b1[1][0] != 1 && pucch_b0b1[1][1] != 1) { // 0 ACKs, or at least one DL assignment missed harq_ack[0] = 0; } fill_uci_harq_indication(eNB,uci,frame,subframe,harq_ack,2,0xffff); // special_bundling mode } else if ((uci->tdd_bundling == 0) && (uci->num_pucch_resources==2)){ // multiplexing + no SR, implement Table 10.1.3-5 (Rel14) for multiplexing with M=2 if (pucch_b0b1[0][0] == 4 || pucch_b0b1[1][0] == 4) { // there isn't a likely transmission harq_ack[0] = 4; // DTX harq_ack[1] = 6; // NACK/DTX } else { if (metric[1]>metric[0]) { if (pucch_b0b1[1][0] == 1 && pucch_b0b1[1][1] != 1){ harq_ack[0] = 1; // ACK harq_ack[1] = 1; // ACK tdd_multiplexing_mask = 0x3; } else if (pucch_b0b1[1][0] != 1 && pucch_b0b1[1][1] == 1){ harq_ack[0] = 6; // NACK/DTX harq_ack[1] = 1; // ACK tdd_multiplexing_mask = 0x2; } else { harq_ack[0] = 4; // DTX harq_ack[1] = 4; // DTX } } else { if (pucch_b0b1[0][0] == 1 && pucch_b0b1[0][1] == 1){ harq_ack[0] = 1; // ACK harq_ack[1] = 6; // NACK/DTX tdd_multiplexing_mask = 0x1; } else if (pucch_b0b1[0][0] != 1 && pucch_b0b1[0][1] != 1){ harq_ack[0] = 2; // NACK harq_ack[1] = 6; // NACK/DTX } else { harq_ack[0] = 4; // DTX harq_ack[1] = 4; // DTX } } } fill_uci_harq_indication(eNB,uci,frame,subframe,harq_ack,1,tdd_multiplexing_mask); // multiplexing mode } //else if ((uci->tdd_bundling == 0) && (res==2)) else if ((uci->tdd_bundling == 0) && (uci->num_pucch_resources==3)){ // multiplexing + no SR, implement Table 10.1.3-6 (Rel14) for multiplexing with M=3 if (harq_ack[0] == 4 || harq_ack[1] == 4 || harq_ack[2] == 4) { // there isn't a likely transmission harq_ack[0] = 4; // DTX harq_ack[1] = 6; // NACK/DTX harq_ack[2] = 6; // NACK/DTX } else { max_metric = max(metric[0],max(metric[1],metric[2])); if (metric[0]==max_metric) { if (pucch_b0b1[0][0] == 1 && pucch_b0b1[0][1] == 1){ harq_ack[0] = 1; // ACK harq_ack[1] = 6; // NACK/DTX harq_ack[2] = 6; // NACK/DTX tdd_multiplexing_mask = 0x1; } else if (pucch_b0b1[0][0] != 1 && pucch_b0b1[0][1] != 1){ harq_ack[0] = 2; // NACK harq_ack[1] = 6; // NACK/DTX harq_ack[2] = 6; // NACK/DTX } else { harq_ack[0] = 4; // DTX harq_ack[1] = 4; // DTX harq_ack[2] = 4; // DTX } } // if (metric[0]==max_metric) { else if (metric[1]==max_metric) { if (pucch_b0b1[1][0] == 1 && pucch_b0b1[1][1] != 1){ harq_ack[0] = 1; // ACK harq_ack[1] = 1; // ACK harq_ack[2] = 6; // NACK/DTX tdd_multiplexing_mask = 0x3; } else if (pucch_b0b1[1][0] != 1 && pucch_b0b1[1][1] == 1 ) { harq_ack[0] = 6; // NACK/DTX harq_ack[1] = 1; // ACK harq_ack[2] = 6; // NACK/DTX tdd_multiplexing_mask = 0x2; } else { harq_ack[0] = 4; // DTX harq_ack[1] = 4; // DTX harq_ack[2] = 4; // DTX } } // if (metric[1]==max_metric) { else { if (pucch_b0b1[2][0] == 1 && pucch_b0b1[2][1] == 1){ harq_ack[0] = 1; // ACK harq_ack[1] = 1; // ACK harq_ack[2] = 1; // ACK tdd_multiplexing_mask = 0x7; } else if (pucch_b0b1[2][0] == 1 && pucch_b0b1[2][1] != 1 ) { harq_ack[0] = 1; // ACK harq_ack[1] = 6; // NACK/DTX harq_ack[2] = 1; // ACK tdd_multiplexing_mask = 0x5; } else if (pucch_b0b1[2][0] != 1 && pucch_b0b1[2][1] == 1 ) { harq_ack[0] = 6; // NACK/DTX harq_ack[1] = 1; // ACK harq_ack[2] = 1; // ACK tdd_multiplexing_mask = 0x6; } else if (pucch_b0b1[2][0] != 1 && pucch_b0b1[2][1] != 1 ) { harq_ack[0] = 6; // NACK/DTX harq_ack[1] = 6; // NACK/DTX harq_ack[2] = 1; // ACK tdd_multiplexing_mask = 0x4; } } } fill_uci_harq_indication(eNB,uci,frame,subframe,harq_ack,1,tdd_multiplexing_mask); // multiplexing mode } //else if ((uci->tdd_bundling == 0) && (res==3)) else if ((uci->tdd_bundling == 0) && (uci->num_pucch_resources==4)){ // multiplexing + no SR, implement Table 10.1.3-7 (Rel14) for multiplexing with M=4 if (pucch_b0b1[0][0] == 4 || pucch_b0b1[1][0] == 4 || pucch_b0b1[2][0] == 4 || pucch_b0b1[3][0] == 4) { // there isn't a likely transmission harq_ack[0] = 4; // DTX harq_ack[1] = 6; // NACK/DTX harq_ack[2] = 6; // NACK/DTX harq_ack[3] = 6; // NACK/DTX } else { max_metric = max(metric[0],max(metric[1],max(metric[2],metric[3]))); if (metric[0]==max_metric) { if (pucch_b0b1[0][0] == 1 && pucch_b0b1[0][1] != 1){ harq_ack[0] = 2; // NACK harq_ack[1] = 4; // DTX harq_ack[2] = 4; // DTX harq_ack[3] = 4; // DTX } else if (pucch_b0b1[0][0] != 1 && pucch_b0b1[0][1] == 1){ harq_ack[0] = 1; // ACK harq_ack[1] = 6; // NACK/DTX harq_ack[2] = 6; // NACK/DTX harq_ack[3] = 1; // ACK tdd_multiplexing_mask = 0x9; } else if (pucch_b0b1[0][0] == 1 && pucch_b0b1[0][1] == 1){ harq_ack[0] = 1; // ACK harq_ack[1] = 6; // NACK/DTX harq_ack[2] = 6; // NACK/DTX harq_ack[3] = 6; // NACK/DTX tdd_multiplexing_mask = 0x1; } else if (pucch_b0b1[0][0] != 1 && pucch_b0b1[0][1] != 1){ harq_ack[0] = 2; // NACK harq_ack[1] = 6; // NACK/DTX harq_ack[2] = 6; // NACK/DTX harq_ack[3] = 6; // NACK/DTX } } else if (metric[1]==max_metric) { if (pucch_b0b1[1][0] == 1 && pucch_b0b1[1][1] == 1){ harq_ack[0] = 1; // ACK harq_ack[1] = 1; // ACK harq_ack[2] = 1; // ACK harq_ack[3] = 1; // ACK tdd_multiplexing_mask = 0xF; } else if (pucch_b0b1[1][0] == 1 && pucch_b0b1[1][1] != 1 ) { harq_ack[0] = 1; // ACK harq_ack[1] = 1; // ACK harq_ack[2] = 6; // NACK/DTX harq_ack[3] = 6; // NACK/DTX tdd_multiplexing_mask = 0x3; } else if (pucch_b0b1[1][0] != 1 && pucch_b0b1[1][1] != 1 ) { harq_ack[0] = 6; // NACK/DTX harq_ack[1] = 1; // ACK harq_ack[2] = 1; // ACK harq_ack[3] = 1; // ACK tdd_multiplexing_mask = 0xE; } else if (pucch_b0b1[1][0] != 1 && pucch_b0b1[1][1] == 1 ) { harq_ack[0] = 6; // NACK/DTX harq_ack[1] = 1; // ACK harq_ack[2] = 6; // NACK/DTX harq_ack[3] = 6; // NACK/DTX tdd_multiplexing_mask = 0x2; } } else if (metric[2]==max_metric) { if (pucch_b0b1[2][0] == 1 && pucch_b0b1[2][1] == 1){ harq_ack[0] = 1; // ACK harq_ack[1] = 1; // ACK harq_ack[2] = 1; // ACK harq_ack[3] = 6; // NACK/DTX tdd_multiplexing_mask = 0x7; } else if (pucch_b0b1[2][0] == 1 && pucch_b0b1[2][1] != 1 ) { harq_ack[0] = 1; // ACK harq_ack[1] = 6; // NACK/DTX harq_ack[2] = 1; // ACK harq_ack[3] = 6; // NACK/DTX tdd_multiplexing_mask = 0x5; } else if (pucch_b0b1[2][0] != 1 && pucch_b0b1[2][1] == 1 ) { harq_ack[0] = 4; // NACK/DTX harq_ack[1] = 1; // ACK harq_ack[2] = 1; // ACK harq_ack[3] = 4; // NACK/DTX tdd_multiplexing_mask = 0x6; } else if (pucch_b0b1[2][0] != 1 && pucch_b0b1[2][1] != 1 ) { harq_ack[0] = 4; // NACK/DTX harq_ack[1] = 4; // NACK/DTX harq_ack[2] = 1; // ACK harq_ack[3] = 4; // NACK/DTX tdd_multiplexing_mask = 0x4; } } else { // max_metric[3]=max_metric if (pucch_b0b1[2][0] == 1 && pucch_b0b1[2][1] == 1){ harq_ack[0] = 1; // ACK harq_ack[1] = 6; // NACK/DTX harq_ack[2] = 1; // ACK harq_ack[3] = 1; // ACK tdd_multiplexing_mask = 0xD; } else if (pucch_b0b1[2][0] == 1 && pucch_b0b1[2][1] != 1 ) { harq_ack[0] = 6; // NACK/DTX harq_ack[1] = 1; // ACK harq_ack[2] = 6; // NACK/DTX harq_ack[3] = 1; // ACK tdd_multiplexing_mask = 0xA; } else if (pucch_b0b1[2][0] != 1 && pucch_b0b1[2][1] == 1 ) { harq_ack[0] = 6; // NACK/DTX harq_ack[1] = 6; // NACK/DTX harq_ack[2] = 1; // ACK harq_ack[3] = 1; // ACK tdd_multiplexing_mask = 0xC; } else if (pucch_b0b1[2][0] != 1 && pucch_b0b1[2][1] != 1 ) { harq_ack[0] = 6; // NACK/DTX harq_ack[1] = 6; // NACK/DTX harq_ack[2] = 6; // NACK/DTX harq_ack[3] = 1; // ACK tdd_multiplexing_mask = 0x8; } } } fill_uci_harq_indication(eNB,uci,frame,subframe,harq_ack,1,tdd_multiplexing_mask); // multiplexing mode } // else if ((uci->tdd_bundling == 0) && (res==4)) else { // bundling harq_ack[0] = pucch_b0b1[0][0]; harq_ack[1] = pucch_b0b1[0][1]; fill_uci_harq_indication(eNB,uci,frame,subframe,harq_ack,0,0xffff); // special_bundling mode } #ifdef DEBUG_PHY_PROC LOG_D(PHY,"[eNB %d][PDSCH %x] Frame %d subframe %d ACK/NAK metric 0 %d, metric 1 %d, (%d,%d)\n",eNB->Mod_id, eNB->dlsch[UE_id][0]->rnti, frame,subframe, metric0,metric1,pucch_b0b1[0],pucch_b0b1[1]); #endif } break; default: AssertFatal(1==0,"Unsupported UCI type %d\n",uci->type); break; } if (SR_payload == 1) { LOG_D(PHY,"[eNB %d][SR %x] Frame %d subframe %d Got SR for PUSCH, transmitting to MAC\n",eNB->Mod_id, uci->rnti,frame,subframe); if (eNB->first_sr[i] == 1) { // this is the first request for uplink after Connection Setup, so clear HARQ process 0 use for Msg4 eNB->first_sr[i] = 0; eNB->dlsch[i][0]->harq_processes[0]->round=0; eNB->dlsch[i][0]->harq_processes[0]->status=SCH_IDLE; LOG_D(PHY,"[eNB %d][SR %x] Frame %d subframe %d First SR\n", eNB->Mod_id, eNB->ulsch[i]->rnti,frame,subframe); } } } } } void pusch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) { uint32_t ret=0,i; uint32_t harq_pid; uint8_t nPRS; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; LTE_eNB_ULSCH_t *ulsch; LTE_UL_eNB_HARQ_t *ulsch_harq; const int subframe = proc->subframe_rx; const int frame = proc->frame_rx; if (fp->frame_type == FDD) harq_pid = ((10*frame) + subframe)&7; else harq_pid = subframe%10; for (i=0; i<NUMBER_OF_UE_MAX; i++) { ulsch = eNB->ulsch[i]; ulsch_harq = ulsch->harq_processes[harq_pid]; if (ulsch->rnti>0) LOG_D(PHY,"Frame %d, subframe %d: PUSCH procedures, harq_pid %d, UE %d/%x\n", frame,subframe,harq_pid,i,ulsch->rnti); if ((ulsch) && (ulsch->rnti>0) && (ulsch_harq->status == ACTIVE) && (ulsch_harq->frame == frame) && (ulsch_harq->subframe == subframe) && (ulsch_harq->handled == 0)) { // UE has ULSCH scheduling for (int rb=0; rb<=ulsch_harq->nb_rb; rb++) { int rb2 = rb+ulsch_harq->first_rb; eNB->rb_mask_ul[rb2>>5] |= (1<<(rb2&31)); } LOG_D(PHY,"[eNB %d] frame %d, subframe %d: Scheduling ULSCH Reception for UE %d \n", eNB->Mod_id, frame, subframe, i); nPRS = fp->pusch_config_common.ul_ReferenceSignalsPUSCH.nPRS[subframe<<1]; ulsch->cyclicShift = (ulsch_harq->n_DMRS2 + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift + nPRS)%12; LOG_D(PHY, "[eNB %d][PUSCH %d] Frame %d Subframe %d Demodulating PUSCH: dci_alloc %d, rar_alloc %d, round %d, first_rb %d, nb_rb %d, Qm %d, TBS %d, rv %d, cyclic_shift %d (n_DMRS2 %d, cyclicShift_common %d, nprs %d), O_ACK %d, beta_cqi %d \n", eNB->Mod_id,harq_pid,frame,subframe, ulsch_harq->dci_alloc, ulsch_harq->rar_alloc, ulsch_harq->round, ulsch_harq->first_rb, ulsch_harq->nb_rb, ulsch_harq->Qm, ulsch_harq->TBS, ulsch_harq->rvidx, ulsch->cyclicShift, ulsch_harq->n_DMRS2, fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift, nPRS, ulsch_harq->O_ACK, ulsch->beta_offset_cqi_times8); start_meas(&eNB->ulsch_demodulation_stats); rx_ulsch(eNB,proc, i); stop_meas(&eNB->ulsch_demodulation_stats); start_meas(&eNB->ulsch_decoding_stats); ret = ulsch_decoding(eNB,proc, i, 0, // control_only_flag ulsch_harq->V_UL_DAI, ulsch_harq->nb_rb>20 ? 1 : 0); stop_meas(&eNB->ulsch_decoding_stats); LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d RNTI %x RX power (%d,%d) N0 (%d,%d) dB ACK (%d,%d), decoding iter %d\n", eNB->Mod_id,harq_pid, frame,subframe, ulsch->rnti, dB_fixed(eNB->pusch_vars[i]->ulsch_power[0]), dB_fixed(eNB->pusch_vars[i]->ulsch_power[1]), 20,//eNB->measurements.n0_power_dB[0], 20,//eNB->measurements.n0_power_dB[1], ulsch_harq->o_ACK[0], ulsch_harq->o_ACK[1], ret); //compute the expected ULSCH RX power (for the stats) ulsch_harq->delta_TF = get_hundred_times_delta_IF_eNB(eNB,i,harq_pid, 0); // 0 means bw_factor is not considered if (ulsch_harq->cqi_crc_status == 1) { #ifdef DEBUG_PHY_PROC //if (((frame%10) == 0) || (frame < 50)) print_CQI(ulsch_harq->o,ulsch_harq->uci_format,0,fp->N_RB_DL); #endif fill_ulsch_cqi_indication(eNB,frame,subframe, ulsch_harq, ulsch->rnti); } if (ret == (1+MAX_TURBO_ITERATIONS)) { T(T_ENB_PHY_ULSCH_UE_NACK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(ulsch->rnti), T_INT(harq_pid)); fill_crc_indication(eNB,i,frame,subframe,1); // indicate NAK to MAC fill_rx_indication(eNB,i,frame,subframe); // indicate SDU to MAC LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d UE %d Error receiving ULSCH, round %d/%d (ACK %d,%d)\n", eNB->Mod_id,harq_pid, frame,subframe, i, ulsch_harq->round-1, ulsch->Mlimit, ulsch_harq->o_ACK[0], ulsch_harq->o_ACK[1]); /*if (dB_fixed_times10(eNB->pusch_vars[i]->ulsch_power[0]) > 300) { dump_ulsch(eNB,frame,subframe,i); exit(-1); } */ #if defined(MESSAGE_CHART_GENERATOR_PHY) MSC_LOG_RX_DISCARDED_MESSAGE( MSC_PHY_ENB,MSC_PHY_UE, NULL,0, "%05u:%02u ULSCH received rnti %x harq id %u round %d", frame,subframe, ulsch->rnti,harq_pid, ulsch_harq->round-1 ); #endif } // ulsch in error else { fill_crc_indication(eNB,i,frame,subframe,0); // indicate ACK to MAC fill_rx_indication(eNB,i,frame,subframe); // indicate SDU to MAC T(T_ENB_PHY_ULSCH_UE_ACK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(ulsch->rnti), T_INT(harq_pid)); ulsch_harq->status = SCH_IDLE; #if defined(MESSAGE_CHART_GENERATOR_PHY) MSC_LOG_RX_MESSAGE( MSC_PHY_ENB,MSC_PHY_UE, NULL,0, "%05u:%02u ULSCH received rnti %x harq id %u", frame,subframe, ulsch->rnti,harq_pid ); #endif #ifdef DEBUG_PHY_PROC #ifdef DEBUG_ULSCH LOG_D(PHY,"[eNB] Frame %d, Subframe %d : ULSCH SDU (RX harq_pid %d) %d bytes:",frame,subframe, harq_pid,ulsch_harq->TBS>>3); for (j=0; j<ulsch_harq->TBS>>3; j++) LOG_T(PHY,"%x.",ulsch->harq_processes[harq_pid]->b[j]); LOG_T(PHY,"\n"); #endif #endif } // ulsch not in error if (ulsch_harq->O_ACK>0) fill_ulsch_harq_indication(eNB,ulsch_harq,ulsch->rnti,frame,subframe,ulsch->bundling); LOG_D(PHY,"[eNB %d] Frame %d subframe %d: received ULSCH harq_pid %d for UE %d, ret = %d, CQI CRC Status %d, ACK %d,%d, ulsch_errors %d/%d\n", eNB->Mod_id,frame,subframe, harq_pid, i, ret, ulsch_harq->cqi_crc_status, ulsch_harq->o_ACK[0], ulsch_harq->o_ACK[1], eNB->UE_stats[i].ulsch_errors[harq_pid], eNB->UE_stats[i].ulsch_decoding_attempts[harq_pid][0]); ulsch_harq->handled = 1; } // if ((ulsch) && // (ulsch->rnti>0) && // (ulsch_harq->status == ACTIVE)) else if ((ulsch) && (ulsch->rnti>0) && (ulsch_harq->status == ACTIVE) && (ulsch_harq->frame == frame) && (ulsch_harq->subframe == subframe) && (ulsch_harq->handled == 1)) { // this harq process is stale, kill it, this 1024 frames later (10s), consider reducing that ulsch_harq->status = SCH_IDLE; ulsch->harq_mask = 0; LOG_W(PHY,"Removing stale ULSCH config for UE %x\n",ulsch->rnti); } } // for (i=0; i<NUMBER_OF_UE_MAX; i++) { } extern int oai_exit; extern void *td_thread(void*); void init_td_thread(PHY_VARS_eNB *eNB,pthread_attr_t *attr_td) { eNB_proc_t *proc = &eNB->proc; proc->tdp.eNB = eNB; proc->instance_cnt_td = -1; pthread_mutex_init( &proc->mutex_td, NULL); pthread_cond_init( &proc->cond_td, NULL); pthread_create(&proc->pthread_td, attr_td, td_thread, (void*)&proc->tdp); } extern void *te_thread(void*); void init_te_thread(PHY_VARS_eNB *eNB,pthread_attr_t *attr_te) { eNB_proc_t *proc = &eNB->proc; proc->tep.eNB = eNB; proc->instance_cnt_te = -1; pthread_mutex_init( &proc->mutex_te, NULL); pthread_cond_init( &proc->cond_te, NULL); printf("Creating te_thread\n"); pthread_create(&proc->pthread_te, attr_te, te_thread, (void*)&proc->tep); } void fill_rx_indication(PHY_VARS_eNB *eNB,int UE_id,int frame,int subframe) { nfapi_rx_indication_pdu_t *pdu; int timing_advance_update; int sync_pos; uint32_t harq_pid = subframe2harq_pid(&eNB->frame_parms, frame,subframe); pthread_mutex_lock(&eNB->UL_INFO_mutex); pdu = &eNB->UL_INFO.rx_ind.rx_pdu_list[eNB->UL_INFO.rx_ind.number_of_pdus]; // pdu->rx_ue_information.handle = eNB->ulsch[UE_id]->handle; pdu->rx_ue_information.rnti = eNB->ulsch[UE_id]->rnti; pdu->rx_indication_rel8.length = eNB->ulsch[UE_id]->harq_processes[harq_pid]->TBS>>3; pdu->rx_indication_rel8.offset = 0; // filled in at the end of the UL_INFO formation pdu->data = eNB->ulsch[UE_id]->harq_processes[harq_pid]->b; // estimate timing advance for MAC sync_pos = lte_est_timing_advance_pusch(eNB,UE_id); timing_advance_update = sync_pos - eNB->frame_parms.nb_prefix_samples/4; //to check // if (timing_advance_update > 10) { dump_ulsch(eNB,frame,subframe,UE_id); exit(-1);} // if (timing_advance_update < -10) { dump_ulsch(eNB,frame,subframe,UE_id); exit(-1);} switch (eNB->frame_parms.N_RB_DL) { case 6: /* nothing to do */ break; case 15: timing_advance_update /= 2; break; case 25: timing_advance_update /= 4; break; case 50: timing_advance_update /= 8; break; case 75: timing_advance_update /= 12; break; case 100: timing_advance_update /= 16; break; default: abort(); } // put timing advance command in 0..63 range timing_advance_update += 31; if (timing_advance_update < 0) timing_advance_update = 0; if (timing_advance_update > 63) timing_advance_update = 63; pdu->rx_indication_rel8.timing_advance = timing_advance_update; // estimate UL_CQI for MAC (from antenna port 0 only) int SNRtimes10 = dB_fixed_times10(eNB->pusch_vars[UE_id]->ulsch_power[0]) - 200;//(10*eNB->measurements.n0_power_dB[0]); if (SNRtimes10 < -640) pdu->rx_indication_rel8.ul_cqi=0; else if (SNRtimes10 > 635) pdu->rx_indication_rel8.ul_cqi=255; else pdu->rx_indication_rel8.ul_cqi=(640+SNRtimes10)/5; LOG_D(PHY,"[PUSCH %d] Filling RX_indication with SNR %d (%d), timing_advance %d (update %d)\n", harq_pid,SNRtimes10,pdu->rx_indication_rel8.ul_cqi,pdu->rx_indication_rel8.timing_advance, timing_advance_update); eNB->UL_INFO.rx_ind.number_of_pdus++; pthread_mutex_unlock(&eNB->UL_INFO_mutex); } void release_harq(PHY_VARS_eNB *eNB,int UE_id,int tb,uint16_t frame,uint8_t subframe,uint16_t mask) { LTE_eNB_DLSCH_t *dlsch0=NULL,*dlsch1=NULL; LTE_DL_eNB_HARQ_t *dlsch0_harq=NULL,*dlsch1_harq=NULL; int harq_pid; int subframe_tx; int M,m; AssertFatal(UE_id!=-1,"no existing dlsch context\n"); AssertFatal(UE_id<NUMBER_OF_UE_MAX,"returned UE_id %d >= %d(NUMBER_OF_UE_MAX)\n",UE_id,NUMBER_OF_UE_MAX); dlsch0 = eNB->dlsch[UE_id][0]; dlsch1 = eNB->dlsch[UE_id][1]; if (eNB->frame_parms.frame_type == FDD) { subframe_tx = (subframe+6)%10; harq_pid = dlsch0->harq_ids[subframe_tx]; AssertFatal((harq_pid>=0) && (harq_pid<10),"harq_pid %d not in 0...9\n",harq_pid); dlsch0_harq = dlsch0->harq_processes[harq_pid]; dlsch1_harq = dlsch1->harq_processes[harq_pid]; AssertFatal(dlsch0_harq!=NULL,"dlsch0_harq is null\n"); dlsch0_harq->status = SCH_IDLE; /*if ((dlsch1_harq == NULL)|| ((dlsch1_harq!=NULL)&& (dlsch1_harq->status == SCH_IDLE)))*/ dlsch0->harq_mask &= ~(1<<harq_pid); LOG_D(PHY,"Frame %d, subframe %d: Releasing harq %d for UE %x\n",frame,subframe,harq_pid,dlsch0->rnti); } else { // release all processes in the bundle that was acked, based on mask // This is at most 4 for multiplexing and 9 for bundling/special bundling M=ul_ACK_subframe2_M(&eNB->frame_parms, subframe); for (m=0; m<M; m++) { subframe_tx = ul_ACK_subframe2_dl_subframe(&eNB->frame_parms, subframe, m); if (((1<<m)&mask) > 0) { harq_pid = dlsch0->harq_ids[subframe_tx]; if ((harq_pid>=0) && (harq_pid<10)) { dlsch0_harq = dlsch0->harq_processes[harq_pid]; dlsch1_harq = dlsch1->harq_processes[harq_pid]; AssertFatal(dlsch0_harq!=NULL,"dlsch0_harq is null\n"); dlsch0_harq->status = SCH_IDLE; if ((dlsch1_harq == NULL)|| ((dlsch1_harq!=NULL)&& (dlsch1_harq->status == SCH_IDLE))) dlsch0->harq_mask &= ~(1<<harq_pid); } } } } } int getM(PHY_VARS_eNB *eNB,int frame,int subframe) { int M,Mtx=0; LTE_eNB_DLSCH_t *dlsch0=NULL,*dlsch1=NULL; LTE_DL_eNB_HARQ_t *dlsch0_harq=NULL,*dlsch1_harq=NULL; int harq_pid; int subframe_tx; int m; M=ul_ACK_subframe2_M(&eNB->frame_parms, subframe); for (m=0; m<M; m++) { subframe_tx = ul_ACK_subframe2_dl_subframe(&eNB->frame_parms, subframe, m); harq_pid = dlsch0->harq_ids[subframe_tx]; if (harq_pid>=0 && harq_pid<10) { dlsch0_harq = dlsch0->harq_processes[harq_pid]; dlsch1_harq = dlsch1->harq_processes[harq_pid]; AssertFatal(dlsch0_harq!=NULL,"dlsch0_harq is null\n"); if (dlsch0_harq->status == ACTIVE|| (dlsch1_harq!=NULL && dlsch1_harq->status == ACTIVE)) Mtx ++; } } return(Mtx); } void fill_ulsch_cqi_indication(PHY_VARS_eNB *eNB,uint16_t frame,uint8_t subframe,LTE_UL_eNB_HARQ_t *ulsch_harq,uint16_t rnti) { pthread_mutex_lock(&eNB->UL_INFO_mutex); nfapi_cqi_indication_pdu_t *pdu = &eNB->UL_INFO.cqi_ind.cqi_pdu_list[eNB->UL_INFO.cqi_ind.number_of_cqis]; nfapi_cqi_indication_raw_pdu_t *raw_pdu = &eNB->UL_INFO.cqi_ind.cqi_raw_pdu_list[eNB->UL_INFO.cqi_ind.number_of_cqis]; pdu->rx_ue_information.rnti = rnti; if (ulsch_harq->cqi_crc_status != 1) pdu->cqi_indication_rel9.data_offset = 0; else pdu->cqi_indication_rel9.data_offset = 1; // fill in after all cqi_indications have been generated when non-zero // by default set O to rank 1 value pdu->cqi_indication_rel9.length = (ulsch_harq->Or1>>3) + ((ulsch_harq->Or1&7) > 0 ? 1 : 0); pdu->cqi_indication_rel9.ri[0] = 0; // if we have RI bits, set them and if rank2 overwrite O if (ulsch_harq->O_RI>0) { pdu->cqi_indication_rel9.ri[0] = ulsch_harq->o_RI[0]; if (ulsch_harq->o_RI[0] == 2) pdu->cqi_indication_rel9.length = (ulsch_harq->Or2>>3) + ((ulsch_harq->Or2&7) > 0 ? 1 : 0); pdu->cqi_indication_rel9.timing_advance = 0; } pdu->cqi_indication_rel9.number_of_cc_reported = 1; pdu->ul_cqi_information.channel = 1; // PUSCH memcpy((void*)raw_pdu->pdu,ulsch_harq->o,pdu->cqi_indication_rel9.length); eNB->UL_INFO.cqi_ind.number_of_cqis++; pthread_mutex_unlock(&eNB->UL_INFO_mutex); } void fill_ulsch_harq_indication(PHY_VARS_eNB *eNB,LTE_UL_eNB_HARQ_t *ulsch_harq,uint16_t rnti, int frame,int subframe,int bundling) { int UE_id = find_dlsch(rnti,eNB,SEARCH_EXIST); AssertFatal(UE_id>=0,"UE_id doesn't exist\n"); pthread_mutex_lock(&eNB->UL_INFO_mutex); nfapi_harq_indication_pdu_t *pdu = &eNB->UL_INFO.harq_ind.harq_pdu_list[eNB->UL_INFO.harq_ind.number_of_harqs]; int M; int i; pdu->instance_length = 0; // don't know what to do with this // pdu->rx_ue_information.handle = handle; pdu->rx_ue_information.rnti = rnti; if (eNB->frame_parms.frame_type == FDD) { pdu->harq_indication_fdd_rel13.mode = 0; pdu->harq_indication_fdd_rel13.number_of_ack_nack = ulsch_harq->O_ACK; for (i=0;i<ulsch_harq->O_ACK;i++) { AssertFatal(ulsch_harq->o_ACK[i] == 0 || ulsch_harq->o_ACK[i] == 1, "harq_ack[%d] is %d, should be 1,2 or 4\n",i,ulsch_harq->o_ACK[i]); pdu->harq_indication_fdd_rel13.harq_tb_n[i] = 2-ulsch_harq->o_ACK[i]; // release DLSCH if needed if (ulsch_harq->o_ACK[i] == 1) release_harq(eNB,UE_id,i,frame,subframe,0xffff); #if T_TRACER /* TODO: get correct harq pid */ if (ulsch_harq->o_ACK[i] != 1) T(T_ENB_PHY_DLSCH_UE_NACK, T_INT(0), T_INT(frame), T_INT(subframe), T_INT(rnti), T_INT(eNB->dlsch[UE_id][0]->harq_ids[(subframe+6)%10])); else T(T_ENB_PHY_DLSCH_UE_ACK, T_INT(0), T_INT(frame), T_INT(subframe), T_INT(rnti), T_INT(eNB->dlsch[UE_id][0]->harq_ids[(subframe+6)%10])); #endif } } else { // TDD M=ul_ACK_subframe2_M(&eNB->frame_parms, subframe); pdu->harq_indication_fdd_rel13.mode = 1-bundling; pdu->harq_indication_fdd_rel13.number_of_ack_nack = ulsch_harq->O_ACK; for (i=0;i<ulsch_harq->O_ACK;i++) { AssertFatal(ulsch_harq->o_ACK[i] == 0 || ulsch_harq->o_ACK[i] == 1, "harq_ack[%d] is %d, should be 1,2 or 4\n",i,ulsch_harq->o_ACK[i]); pdu->harq_indication_tdd_rel13.harq_data[0].multiplex.value_0 = 2-ulsch_harq->o_ACK[i]; // release DLSCH if needed if (ulsch_harq->o_ACK[i] == 1) release_harq(eNB,UE_id,i,frame,subframe,0xffff); if (M==1 && ulsch_harq->O_ACK==1 && ulsch_harq->o_ACK[i] == 1) release_harq(eNB,UE_id,0,frame,subframe,0xffff); else if (M==1 && ulsch_harq->O_ACK==2 && ulsch_harq->o_ACK[i] == 1) release_harq(eNB,UE_id,i,frame,subframe,0xffff); else if (M>1 && ulsch_harq->o_ACK[i] == 1) { // spatial bundling release_harq(eNB,UE_id,0,frame,subframe,1<<i); release_harq(eNB,UE_id,1,frame,subframe,1<<i); } } } eNB->UL_INFO.harq_ind.number_of_harqs++; pthread_mutex_unlock(&eNB->UL_INFO_mutex); } void fill_uci_harq_indication(PHY_VARS_eNB *eNB, LTE_eNB_UCI *uci, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask) { int UE_id=find_dlsch(uci->rnti,eNB,SEARCH_EXIST); pthread_mutex_lock(&eNB->UL_INFO_mutex); nfapi_harq_indication_pdu_t *pdu = &eNB->UL_INFO.harq_ind.harq_pdu_list[eNB->UL_INFO.harq_ind.number_of_harqs]; pdu->instance_length = 0; // don't know what to do with this // pdu->rx_ue_information.handle = handle; pdu->rx_ue_information.rnti = uci->rnti; // estimate UL_CQI for MAC (from antenna port 0 only) int SNRtimes10 = dB_fixed_times10(uci->stat) - 200;//(10*eNB->measurements.n0_power_dB[0]); if (SNRtimes10 < -640) pdu->ul_cqi_information.ul_cqi=0; else if (SNRtimes10 > 635) pdu->ul_cqi_information.ul_cqi=255; else pdu->ul_cqi_information.ul_cqi=(640+SNRtimes10)/5; pdu->ul_cqi_information.channel = 0; if (eNB->frame_parms.frame_type == FDD) { if (uci->pucch_fmt == pucch_format1a) { pdu->harq_indication_fdd_rel13.mode = 0; pdu->harq_indication_fdd_rel13.number_of_ack_nack = 1; AssertFatal(harq_ack[0] == 1 || harq_ack[0] == 2 || harq_ack[0] == 4, "harq_ack[0] is %d, should be 1,2 or 4\n",harq_ack[0]); pdu->harq_indication_fdd_rel13.harq_tb_n[0] = harq_ack[0]; // release DLSCH if needed if (harq_ack[0] == 1) release_harq(eNB,UE_id,0,frame,subframe,0xffff); #if T_TRACER if (harq_ack[0] != 1) T(T_ENB_PHY_DLSCH_UE_NACK, T_INT(0), T_INT(frame), T_INT(subframe), T_INT(uci->rnti), T_INT(eNB->dlsch[UE_id][0]->harq_ids[(subframe+6)%10])); else T(T_ENB_PHY_DLSCH_UE_ACK, T_INT(0), T_INT(frame), T_INT(subframe), T_INT(uci->rnti), T_INT(eNB->dlsch[UE_id][0]->harq_ids[(subframe+6)%10])); #endif } else if (uci->pucch_fmt == pucch_format1b) { pdu->harq_indication_fdd_rel13.mode = 0; pdu->harq_indication_fdd_rel13.number_of_ack_nack = 2; AssertFatal(harq_ack[0] == 1 || harq_ack[0] == 2 || harq_ack[1] == 4, "harq_ack[0] is %d, should be 0,1 or 4\n",harq_ack[0]); AssertFatal(harq_ack[1] == 1 || harq_ack[1] == 2 || harq_ack[1] == 4, "harq_ack[1] is %d, should be 0,1 or 4\n",harq_ack[1]); pdu->harq_indication_fdd_rel13.harq_tb_n[0] = harq_ack[0]; pdu->harq_indication_fdd_rel13.harq_tb_n[1] = harq_ack[1]; // release DLSCH if needed if (harq_ack[0] == 1) release_harq(eNB,UE_id,0,frame,subframe,0xffff); if (harq_ack[1] == 1) release_harq(eNB,UE_id,1,frame,subframe,0xffff); } else AssertFatal(1==0,"only format 1a/b for now, received %d\n",uci->pucch_fmt); } else { // TDD AssertFatal(tdd_mapping_mode==0 || tdd_mapping_mode==1 || tdd_mapping_mode==2, "Illegal tdd_mapping_mode %d\n",tdd_mapping_mode); pdu->harq_indication_tdd_rel13.mode = tdd_mapping_mode; switch (tdd_mapping_mode) { case 0: // bundling if (uci->pucch_fmt == pucch_format1a) { pdu->harq_indication_tdd_rel13.number_of_ack_nack = 1; AssertFatal(harq_ack[0] == 1 || harq_ack[0] == 2 || harq_ack[0] == 4, "harq_ack[0] is %d, should be 1,2 or 4\n",harq_ack[0]); pdu->harq_indication_tdd_rel13.harq_data[0].bundling.value_0 = harq_ack[0]; // release all bundled DLSCH if needed if (harq_ack[0] == 1) release_harq(eNB,UE_id,0,frame,subframe,0xffff); } else if (uci->pucch_fmt == pucch_format1b) { pdu->harq_indication_tdd_rel13.number_of_ack_nack = 2; AssertFatal(harq_ack[0] == 1 || harq_ack[0] == 2 || harq_ack[1] == 4, "harq_ack[0] is %d, should be 0,1 or 4\n",harq_ack[0]); AssertFatal(harq_ack[1] == 1 || harq_ack[1] == 2 || harq_ack[1] == 4, "harq_ack[1] is %d, should be 0,1 or 4\n",harq_ack[1]); pdu->harq_indication_tdd_rel13.harq_data[0].bundling.value_0 = harq_ack[0]; pdu->harq_indication_tdd_rel13.harq_data[1].bundling.value_0 = harq_ack[1]; // release all DLSCH if needed if (harq_ack[0] == 1) release_harq(eNB,UE_id,0,frame,subframe,0xffff); if (harq_ack[1] == 1) release_harq(eNB,UE_id,1,frame,subframe,0xffff); } break; case 1: // multiplexing AssertFatal(uci->pucch_fmt == pucch_format1b,"uci->pucch_format %d is not format1b\n",uci->pucch_fmt); if (uci->num_pucch_resources == 1 && uci->pucch_fmt == pucch_format1a) { pdu->harq_indication_tdd_rel13.number_of_ack_nack = 1; AssertFatal(harq_ack[0] == 1 || harq_ack[0] == 2 || harq_ack[0] == 4, "harq_ack[0] is %d, should be 1,2 or 4\n",harq_ack[0]); pdu->harq_indication_tdd_rel13.harq_data[0].multiplex.value_0 = harq_ack[0]; // release all DLSCH if needed if (harq_ack[0] == 1) release_harq(eNB,UE_id,0,frame,subframe,0xffff); } else if (uci->num_pucch_resources == 1 && uci->pucch_fmt == pucch_format1b) { pdu->harq_indication_tdd_rel13.number_of_ack_nack = 2; AssertFatal(harq_ack[0] == 1 || harq_ack[0] == 2 || harq_ack[1] == 4, "harq_ack[0] is %d, should be 0,1 or 4\n",harq_ack[0]); AssertFatal(harq_ack[1] == 1 || harq_ack[1] == 2 || harq_ack[1] == 4, "harq_ack[1] is %d, should be 0,1 or 4\n",harq_ack[1]); pdu->harq_indication_tdd_rel13.harq_data[0].multiplex.value_0 = harq_ack[0]; pdu->harq_indication_tdd_rel13.harq_data[1].multiplex.value_0 = harq_ack[1]; // release all DLSCH if needed if (harq_ack[0] == 1) release_harq(eNB,UE_id,0,frame,subframe,0xffff); if (harq_ack[1] == 1) release_harq(eNB,UE_id,1,frame,subframe,0xffff); } else { // num_pucch_resources (M) > 1 pdu->harq_indication_tdd_rel13.number_of_ack_nack = uci->num_pucch_resources; pdu->harq_indication_tdd_rel13.harq_data[0].multiplex.value_0 = harq_ack[0]; pdu->harq_indication_tdd_rel13.harq_data[1].multiplex.value_0 = harq_ack[1]; if (uci->num_pucch_resources == 3) pdu->harq_indication_tdd_rel13.harq_data[2].multiplex.value_0 = harq_ack[2]; if (uci->num_pucch_resources == 4) pdu->harq_indication_tdd_rel13.harq_data[3].multiplex.value_0 = harq_ack[3]; // spatial-bundling in this case so release both HARQ if necessary release_harq(eNB,UE_id,0,frame,subframe,tdd_multiplexing_mask); release_harq(eNB,UE_id,1,frame,subframe,tdd_multiplexing_mask); } break; case 2: // special bundling (SR collision) pdu->harq_indication_tdd_rel13.number_of_ack_nack = 1; int tdd_config5_sf2scheds=0; if (eNB->frame_parms.tdd_config==5) tdd_config5_sf2scheds = getM(eNB,frame,subframe); switch (harq_ack[0]) { case 0: break; case 1: // check if M=1,4,7 if (uci->num_pucch_resources == 1 || uci->num_pucch_resources == 4 || tdd_config5_sf2scheds == 1 || tdd_config5_sf2scheds == 4 || tdd_config5_sf2scheds == 7) { release_harq(eNB,UE_id,0,frame,subframe,0xffff); release_harq(eNB,UE_id,1,frame,subframe,0xffff); } break; case 2: // check if M=2,5,8 if (uci->num_pucch_resources == 2 || tdd_config5_sf2scheds == 2 || tdd_config5_sf2scheds == 5 || tdd_config5_sf2scheds == 8) { release_harq(eNB,UE_id,0,frame,subframe,0xffff); release_harq(eNB,UE_id,1,frame,subframe,0xffff); } break; case 3: // check if M=3,6,9 if (uci->num_pucch_resources == 3 || tdd_config5_sf2scheds == 3 || tdd_config5_sf2scheds == 6 || tdd_config5_sf2scheds == 9) { release_harq(eNB,UE_id,0,frame,subframe,0xffff); release_harq(eNB,UE_id,1,frame,subframe,0xffff); } break; } break; } } //TDD eNB->UL_INFO.harq_ind.number_of_harqs++; pthread_mutex_unlock(&eNB->UL_INFO_mutex); } void fill_crc_indication(PHY_VARS_eNB *eNB,int UE_id,int frame,int subframe,uint8_t crc_flag) { pthread_mutex_lock(&eNB->UL_INFO_mutex); nfapi_crc_indication_pdu_t *pdu = &eNB->UL_INFO.crc_ind.crc_pdu_list[eNB->UL_INFO.crc_ind.number_of_crcs]; pdu->instance_length = 0; // don't know what to do with this // pdu->rx_ue_information.handle = handle; pdu->rx_ue_information.rnti = eNB->ulsch[UE_id]->rnti; pdu->crc_indication_rel8.crc_flag = crc_flag; eNB->UL_INFO.crc_ind.number_of_crcs++; pthread_mutex_unlock(&eNB->UL_INFO_mutex); } void phy_procedures_eNB_uespec_RX(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,const relaying_type_t r_type) { //RX processing for ue-specific resources (i LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; const int subframe = proc->subframe_rx; const int frame = proc->frame_rx; if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)!=SF_UL)) return; T(T_ENB_PHY_UL_TICK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe)); /* TODO: use correct rxdata */ T(T_ENB_PHY_INPUT_SIGNAL, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(0), T_BUFFER(&eNB->RU_list[0]->common.rxdata[0][subframe*eNB->frame_parms.samples_per_tti], eNB->frame_parms.samples_per_tti * 4)); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_UESPEC, 1 ); LOG_D(PHY,"[eNB %d] Frame %d: Doing phy_procedures_eNB_uespec_RX(%d)\n",eNB->Mod_id,frame, subframe); eNB->rb_mask_ul[0]=0; eNB->rb_mask_ul[1]=0; eNB->rb_mask_ul[2]=0; eNB->rb_mask_ul[3]=0; // Fix me here, these should be locked eNB->UL_INFO.rx_ind.number_of_pdus = 0; eNB->UL_INFO.crc_ind.number_of_crcs = 0; // Call SRS first since all others depend on presence of SRS or lack thereof srs_procedures(eNB,proc); lte_eNB_I0_measurements(eNB, subframe, 0, eNB->first_run_I0_measurements); eNB->first_run_I0_measurements = 0; uci_procedures(eNB,proc); pusch_procedures(eNB,proc); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_UESPEC, 0 ); stop_meas(&eNB->phy_proc_rx); }