/******************************************************************************* OpenAirInterface Copyright(c) 1999 - 2014 Eurecom OpenAirInterface is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenAirInterface is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenAirInterface.The full GNU General Public License is included in this distribution in the file called "COPYING". If not, see <http://www.gnu.org/licenses/>. Contact Information OpenAirInterface Admin: openair_admin@eurecom.fr OpenAirInterface Tech : openair_tech@eurecom.fr OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE *******************************************************************************/ /*! \file phy_procedures_lte_eNB.c * \brief Implementation of eNB procedures from 36.213 LTE specifications * \author R. Knopp, F. Kaltenberger, N. Nikaein * \date 2011 * \version 0.1 * \company Eurecom * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr,navid.nikaein@eurecom.fr * \note * \warning */ #include "PHY/defs.h" #include "PHY/extern.h" #include "SCHED/defs.h" #include "SCHED/extern.h" #include "PHY/LTE_TRANSPORT/if4_tools.h" #ifdef EMOS #include "SCHED/phy_procedures_emos.h" #endif //#define DEBUG_PHY_PROC (Already defined in cmake) //#define DEBUG_ULSCH #include "LAYER2/MAC/extern.h" #include "LAYER2/MAC/defs.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 //#define DIAG_PHY #define NS_PER_SLOT 500000 #define PUCCH 1 void exit_fun(const char* s); extern int exit_openair; // Fix per CC openair rf/if device update // extern openair0_device openair0; unsigned char dlsch_input_buffer[2700] __attribute__ ((aligned(32))); int eNB_sync_buffer0[640*6] __attribute__ ((aligned(32))); int eNB_sync_buffer1[640*6] __attribute__ ((aligned(32))); int *eNB_sync_buffer[2] = {eNB_sync_buffer0, eNB_sync_buffer1}; extern uint16_t hundred_times_log10_NPRB[100]; unsigned int max_peak_val; int max_sync_pos; //DCI_ALLOC_t dci_alloc[8]; #ifdef EMOS fifo_dump_emos_eNB emos_dump_eNB; #endif #if defined(SMBV) extern const char smbv_fname[]; extern unsigned short config_frames[4]; extern uint8_t smbv_frame_cnt; #endif #ifdef DIAG_PHY extern int rx_sig_fifo; #endif uint8_t is_SR_subframe(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,uint8_t UE_id) { const int subframe = proc->subframe_rx; const int frame = proc->frame_rx; LOG_D(PHY,"[eNB %d][SR %x] Frame %d subframe %d Checking for SR TXOp(sr_ConfigIndex %d)\n", eNB->Mod_id,eNB->ulsch[UE_id]->rnti,frame,subframe, eNB->scheduling_request_config[UE_id].sr_ConfigIndex); if (eNB->scheduling_request_config[UE_id].sr_ConfigIndex <= 4) { // 5 ms SR period if ((subframe%5) == eNB->scheduling_request_config[UE_id].sr_ConfigIndex) return(1); } else if (eNB->scheduling_request_config[UE_id].sr_ConfigIndex <= 14) { // 10 ms SR period if (subframe==(eNB->scheduling_request_config[UE_id].sr_ConfigIndex-5)) return(1); } else if (eNB->scheduling_request_config[UE_id].sr_ConfigIndex <= 34) { // 20 ms SR period if ((10*(frame&1)+subframe) == (eNB->scheduling_request_config[UE_id].sr_ConfigIndex-15)) return(1); } else if (eNB->scheduling_request_config[UE_id].sr_ConfigIndex <= 74) { // 40 ms SR period if ((10*(frame&3)+subframe) == (eNB->scheduling_request_config[UE_id].sr_ConfigIndex-35)) return(1); } else if (eNB->scheduling_request_config[UE_id].sr_ConfigIndex <= 154) { // 80 ms SR period if ((10*(frame&7)+subframe) == (eNB->scheduling_request_config[UE_id].sr_ConfigIndex-75)) return(1); } return(0); } void put_harq_pid_in_freelist(LTE_eNB_DLSCH_t *DLSCH_ptr, int harq_pid) { DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->tail_freelist] = harq_pid; DLSCH_ptr->tail_freelist = (DLSCH_ptr->tail_freelist + 1) % 10; } void remove_harq_pid_from_freelist(LTE_eNB_DLSCH_t *DLSCH_ptr, int harq_pid) { if (DLSCH_ptr->head_freelist == DLSCH_ptr->tail_freelist) { LOG_E(PHY, "%s:%d: you cannot read this!\n", __FILE__, __LINE__); abort(); } /* basic check, in case several threads deal with the free list at the same time * in normal situations it should not happen, that's also why we don't use any * locking mechanism to protect the free list * to be refined in case things don't work properly */ if (harq_pid != DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist]) { LOG_E(PHY, "%s:%d: critical error, get in touch with the authors\n", __FILE__, __LINE__); abort(); } DLSCH_ptr->head_freelist = (DLSCH_ptr->head_freelist + 1) % 10; } int32_t add_ue(int16_t rnti, PHY_VARS_eNB *eNB) { uint8_t i; LOG_D(PHY,"[eNB %d/%d] Adding UE with rnti %x\n", eNB->Mod_id, eNB->CC_id, (uint16_t)rnti); for (i=0; i<NUMBER_OF_UE_MAX; i++) { if ((eNB->dlsch[i]==NULL) || (eNB->ulsch[i]==NULL)) { MSC_LOG_EVENT(MSC_PHY_ENB, "0 Failed add ue %"PRIx16" (ENOMEM)", rnti); LOG_E(PHY,"Can't add UE, not enough memory allocated\n"); return(-1); } else { if (eNB->UE_stats[i].crnti==0) { MSC_LOG_EVENT(MSC_PHY_ENB, "0 Add ue %"PRIx16" ", rnti); LOG_D(PHY,"UE_id %d associated with rnti %x\n",i, (uint16_t)rnti); eNB->dlsch[i][0]->rnti = rnti; eNB->ulsch[i]->rnti = rnti; eNB->UE_stats[i].crnti = rnti; eNB->UE_stats[i].Po_PUCCH1_below = 0; eNB->UE_stats[i].Po_PUCCH1_above = (int32_t)pow(10.0,.1*(eNB->frame_parms.ul_power_control_config_common.p0_NominalPUCCH+eNB->rx_total_gain_dB)); eNB->UE_stats[i].Po_PUCCH = (int32_t)pow(10.0,.1*(eNB->frame_parms.ul_power_control_config_common.p0_NominalPUCCH+eNB->rx_total_gain_dB)); LOG_D(PHY,"Initializing Po_PUCCH: p0_NominalPUCCH %d, gain %d => %d\n", eNB->frame_parms.ul_power_control_config_common.p0_NominalPUCCH, eNB->rx_total_gain_dB, eNB->UE_stats[i].Po_PUCCH); return(i); } } } return(-1); } int mac_phy_remove_ue(module_id_t Mod_idP,rnti_t rntiP) { uint8_t i; int j,CC_id; PHY_VARS_eNB *eNB; for (CC_id=0;CC_id<MAX_NUM_CCs;CC_id++) { eNB = PHY_vars_eNB_g[Mod_idP][CC_id]; for (i=0; i<NUMBER_OF_UE_MAX; i++) { if ((eNB->dlsch[i]==NULL) || (eNB->ulsch[i]==NULL)) { MSC_LOG_EVENT(MSC_PHY_ENB, "0 Failed remove ue %"PRIx16" (ENOMEM)", rnti); LOG_E(PHY,"Can't remove UE, not enough memory allocated\n"); return(-1); } else { if (eNB->UE_stats[i].crnti==rntiP) { MSC_LOG_EVENT(MSC_PHY_ENB, "0 Removed ue %"PRIx16" ", rntiP); LOG_D(PHY,"eNB %d removing UE %d with rnti %x\n",eNB->Mod_id,i,rntiP); //LOG_D(PHY,("[PHY] UE_id %d\n",i); clean_eNb_dlsch(eNB->dlsch[i][0]); clean_eNb_ulsch(eNB->ulsch[i]); //eNB->UE_stats[i].crnti = 0; memset(&eNB->UE_stats[i],0,sizeof(LTE_eNB_UE_stats)); // mac_exit_wrapper("Removing UE"); /* clear the harq pid freelist */ eNB->dlsch[i][0]->head_freelist = 0; eNB->dlsch[i][0]->tail_freelist = 0; for (j = 0; j < 8; j++) put_harq_pid_in_freelist(eNB->dlsch[i][0], j); return(i); } } } } MSC_LOG_EVENT(MSC_PHY_ENB, "0 Failed remove ue %"PRIx16" (not found)", rntiP); return(-1); } int8_t find_next_ue_index(PHY_VARS_eNB *eNB) { uint8_t i; for (i=0; i<NUMBER_OF_UE_MAX; i++) { if (eNB->UE_stats[i].crnti==0) { /*if ((eNB->dlsch[i]) && (eNB->dlsch[i][0]) && (eNB->dlsch[i][0]->rnti==0))*/ LOG_D(PHY,"Next free UE id is %d\n",i); return(i); } } return(-1); } int get_ue_active_harq_pid(const uint8_t Mod_id,const uint8_t CC_id,const uint16_t rnti, const int frame, const uint8_t subframe,uint8_t *harq_pid,uint8_t *round,const uint8_t ul_flag) { LTE_eNB_DLSCH_t *DLSCH_ptr; LTE_eNB_ULSCH_t *ULSCH_ptr; uint8_t ulsch_subframe,ulsch_frame; uint8_t i; int8_t UE_id = find_ue(rnti,PHY_vars_eNB_g[Mod_id][CC_id]); int sf1=(10*frame)+subframe,sf2,sfdiff,sfdiff_max=7; if (UE_id==-1) { LOG_D(PHY,"Cannot find UE with rnti %x (Mod_id %d, CC_id %d)\n",rnti, Mod_id, CC_id); *round=0; return(-1); } if (ul_flag == 0) {// this is a DL request DLSCH_ptr = PHY_vars_eNB_g[Mod_id][CC_id]->dlsch[(uint32_t)UE_id][0]; // set to no available process first *harq_pid = -1; for (i=0; i<DLSCH_ptr->Mdlharq; i++) { if (DLSCH_ptr->harq_processes[i]!=NULL) { if (DLSCH_ptr->harq_processes[i]->status == ACTIVE) { sf2 = (DLSCH_ptr->harq_processes[i]->frame*10) + DLSCH_ptr->harq_processes[i]->subframe; if (sf2<=sf1) sfdiff = sf1-sf2; else // this happens when wrapping around 1024 frame barrier sfdiff = 10240 + sf1-sf2; LOG_D(PHY,"process %d is active, round %d (waiting %d)\n",i,DLSCH_ptr->harq_processes[i]->round,sfdiff); if (sfdiff>sfdiff_max) { // this is an active process that is waiting longer than the others (and longer than 7 ms) sfdiff_max = sfdiff; *harq_pid = i; *round = DLSCH_ptr->harq_processes[i]->round; } } } else { // a process is not defined LOG_E(PHY,"[eNB %d] DLSCH process %d for rnti %x (UE_id %d) not allocated\n",Mod_id,i,rnti,UE_id); return(-1); } } /* if no active harq pid, get the oldest in the freelist, if any */ if (*harq_pid == 255 && DLSCH_ptr->head_freelist != DLSCH_ptr->tail_freelist) { *harq_pid = DLSCH_ptr->harq_pid_freelist[DLSCH_ptr->head_freelist]; *round = 0; LOG_D(PHY,"process %d is first free process\n", *harq_pid); } LOG_D(PHY,"get_ue_active_harq_pid DL => Frame %d, Subframe %d : harq_pid %d\n", frame,subframe,*harq_pid); } else { // This is a UL request ULSCH_ptr = PHY_vars_eNB_g[Mod_id][CC_id]->ulsch[(uint32_t)UE_id]; ulsch_subframe = pdcch_alloc2ul_subframe(&PHY_vars_eNB_g[Mod_id][CC_id]->frame_parms,subframe); ulsch_frame = pdcch_alloc2ul_frame(&PHY_vars_eNB_g[Mod_id][CC_id]->frame_parms,frame,subframe); // Note this is for TDD configuration 3,4,5 only *harq_pid = subframe2harq_pid(&PHY_vars_eNB_g[Mod_id][CC_id]->frame_parms, ulsch_frame, ulsch_subframe); *round = ULSCH_ptr->harq_processes[*harq_pid]->round; LOG_T(PHY,"[eNB %d][PUSCH %d] Frame %d subframe %d Checking HARQ, round %d\n",Mod_id,*harq_pid,frame,subframe,*round); } return(0); } int16_t get_target_pusch_rx_power(const module_id_t module_idP, const uint8_t CC_id) { return PHY_vars_eNB_g[module_idP][CC_id]->frame_parms.ul_power_control_config_common.p0_NominalPUSCH; } int16_t get_target_pucch_rx_power(const module_id_t module_idP, const uint8_t CC_id) { return PHY_vars_eNB_g[module_idP][CC_id]->frame_parms.ul_power_control_config_common.p0_NominalPUCCH; } #ifdef EMOS void phy_procedures_emos_eNB_TX(unsigned char subframe, PHY_VARS_eNB *eNB) { } #endif void phy_procedures_eNB_S_RX(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,uint8_t abstraction_flag,relaying_type_t r_type) { UNUSED(r_type); int subframe = proc->subframe_rx; #ifdef DEBUG_PHY_PROC LOG_D(PHY,"[eNB %d] Frame %d: Doing phy_procedures_eNB_S_RX(%d)\n", eNB->Mod_id,proc->frame_rx, subframe); #endif if (abstraction_flag == 0) { lte_eNB_I0_measurements(eNB, subframe, 0, eNB->first_run_I0_measurements); } #ifdef PHY_ABSTRACTION else { lte_eNB_I0_measurements_emul(eNB, 0); } #endif } #ifdef EMOS void phy_procedures_emos_eNB_RX(unsigned char subframe,PHY_VARS_eNB *eNB) { uint8_t aa; uint16_t last_subframe_emos; uint16_t pilot_pos1 = 3 - eNB->frame_parms.Ncp, pilot_pos2 = 10 - 2*eNB->frame_parms.Ncp; uint32_t bytes; last_subframe_emos=0; #ifdef EMOS_CHANNEL //if (last_slot%2==1) // this is for all UL subframes if (subframe==3) for (aa=0; aa<eNB->frame_parms.nb_antennas_rx; aa++) { memcpy(&emos_dump_eNB.channel[aa][last_subframe_emos*2*eNB->frame_parms.N_RB_UL*12], &eNB->pusch_vars[0]->drs_ch_estimates[0][aa][eNB->frame_parms.N_RB_UL*12*pilot_pos1], eNB->frame_parms.N_RB_UL*12*sizeof(int)); memcpy(&emos_dump_eNB.channel[aa][(last_subframe_emos*2+1)*eNB->frame_parms.N_RB_UL*12], &eNB->pusch_vars[0]->drs_ch_estimates[0][aa][eNB->frame_parms.N_RB_UL*12*pilot_pos2], eNB->frame_parms.N_RB_UL*12*sizeof(int)); } #endif if (subframe==4) { emos_dump_eNB.timestamp = rt_get_time_ns(); emos_dump_eNB.frame_tx = eNB->proc[subframe].frame_rx; emos_dump_eNB.rx_total_gain_dB = eNB->rx_total_gain_dB; emos_dump_eNB.mimo_mode = eNB->transmission_mode[0]; memcpy(&emos_dump_eNB.measurements, &eNB->measurements[0], sizeof(PHY_MEASUREMENTS_eNB)); memcpy(&emos_dump_eNB.UE_stats[0],&eNB->UE_stats[0],NUMBER_OF_UE_MAX*sizeof(LTE_eNB_UE_stats)); bytes = rtf_put(CHANSOUNDER_FIFO_MINOR, &emos_dump_eNB, sizeof(fifo_dump_emos_eNB)); //bytes = rtf_put(CHANSOUNDER_FIFO_MINOR, "test", sizeof("test")); if (bytes!=sizeof(fifo_dump_emos_eNB)) { LOG_W(PHY,"[eNB %d] Frame %d, subframe %d, Problem writing EMOS data to FIFO (bytes=%d, size=%d)\n", eNB->Mod_id,eNB->proc[(subframe+1)%10].frame_rx, subframe,bytes,sizeof(fifo_dump_emos_eNB)); } else { if (eNB->proc[(subframe+1)%10].frame_tx%100==0) { LOG_I(PHY,"[eNB %d] Frame %d (%d), subframe %d, Writing %d bytes EMOS data to FIFO\n", eNB->Mod_id,eNB->proc[(subframe+1)%10].frame_rx, ((fifo_dump_emos_eNB*)&emos_dump_eNB)->frame_tx, subframe, bytes); } } } } #endif #define AMP_OVER_SQRT2 ((AMP*ONE_OVER_SQRT2_Q15)>>15) #define AMP_OVER_2 (AMP>>1) int QPSK[4]= {AMP_OVER_SQRT2|(AMP_OVER_SQRT2<<16),AMP_OVER_SQRT2|((65536-AMP_OVER_SQRT2)<<16),((65536-AMP_OVER_SQRT2)<<16)|AMP_OVER_SQRT2,((65536-AMP_OVER_SQRT2)<<16)|(65536-AMP_OVER_SQRT2)}; int QPSK2[4]= {AMP_OVER_2|(AMP_OVER_2<<16),AMP_OVER_2|((65536-AMP_OVER_2)<<16),((65536-AMP_OVER_2)<<16)|AMP_OVER_2,((65536-AMP_OVER_2)<<16)|(65536-AMP_OVER_2)}; unsigned int taus(void); DCI_PDU DCI_pdu_tmp; void pmch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,PHY_VARS_RN *rn, int abstraction_flag,relaying_type_t r_type) { #ifdef Rel10 MCH_PDU *mch_pduP; MCH_PDU mch_pdu; // uint8_t sync_area=255; #endif int subframe = proc->subframe_tx; if (abstraction_flag==0) { // This is DL-Cell spec pilots in Control region generate_pilots_slot(eNB, eNB->common_vars.txdataF[0], AMP, subframe<<1,1); } #ifdef Rel10 // 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_I(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_I(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_I(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, abstraction_flag); // Generate PMCH generate_mch(eNB,proc,(uint8_t*)mch_pduP->payload,abstraction_flag); } 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,int abstraction_flag) { LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; int **txdataF = eNB->common_vars.txdataF[0]; uint8_t *pbch_pdu=&eNB->pbch_pdu[0]; int subframe = proc->subframe_tx; int frame = proc->frame_tx; // generate Cell-Specific Reference Signals for both slots if (abstraction_flag==0) { 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) && (abstraction_flag==0)) { generate_pss(txdataF, AMP, fp, (fp->Ncp==NORMAL) ? 6 : 5, 0); generate_sss(txdataF, AMP, fp, (fp->Ncp==NORMAL) ? 5 : 4, 0); } // generate PBCH (Physical Broadcast CHannel) info if ((frame&3) == 0) { pbch_pdu[2] = 0; // FIXME setting pbch_pdu[2] to zero makes the switch statement easier: remove all the or-operators switch (fp->N_RB_DL) { case 6: pbch_pdu[2] = (pbch_pdu[2]&0x1f) | (0<<5); break; case 15: pbch_pdu[2] = (pbch_pdu[2]&0x1f) | (1<<5); break; case 25: pbch_pdu[2] = (pbch_pdu[2]&0x1f) | (2<<5); break; case 50: pbch_pdu[2] = (pbch_pdu[2]&0x1f) | (3<<5); break; case 75: pbch_pdu[2] = (pbch_pdu[2]&0x1f) | (4<<5); break; case 100: pbch_pdu[2] = (pbch_pdu[2]&0x1f) | (5<<5); break; default: // FIXME if we get here, this should be flagged as an error, right? pbch_pdu[2] = (pbch_pdu[2]&0x1f) | (2<<5); break; } pbch_pdu[2] = (pbch_pdu[2]&0xef) | ((fp->phich_config_common.phich_duration << 4)&0x10); switch (fp->phich_config_common.phich_resource) { case oneSixth: pbch_pdu[2] = (pbch_pdu[2]&0xf3) | (0<<2); break; case half: pbch_pdu[2] = (pbch_pdu[2]&0xf3) | (1<<2); break; case one: pbch_pdu[2] = (pbch_pdu[2]&0xf3) | (2<<2); break; case two: pbch_pdu[2] = (pbch_pdu[2]&0xf3) | (3<<2); break; default: // unreachable break; } pbch_pdu[2] = (pbch_pdu[2]&0xfc) | ((frame>>8)&0x3); pbch_pdu[1] = frame&0xfc; pbch_pdu[0] = 0; } /// First half of SSS (TDD, slot 1) if ((fp->frame_type == TDD)&& (abstraction_flag==0)){ generate_sss(txdataF, AMP, fp, (fp->Ncp==NORMAL) ? 6 : 5, 1); } /// generate PBCH if (abstraction_flag==0) { generate_pbch(&eNB->pbch, txdataF, AMP, fp, pbch_pdu, frame&3); } #ifdef PHY_ABSTRACTION else { generate_pbch_emul(eNB,pbch_pdu); } #endif } else if ((subframe == 1) && (fp->frame_type == TDD)&& (abstraction_flag==0)) { generate_pss(txdataF, AMP, fp, 2, 2); } // Second half of PSS/SSS (FDD, slot 10) else if ((subframe == 5) && (fp->frame_type == FDD) && (abstraction_flag==0)) { 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) && (abstraction_flag==0)) { 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) && (abstraction_flag==0)) { generate_pss(txdataF, AMP, fp, 2, 12); } } void generate_eNB_dlsch_params(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_alloc,const int UE_id) { LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; int frame = proc->frame_tx; int subframe = proc->subframe_tx; // if we have SI_RNTI, configure dlsch parameters and CCE index if (dci_alloc->rnti == SI_RNTI) { LOG_D(PHY,"Generating dlsch params for SI_RNTI\n"); generate_eNB_dlsch_params_from_dci(frame, subframe, &dci_alloc->dci_pdu[0], dci_alloc->rnti, dci_alloc->format, &eNB->dlsch_SI, fp, eNB->pdsch_config_dedicated, SI_RNTI, 0, P_RNTI, eNB->UE_stats[0].DL_pmi_single); eNB->dlsch_SI->nCCE[subframe] = dci_alloc->firstCCE; LOG_T(PHY,"[eNB %"PRIu8"] Frame %d subframe %d : CCE resource for common DCI (SI) => %"PRIu8"\n",eNB->Mod_id,frame,subframe, eNB->dlsch_SI->nCCE[subframe]); #if defined(SMBV) // configure SI DCI if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4)) { LOG_D(PHY,"[SMBV] Frame %3d, SI in SF %d DCI %"PRIu32"\n",frame,subframe,i); smbv_configure_common_dci(smbv_fname,(smbv_frame_cnt*10) + (subframe), "SI", dci_alloc, i); } #endif } else if (dci_alloc->ra_flag == 1) { // This is format 1A allocation for RA // configure dlsch parameters and CCE index LOG_D(PHY,"Generating dlsch params for RA_RNTI\n"); generate_eNB_dlsch_params_from_dci(frame, subframe, &dci_alloc->dci_pdu[0], dci_alloc->rnti, dci_alloc->format, &eNB->dlsch_ra, fp, eNB->pdsch_config_dedicated, SI_RNTI, dci_alloc->rnti, P_RNTI, eNB->UE_stats[0].DL_pmi_single); eNB->dlsch_ra->nCCE[subframe] = dci_alloc->firstCCE; LOG_D(PHY,"[eNB %"PRIu8"] Frame %d subframe %d : CCE resource for common DCI (RA) => %"PRIu8"\n",eNB->Mod_id,frame,subframe, eNB->dlsch_ra->nCCE[subframe]); #if defined(SMBV) // configure RA DCI if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4)) { LOG_D(PHY,"[SMBV] Frame %3d, RA in SF %d DCI %"PRIu32"\n",frame,subframe,i); smbv_configure_common_dci(smbv_fname,(smbv_frame_cnt*10) + (subframe), "RA", dci_alloc, i); } #endif } else if ((dci_alloc->format != format0)&& (dci_alloc->format != format3)&& (dci_alloc->format != format3A)&& (dci_alloc->format != format4)){ // this is a normal DLSCH allocation if (UE_id>=0) { #if defined(SMBV) // Configure this user if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4)) { LOG_D(PHY,"[SMBV] Frame %3d, SF %d (SMBV SF %d) Configuring user %d with RNTI %"PRIu16" in TM%"PRIu8"\n",frame,subframe,(smbv_frame_cnt*10) + (subframe),UE_id+1, dci_alloc->rnti,eNB->transmission_mode[(uint8_t)UE_id]); smbv_configure_user(smbv_fname,UE_id+1,eNB->transmission_mode[(uint8_t)UE_id],dci_alloc->rnti); } #endif LOG_D(PHY,"Generating dlsch params for RNTI %x\n",dci_alloc->rnti); generate_eNB_dlsch_params_from_dci(frame, subframe, &dci_alloc->dci_pdu[0], dci_alloc->rnti, dci_alloc->format, eNB->dlsch[(uint8_t)UE_id], fp, eNB->pdsch_config_dedicated, SI_RNTI, 0, P_RNTI, eNB->UE_stats[(uint8_t)UE_id].DL_pmi_single); LOG_D(PHY,"[eNB %"PRIu8"][PDSCH %"PRIx16"/%"PRIu8"] Frame %d subframe %d: Generated dlsch params\n", eNB->Mod_id,dci_alloc->rnti,eNB->dlsch[(uint8_t)UE_id][0]->current_harq_pid,frame,subframe); eNB->dlsch[(uint8_t)UE_id][0]->nCCE[subframe] = dci_alloc->firstCCE; LOG_D(PHY,"[eNB %"PRIu8"] Frame %d subframe %d : CCE resource for ue DCI (PDSCH %"PRIx16") => %"PRIu8"/%u\n",eNB->Mod_id,frame,subframe, dci_alloc->rnti,eNB->dlsch[(uint8_t)UE_id][0]->nCCE[subframe]); #if defined(SMBV) // configure UE-spec DCI if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4)) { LOG_D(PHY,"[SMBV] Frame %3d, PDSCH in SF %d DCI %"PRIu32"\n",frame,subframe,i); smbv_configure_ue_spec_dci(smbv_fname,(smbv_frame_cnt*10) + (subframe), UE_id+1,dci_alloc, i); } #endif LOG_D(PHY,"[eNB %"PRIu8"][DCI][PDSCH %"PRIx16"] Frame %d subframe %d UE_id %"PRId8" Generated DCI format %d, aggregation %d\n", eNB->Mod_id, dci_alloc->rnti, frame, subframe,UE_id, dci_alloc->format, 1<<dci_alloc->L); } else { LOG_D(PHY,"[eNB %"PRIu8"][PDSCH] Frame %d : No UE_id with corresponding rnti %"PRIx16", dropping DLSCH\n", eNB->Mod_id,frame,dci_alloc->rnti); } } } void generate_eNB_ulsch_params(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_alloc,const int UE_id) { int harq_pid; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; int frame = proc->frame_tx; int subframe = proc->subframe_tx; LOG_D(PHY, "[eNB %"PRIu8"][PUSCH %"PRIu8"] Frame %d subframe %d UL Frame %"PRIu32", UL Subframe %"PRIu8", Generated ULSCH (format0) DCI (rnti %"PRIx16", dci %"PRIx8"), aggregation %d\n", eNB->Mod_id, subframe2harq_pid(fp, pdcch_alloc2ul_frame(fp,frame,subframe), pdcch_alloc2ul_subframe(fp,subframe)), frame, subframe, pdcch_alloc2ul_frame(fp,frame,subframe), pdcch_alloc2ul_subframe(fp,subframe), dci_alloc->rnti, dci_alloc->dci_pdu[0], 1<<dci_alloc->L); generate_eNB_ulsch_params_from_dci(eNB, proc, &dci_alloc->dci_pdu[0], dci_alloc->rnti, format0, UE_id, SI_RNTI, 0, P_RNTI, CBA_RNTI, 0); // do_srs LOG_T(PHY,"[eNB %"PRIu8"] Frame %d subframe %d : CCE resources for UE spec DCI (PUSCH %"PRIx16") => %d\n", eNB->Mod_id,frame,subframe,dci_alloc->rnti, dci_alloc->firstCCE); #if defined(SMBV) // configure UE-spec DCI for UL Grant if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4)) { LOG_D(PHY,"[SMBV] Frame %3d, SF %d UL DCI %"PRIu32"\n",frame,subframe,i); smbv_configure_ue_spec_dci(smbv_fname,(smbv_frame_cnt*10) + (subframe), UE_id+1, &DCI_pdu->dci_alloc[i], i); } #endif // get the hard_pid for this subframe harq_pid = subframe2harq_pid(fp, pdcch_alloc2ul_frame(fp,frame,subframe), pdcch_alloc2ul_subframe(fp,subframe)); if (harq_pid==255) { // should not happen, log an error and exit, this is a fatal error LOG_E(PHY,"[eNB %"PRIu8"] Frame %d: Bad harq_pid for ULSCH allocation\n",eNB->Mod_id,frame); mac_xface->macphy_exit("FATAL\n"); } if ((dci_alloc->rnti >= CBA_RNTI) && (dci_alloc->rnti < P_RNTI)) eNB->ulsch[(uint32_t)UE_id]->harq_processes[harq_pid]->subframe_cba_scheduling_flag = 1; else eNB->ulsch[(uint32_t)UE_id]->harq_processes[harq_pid]->subframe_scheduling_flag = 1; } void pdsch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,LTE_eNB_DLSCH_t *dlsch, LTE_eNB_DLSCH_t *dlsch1,LTE_eNB_UE_stats *ue_stats,int ra_flag,int num_pdcch_symbols,int abstraction_flag) { int frame=proc->frame_tx; int subframe=proc->subframe_tx; int harq_pid = dlsch->current_harq_pid; 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; uint8_t *DLSCH_pdu=NULL; uint8_t DLSCH_pdu_tmp[768*8]; uint8_t DLSCH_pdu_rar[256]; int i; LOG_D(PHY, "[eNB %"PRIu8"][PDSCH %"PRIx16"/%"PRIu8"] Frame %d, subframe %d: Generating PDSCH/DLSCH with input size = %"PRIu16", G %d, nb_rb %"PRIu16", mcs %"PRIu8", pmi_alloc %"PRIx16", rv %"PRIu8" (round %"PRIu8")\n", eNB->Mod_id, dlsch->rnti,harq_pid, frame, subframe, input_buffer_length, get_G(fp, dlsch_harq->nb_rb, dlsch_harq->rb_alloc, get_Qm(dlsch_harq->mcs), dlsch_harq->Nl, num_pdcch_symbols,frame,subframe), dlsch_harq->nb_rb, dlsch_harq->mcs, 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", mcs %"PRIu8", pmi_alloc %"PRIx16", rv %"PRIu8" (round %"PRIu8")", frame, subframe, input_buffer_length, get_G(fp, dlsch_harq->nb_rb, dlsch_harq->rb_alloc, get_Qm(dlsch_harq->mcs), dlsch_harq->Nl, num_pdcch_symbols,frame,subframe), dlsch_harq->nb_rb, dlsch_harq->mcs, 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]++; if (eNB->mac_enabled==1) { if (ra_flag == 0) { DLSCH_pdu = mac_xface->get_dlsch_sdu(eNB->Mod_id, eNB->CC_id, frame, dlsch->rnti, 0); } else { int16_t crnti = mac_xface->fill_rar(eNB->Mod_id, eNB->CC_id, frame, DLSCH_pdu_rar, fp->N_RB_UL, input_buffer_length); DLSCH_pdu = DLSCH_pdu_rar; int UE_id; if (crnti!=0) UE_id = add_ue(crnti,eNB); else UE_id = -1; if (UE_id==-1) { LOG_W(PHY,"[eNB] Max user count reached.\n"); mac_xface->cancel_ra_proc(eNB->Mod_id, eNB->CC_id, frame, crnti); } else { eNB->UE_stats[(uint32_t)UE_id].mode = RA_RESPONSE; // Initialize indicator for first SR (to be cleared after ConnectionSetup is acknowledged) eNB->first_sr[(uint32_t)UE_id] = 1; generate_eNB_ulsch_params_from_rar(DLSCH_pdu, frame, (subframe), eNB->ulsch[(uint32_t)UE_id], fp); eNB->ulsch[(uint32_t)UE_id]->Msg3_active = 1; get_Msg3_alloc(fp, subframe, frame, &eNB->ulsch[(uint32_t)UE_id]->Msg3_frame, &eNB->ulsch[(uint32_t)UE_id]->Msg3_subframe); LOG_D(PHY,"[eNB][RAPROC] Frame %d subframe %d, Activated Msg3 demodulation for UE %"PRId8" in frame %"PRIu32", subframe %"PRIu8"\n", frame, subframe, UE_id, eNB->ulsch[(uint32_t)UE_id]->Msg3_frame, eNB->ulsch[(uint32_t)UE_id]->Msg3_subframe); } if (ue_stats) ue_stats->total_TBS_MAC += dlsch_harq->TBS; } } else { DLSCH_pdu = DLSCH_pdu_tmp; for (i=0; i<input_buffer_length; i++) DLSCH_pdu[i] = (unsigned char)(taus()&0xff); } #if defined(SMBV) // Configures the data source of allocation (allocation is configured by DCI) if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4)) { LOG_D(PHY,"[SMBV] Frame %3d, Configuring PDSCH payload in SF %d alloc %"PRIu8"\n",frame,(smbv_frame_cnt*10) + (subframe),smbv_alloc_cnt); // smbv_configure_datalist_for_user(smbv_fname, find_ue(dlsch->rnti,eNB)+1, DLSCH_pdu, input_buffer_length); } #endif #ifdef DEBUG_PHY_PROC #ifdef DEBUG_DLSCH LOG_T(PHY,"eNB DLSCH SDU: \n"); T(T_ENB_PHY_DLSCH_UE_DCI, T_INT(phy_vars_eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(UE_id), T_INT(DCI_pdu->dci_alloc[i].rnti), T_INT(DCI_pdu->dci_alloc[i].format), T_INT(phy_vars_eNB->dlsch_eNB[(int)UE_id][0]->current_harq_pid)); phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][0]->nCCE[subframe] = DCI_pdu->dci_alloc[i].firstCCE; LOG_D(PHY,"[eNB %"PRIu8"] Frame %d subframe %d : CCE resource for ue DCI (PDSCH %"PRIx16") => %"PRIu8"/%u\n",phy_vars_eNB->Mod_id,phy_vars_eNB->proc[sched_subframe].frame_tx,subframe, DCI_pdu->dci_alloc[i].rnti,phy_vars_eNB->dlsch_eNB[(uint8_t)UE_id][0]->nCCE[subframe],DCI_pdu->dci_alloc[i].firstCCE); for (i=0; i<dlsch_harq->TBS>>3; i++) LOG_T(PHY,"%"PRIx8".",DLSCH_pdu[i]); LOG_T(PHY,"\n"); #endif #endif } 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 } if (abstraction_flag==0) { LOG_D(PHY,"Generating DLSCH/PDSCH %d\n",ra_flag); // 36-212 start_meas(&eNB->dlsch_encoding_stats); dlsch_encoding(DLSCH_pdu, fp, num_pdcch_symbols, 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, get_G(fp, dlsch_harq->nb_rb, dlsch_harq->rb_alloc, get_Qm(dlsch_harq->mcs), dlsch_harq->Nl, num_pdcch_symbols,frame,subframe), 0, subframe<<1); stop_meas(&eNB->dlsch_scrambling_stats); start_meas(&eNB->dlsch_modulation_stats); dlsch_modulation(eNB->common_vars.txdataF[0], AMP, subframe, fp, num_pdcch_symbols, dlsch, dlsch1); stop_meas(&eNB->dlsch_modulation_stats); } #ifdef PHY_ABSTRACTION else { start_meas(&eNB->dlsch_encoding_stats); dlsch_encoding_emul(eNB, DLSCH_pdu, dlsch); stop_meas(&eNB->dlsch_encoding_stats); } #endif dlsch->active = 0; } void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, eNB_rxtx_proc_t *proc, uint8_t abstraction_flag, relaying_type_t r_type, PHY_VARS_RN *rn) { UNUSED(rn); int frame=proc->frame_tx; int subframe=proc->subframe_tx; // uint16_t input_buffer_length; uint32_t i,aa; uint8_t harq_pid; DCI_PDU *DCI_pdu; DCI_PDU DCI_pdu_tmp; int8_t UE_id=0; uint8_t num_pdcch_symbols=0; uint8_t ul_subframe; uint32_t ul_frame; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; DCI_ALLOC_t *dci_alloc=(DCI_ALLOC_t *)NULL; #if defined(SMBV) // counts number of allocations in subframe // there is at least one allocation for PDCCH uint8_t smbv_alloc_cnt = 1; #endif VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_TX,1); start_meas(&eNB->phy_proc_tx); for (i=0; i<NUMBER_OF_UE_MAX; i++) { // If we've dropped the UE, go back to PRACH mode for this UE if ((frame==0)&&(subframe==0)) { if (eNB->UE_stats[i].crnti > 0) { LOG_I(PHY,"UE %d : rnti %x\n",i,eNB->UE_stats[i].crnti); } } if (eNB->UE_stats[i].ulsch_consecutive_errors == ULSCH_max_consecutive_errors) { LOG_W(PHY,"[eNB %d, CC %d] frame %d, subframe %d, UE %d: ULSCH consecutive error count reached %u, triggering UL Failure\n", eNB->Mod_id,eNB->CC_id,frame,subframe, i, eNB->UE_stats[i].ulsch_consecutive_errors); eNB->UE_stats[i].ulsch_consecutive_errors=0; mac_xface->UL_failure_indication(eNB->Mod_id, eNB->CC_id, frame, eNB->UE_stats[i].crnti, subframe); } } // Get scheduling info for next subframe // This is called only for the CC_id = 0 and triggers scheduling for all CC_id's if (eNB->mac_enabled==1) { if (eNB->CC_id == 0) { mac_xface->eNB_dlsch_ulsch_scheduler(eNB->Mod_id,0,frame,subframe);//,1); } } // clear the transmit data array for the current subframe if (abstraction_flag==0) { for (aa=0; aa<fp->nb_antennas_tx_eNB; aa++) { memset(&eNB->common_vars.txdataF[0][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,abstraction_flag,r_type); } else { // this is not a pmch subframe, so generate PSS/SSS/PBCH common_signal_procedures(eNB,proc,abstraction_flag); } #if defined(SMBV) // PBCH takes one allocation if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4)) { if (subframe==0) smbv_alloc_cnt++; } #endif if (eNB->mac_enabled==1) { // Parse DCI received from MAC VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PDCCH_TX,1); DCI_pdu = mac_xface->get_dci_sdu(eNB->Mod_id, eNB->CC_id, frame, subframe); } else { DCI_pdu = &DCI_pdu_tmp; #ifdef EMOS_CHANNEL fill_dci_emos(DCI_pdu,eNB); #else fill_dci(DCI_pdu,eNB,proc); #endif } // 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); if ((subframe_select(fp,ul_subframe)==SF_UL) || (fp->frame_type == FDD)) { harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe); // clear DCI allocation maps for new subframe for (i=0; i<NUMBER_OF_UE_MAX; i++) if (eNB->ulsch[i]) { eNB->ulsch[i]->harq_processes[harq_pid]->dci_alloc=0; eNB->ulsch[i]->harq_processes[harq_pid]->rar_alloc=0; } } // clear previous allocation information for all UEs for (i=0; i<NUMBER_OF_UE_MAX; i++) { eNB->dlsch[i][0]->subframe_tx[subframe] = 0; } num_pdcch_symbols = DCI_pdu->num_pdcch_symbols; 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); #if defined(SMBV) // Sets up PDCCH and DCI table if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4) && ((DCI_pdu->Num_common_dci+DCI_pdu->Num_ue_spec_dci)>0)) { LOG_D(PHY,"[SMBV] Frame %3d, SF %d PDCCH, number of DCIs %d\n",frame,subframe,DCI_pdu->Num_common_dci+DCI_pdu->Num_ue_spec_dci); dump_dci(fp,&DCI_pdu->dci_alloc[0]); smbv_configure_pdcch(smbv_fname,(smbv_frame_cnt*10) + (subframe),num_pdcch_symbols,DCI_pdu->Num_common_dci+DCI_pdu->Num_ue_spec_dci); } #endif VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,DCI_pdu->num_pdcch_symbols); // loop over all DCIs for this subframe to generate DLSCH allocations for (i=0; i<DCI_pdu->Num_common_dci + DCI_pdu->Num_ue_spec_dci ; i++) { LOG_D(PHY,"[eNB] Subframe %d: DCI %d/%d : rnti %x, CCEind %d\n",subframe,i,DCI_pdu->Num_common_dci+DCI_pdu->Num_ue_spec_dci,DCI_pdu->dci_alloc[i].rnti,DCI_pdu->dci_alloc[i].firstCCE); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,DCI_pdu->dci_alloc[i].rnti); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,DCI_pdu->dci_alloc[i].format); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,DCI_pdu->dci_alloc[i].firstCCE); dci_alloc = &DCI_pdu->dci_alloc[i]; if ((dci_alloc->rnti<= P_RNTI) && (dci_alloc->ra_flag!=1)) { if (eNB->mac_enabled==1) UE_id = find_ue((int16_t)dci_alloc->rnti,eNB); else UE_id = i; } else UE_id=0; generate_eNB_dlsch_params(eNB,proc,dci_alloc,UE_id); } VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,(frame*10)+subframe); // Apply physicalConfigDedicated if needed // This is for UEs that have received this IE, which changes these DL and UL configuration, we apply after a delay for the eNodeB UL parameters phy_config_dedicated_eNB_step2(eNB); // Now loop again over the DCIs for UL configuration for (i=0; i<DCI_pdu->Num_common_dci + DCI_pdu->Num_ue_spec_dci ; i++) { if (dci_alloc->format == format0) { // this is a ULSCH allocation if (eNB->mac_enabled==1) UE_id = find_ue((int16_t)dci_alloc->rnti,eNB); else UE_id = i; if (UE_id<0) { // should not happen, log an error and exit, this is a fatal error LOG_E(PHY,"[eNB %"PRIu8"] Frame %d: Unknown UE_id for rnti %"PRIx16"\n",eNB->Mod_id,frame,dci_alloc->rnti); mac_xface->macphy_exit("FATAL\n"); } generate_eNB_ulsch_params(eNB,proc,dci_alloc,UE_id); } } // if we have DCI to generate do it now if ((DCI_pdu->Num_common_dci + DCI_pdu->Num_ue_spec_dci)>0) { } else { // for emulation!! eNB->num_ue_spec_dci[(subframe)&1]=0; eNB->num_common_dci[(subframe)&1]=0; } if (abstraction_flag == 0) { if (DCI_pdu->Num_ue_spec_dci+DCI_pdu->Num_common_dci > 0) LOG_D(PHY,"[eNB %"PRIu8"] Frame %d, subframe %d: Calling generate_dci_top (pdcch) (common %"PRIu8",ue_spec %"PRIu8")\n",eNB->Mod_id,frame, subframe, DCI_pdu->Num_common_dci,DCI_pdu->Num_ue_spec_dci); num_pdcch_symbols = generate_dci_top(DCI_pdu->Num_ue_spec_dci, DCI_pdu->Num_common_dci, DCI_pdu->dci_alloc, 0, AMP, fp, eNB->common_vars.txdataF[0], subframe); } #ifdef PHY_ABSTRACTION // FIXME this ifdef seems suspicious else { LOG_D(PHY,"[eNB %"PRIu8"] Frame %d, subframe %d: Calling generate_dci_to_emul\n",eNB->Mod_id,frame, subframe); num_pdcch_symbols = generate_dci_top_emul(eNB,DCI_pdu->Num_ue_spec_dci,DCI_pdu->Num_common_dci,DCI_pdu->dci_alloc,subframe); } #endif VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PDCCH_TX,0); // Check for SI activity if (eNB->dlsch_SI->active == 1) { pdsch_procedures(eNB,proc,eNB->dlsch_SI,(LTE_eNB_DLSCH_t*)NULL,(LTE_eNB_UE_stats*)NULL,0,num_pdcch_symbols,abstraction_flag); #if defined(SMBV) // Configures the data source of allocation (allocation is configured by DCI) if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4)) { LOG_D(PHY,"[SMBV] Frame %3d, Configuring SI payload in SF %d alloc %"PRIu8"\n",frame,(smbv_frame_cnt*10) + (subframe),smbv_alloc_cnt); smbv_configure_datalist_for_alloc(smbv_fname, smbv_alloc_cnt++, (smbv_frame_cnt*10) + (subframe), DLSCH_pdu, input_buffer_length); } #endif } // Check for RA activity if (eNB->dlsch_ra->active == 1) { #if defined(SMBV) // Configures the data source of allocation (allocation is configured by DCI) if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4)) { LOG_D(PHY,"[SMBV] Frame %3d, Configuring RA payload in SF %d alloc %"PRIu8"\n",frame,(smbv_frame_cnt*10) + (subframe),smbv_alloc_cnt); smbv_configure_datalist_for_alloc(smbv_fname, smbv_alloc_cnt++, (smbv_frame_cnt*10) + (subframe), dlsch_input_buffer, input_buffer_length); } #endif LOG_D(PHY,"[eNB %"PRIu8"][RAPROC] Frame %d, subframe %d: Calling generate_dlsch (RA),Msg3 frame %"PRIu32", Msg3 subframe %"PRIu8"\n", eNB->Mod_id, frame, subframe, eNB->ulsch[(uint32_t)UE_id]->Msg3_frame, eNB->ulsch[(uint32_t)UE_id]->Msg3_subframe); pdsch_procedures(eNB,proc,eNB->dlsch_ra,(LTE_eNB_DLSCH_t*)NULL,(LTE_eNB_UE_stats*)NULL,1,num_pdcch_symbols,abstraction_flag); eNB->dlsch_ra->active = 0; } // Now scan UE specific DLSCH for (UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) { if ((eNB->dlsch[(uint8_t)UE_id][0])&& (eNB->dlsch[(uint8_t)UE_id][0]->rnti>0)&& (eNB->dlsch[(uint8_t)UE_id][0]->active == 1)) { pdsch_procedures(eNB,proc,eNB->dlsch[(uint8_t)UE_id][0],eNB->dlsch[(uint8_t)UE_id][1],&eNB->UE_stats[(uint32_t)UE_id],0,num_pdcch_symbols,abstraction_flag); } else if ((eNB->dlsch[(uint8_t)UE_id][0])&& (eNB->dlsch[(uint8_t)UE_id][0]->rnti>0)&& (eNB->dlsch[(uint8_t)UE_id][0]->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) eNB->dlsch[(uint8_t)UE_id][0]->subframe_tx[subframe]=0; } } // if we have PHICH to generate if (is_phich_subframe(fp,subframe)) { generate_phich_top(eNB, proc, AMP, 0, abstraction_flag); } #ifdef EMOS phy_procedures_emos_eNB_TX(subframe, eNB); #endif #if !(defined(EXMIMO) || defined(OAI_USRP) || defined (CPRIGW)) if (abstraction_flag==0) { start_meas(&eNB->ofdm_mod_stats); do_OFDM_mod(eNB->common_vars.txdataF[0], eNB->common_vars.txdata[0], frame,subframe<<1, fp); do_OFDM_mod(eNB->common_vars.txdataF[0], eNB->common_vars.txdata[0], frame,1+(subframe<<1), fp); stop_meas(&eNB->ofdm_mod_stats); } #endif VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_TX,0); stop_meas(&eNB->phy_proc_tx); } void process_Msg3(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,uint8_t UE_id, uint8_t harq_pid) { // this prepares the demodulation of the first PUSCH of a new user, containing Msg3 int subframe = proc->subframe_rx; int frame = proc->frame_rx; LOG_D(PHY,"[eNB %d][RAPROC] frame %d : subframe %d : process_Msg3 UE_id %d (active %d, subframe %d, frame %d)\n", eNB->Mod_id, frame,subframe, UE_id,eNB->ulsch[(uint32_t)UE_id]->Msg3_active, eNB->ulsch[(uint32_t)UE_id]->Msg3_subframe, eNB->ulsch[(uint32_t)UE_id]->Msg3_frame); eNB->ulsch[(uint32_t)UE_id]->Msg3_flag = 0; if ((eNB->ulsch[(uint32_t)UE_id]->Msg3_active == 1) && (eNB->ulsch[(uint32_t)UE_id]->Msg3_subframe == subframe) && (eNB->ulsch[(uint32_t)UE_id]->Msg3_frame == (uint32_t)frame)) { // harq_pid = 0; eNB->ulsch[(uint32_t)UE_id]->Msg3_active = 0; eNB->ulsch[(uint32_t)UE_id]->Msg3_flag = 1; eNB->ulsch[(uint32_t)UE_id]->harq_processes[harq_pid]->subframe_scheduling_flag=1; LOG_D(PHY,"[eNB %d][RAPROC] frame %d, subframe %d: Setting subframe_scheduling_flag (Msg3) for UE %d\n", eNB->Mod_id, frame,subframe,UE_id); } } // This function retrieves the harq_pid of the corresponding DLSCH process // and updates the error statistics of the DLSCH based on the received ACK // info from UE along with the round index. It also performs the fine-grain // rate-adaptation based on the error statistics derived from the ACK/NAK process void process_HARQ_feedback(uint8_t UE_id, PHY_VARS_eNB *eNB, eNB_rxtx_proc_t *proc, uint8_t pusch_flag, uint8_t *pucch_payload, uint8_t pucch_sel, uint8_t SR_payload) { LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; uint8_t dl_harq_pid[8],dlsch_ACK[8],dl_subframe; LTE_eNB_DLSCH_t *dlsch = eNB->dlsch[(uint32_t)UE_id][0]; LTE_eNB_UE_stats *ue_stats = &eNB->UE_stats[(uint32_t)UE_id]; LTE_DL_eNB_HARQ_t *dlsch_harq_proc; uint8_t subframe_m4,M,m; int mp; int all_ACKed=1,nb_alloc=0,nb_ACK=0; int frame = proc->frame_rx; int subframe = proc->subframe_rx; int harq_pid = subframe2harq_pid( fp,frame,subframe); if (fp->frame_type == FDD) { //FDD subframe_m4 = (subframe<4) ? subframe+6 : subframe-4; dl_harq_pid[0] = dlsch->harq_ids[subframe_m4]; M=1; if (pusch_flag == 1) { dlsch_ACK[0] = eNB->ulsch[(uint8_t)UE_id]->harq_processes[harq_pid]->o_ACK[0]; if (dlsch->subframe_tx[subframe_m4]==1) LOG_D(PHY,"[eNB %d] Frame %d: Received ACK/NAK %d on PUSCH for subframe %d\n",eNB->Mod_id, frame,dlsch_ACK[0],subframe_m4); } else { dlsch_ACK[0] = pucch_payload[0]; LOG_D(PHY,"[eNB %d] Frame %d: Received ACK/NAK %d on PUCCH for subframe %d\n",eNB->Mod_id, frame,dlsch_ACK[0],subframe_m4); /* if (dlsch_ACK[0]==0) AssertFatal(0,"Exiting on NAK on PUCCH\n"); */ } #if defined(MESSAGE_CHART_GENERATOR_PHY) MSC_LOG_RX_MESSAGE( MSC_PHY_ENB,MSC_PHY_UE, NULL,0, "%05u:%02u %s received %s rnti %x harq id %u tx SF %u", frame,subframe, (pusch_flag == 1)?"PUSCH":"PUCCH", (dlsch_ACK[0])?"ACK":"NACK", dlsch->rnti, dl_harq_pid[0], subframe_m4 ); #endif } else { // TDD Handle M=1,2 cases only M=ul_ACK_subframe2_M(fp, subframe); // Now derive ACK information for TDD if (pusch_flag == 1) { // Do PUSCH ACK/NAK first // detect missing DAI //FK: this code is just a guess //RK: not exactly, yes if scheduled from PHICH (i.e. no DCI format 0) // otherwise, it depends on how many of the PDSCH in the set are scheduled, we can leave it like this, // but we have to adapt the code below. For example, if only one out of 2 are scheduled, only 1 bit o_ACK is used dlsch_ACK[0] = eNB->ulsch[(uint8_t)UE_id]->harq_processes[harq_pid]->o_ACK[0]; dlsch_ACK[1] = (eNB->pucch_config_dedicated[UE_id].tdd_AckNackFeedbackMode == bundling) ?eNB->ulsch[(uint8_t)UE_id]->harq_processes[harq_pid]->o_ACK[0]:eNB->ulsch[(uint8_t)UE_id]->harq_processes[harq_pid]->o_ACK[1]; } else { // PUCCH ACK/NAK if ((SR_payload == 1)&&(pucch_sel!=2)) { // decode Table 7.3 if multiplexing and SR=1 nb_ACK = 0; if (M == 2) { if ((pucch_payload[0] == 1) && (pucch_payload[1] == 1)) // b[0],b[1] nb_ACK = 1; else if ((pucch_payload[0] == 1) && (pucch_payload[1] == 0)) nb_ACK = 2; } else if (M == 3) { if ((pucch_payload[0] == 1) && (pucch_payload[1] == 1)) nb_ACK = 1; else if ((pucch_payload[0] == 1) && (pucch_payload[1] == 0)) nb_ACK = 2; else if ((pucch_payload[0] == 0) && (pucch_payload[1] == 1)) nb_ACK = 3; } } else if (pucch_sel == 2) { // bundling or M=1 dlsch_ACK[0] = pucch_payload[0]; dlsch_ACK[1] = pucch_payload[0]; } else { // multiplexing with no SR, this is table 10.1 if (M==1) dlsch_ACK[0] = pucch_payload[0]; else if (M==2) { if (((pucch_sel == 1) && (pucch_payload[0] == 1) && (pucch_payload[1] == 1)) || ((pucch_sel == 0) && (pucch_payload[0] == 0) && (pucch_payload[1] == 1))) dlsch_ACK[0] = 1; else dlsch_ACK[0] = 0; if (((pucch_sel == 1) && (pucch_payload[0] == 1) && (pucch_payload[1] == 1)) || ((pucch_sel == 1) && (pucch_payload[0] == 0) && (pucch_payload[1] == 0))) dlsch_ACK[1] = 1; else dlsch_ACK[1] = 0; } } } } // handle case where positive SR was transmitted with multiplexing if ((SR_payload == 1)&&(pucch_sel!=2)&&(pusch_flag == 0)) { nb_alloc = 0; for (m=0; m<M; m++) { dl_subframe = ul_ACK_subframe2_dl_subframe(fp, subframe, m); if (dlsch->subframe_tx[dl_subframe]==1) nb_alloc++; } if (nb_alloc == nb_ACK) all_ACKed = 1; else all_ACKed = 0; } for (m=0,mp=-1; m<M; m++) { dl_subframe = ul_ACK_subframe2_dl_subframe(fp, subframe, m); if (dlsch->subframe_tx[dl_subframe]==1) { if (pusch_flag == 1) mp++; else mp = m; dl_harq_pid[m] = dlsch->harq_ids[dl_subframe]; if ((pucch_sel != 2)&&(pusch_flag == 0)) { // multiplexing if ((SR_payload == 1)&&(all_ACKed == 1)) dlsch_ACK[m] = 1; else dlsch_ACK[m] = 0; } if (dl_harq_pid[m]<dlsch->Mdlharq) { dlsch_harq_proc = dlsch->harq_processes[dl_harq_pid[m]]; #ifdef DEBUG_PHY_PROC LOG_D(PHY,"[eNB %d][PDSCH %x/%d] subframe %d, status %d, round %d (mcs %d, rv %d, TBS %d)\n",eNB->Mod_id, dlsch->rnti,dl_harq_pid[m],dl_subframe, dlsch_harq_proc->status,dlsch_harq_proc->round, dlsch->harq_processes[dl_harq_pid[m]]->mcs, dlsch->harq_processes[dl_harq_pid[m]]->rvidx, dlsch->harq_processes[dl_harq_pid[m]]->TBS); if (dlsch_harq_proc->status==DISABLED) LOG_E(PHY,"dlsch_harq_proc is disabled? \n"); #endif if ((dl_harq_pid[m]<dlsch->Mdlharq) && (dlsch_harq_proc->status == ACTIVE)) { // dl_harq_pid of DLSCH is still active if ( dlsch_ACK[mp]==0) { // Received NAK #ifdef DEBUG_PHY_PROC LOG_D(PHY,"[eNB %d][PDSCH %x/%d] M = %d, m= %d, mp=%d NAK Received in round %d, requesting retransmission\n",eNB->Mod_id, dlsch->rnti,dl_harq_pid[m],M,m,mp,dlsch_harq_proc->round); #endif T(T_ENB_PHY_DLSCH_UE_NACK, T_INT(phy_vars_eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(UE_id), T_INT(dlsch->rnti), T_INT(dl_harq_pid[m])); if (dlsch_harq_proc->round == 0) ue_stats->dlsch_NAK_round0++; ue_stats->dlsch_NAK[dl_harq_pid[m]][dlsch_harq_proc->round]++; // then Increment DLSCH round index dlsch_harq_proc->round++; if (dlsch_harq_proc->round == dlsch->Mlimit) { // This was the last round for DLSCH so reset round and increment l2_error counter #ifdef DEBUG_PHY_PROC LOG_W(PHY,"[eNB %d][PDSCH %x/%d] DLSCH retransmissions exhausted, dropping packet\n",eNB->Mod_id, dlsch->rnti,dl_harq_pid[m]); #endif #if defined(MESSAGE_CHART_GENERATOR_PHY) MSC_LOG_EVENT(MSC_PHY_ENB, "0 HARQ DLSCH Failed RNTI %"PRIx16" round %u", dlsch->rnti, dlsch_harq_proc->round); #endif dlsch_harq_proc->round = 0; ue_stats->dlsch_l2_errors[dl_harq_pid[m]]++; dlsch_harq_proc->status = SCH_IDLE; put_harq_pid_in_freelist(dlsch, dl_harq_pid[m]); dlsch->harq_ids[dl_subframe] = dlsch->Mdlharq; } } else { #ifdef DEBUG_PHY_PROC LOG_D(PHY,"[eNB %d][PDSCH %x/%d] ACK Received in round %d, resetting process\n",eNB->Mod_id, dlsch->rnti,dl_harq_pid[m],dlsch_harq_proc->round); #endif T(T_ENB_PHY_DLSCH_UE_ACK, T_INT(phy_vars_eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(UE_id), T_INT(dlsch->rnti), T_INT(dl_harq_pid[m])); ue_stats->dlsch_ACK[dl_harq_pid[m]][dlsch_harq_proc->round]++; // Received ACK so set round to 0 and set dlsch_harq_pid IDLE dlsch_harq_proc->round = 0; dlsch_harq_proc->status = SCH_IDLE; put_harq_pid_in_freelist(dlsch, dl_harq_pid[m]); dlsch->harq_ids[dl_subframe] = dlsch->Mdlharq; ue_stats->total_TBS = ue_stats->total_TBS + eNB->dlsch[(uint8_t)UE_id][0]->harq_processes[dl_harq_pid[m]]->TBS; /* ue_stats->total_transmitted_bits = ue_stats->total_transmitted_bits + eNB->dlsch[(uint8_t)UE_id][0]->harq_processes[dl_harq_pid[m]]->TBS; */ } // Do fine-grain rate-adaptation for DLSCH if (ue_stats->dlsch_NAK_round0 > dlsch->error_threshold) { if (ue_stats->dlsch_mcs_offset == 1) ue_stats->dlsch_mcs_offset=0; else ue_stats->dlsch_mcs_offset=-1; } #ifdef DEBUG_PHY_PROC LOG_D(PHY,"[process_HARQ_feedback] Frame %d Setting round to %d for pid %d (subframe %d)\n",frame, dlsch_harq_proc->round,dl_harq_pid[m],subframe); #endif // Clear NAK stats and adjust mcs offset // after measurement window timer expires if (ue_stats->dlsch_sliding_cnt == dlsch->ra_window_size) { if ((ue_stats->dlsch_mcs_offset == 0) && (ue_stats->dlsch_NAK_round0 < 2)) ue_stats->dlsch_mcs_offset = 1; if ((ue_stats->dlsch_mcs_offset == 1) && (ue_stats->dlsch_NAK_round0 > 2)) ue_stats->dlsch_mcs_offset = 0; if ((ue_stats->dlsch_mcs_offset == 0) && (ue_stats->dlsch_NAK_round0 > 2)) ue_stats->dlsch_mcs_offset = -1; if ((ue_stats->dlsch_mcs_offset == -1) && (ue_stats->dlsch_NAK_round0 < 2)) ue_stats->dlsch_mcs_offset = 0; ue_stats->dlsch_NAK_round0 = 0; ue_stats->dlsch_sliding_cnt = 0; } } } } } } void get_n1_pucch_eNB(PHY_VARS_eNB *eNB, eNB_rxtx_proc_t *proc, uint8_t UE_id, int16_t *n1_pucch0, int16_t *n1_pucch1, int16_t *n1_pucch2, int16_t *n1_pucch3) { LTE_DL_FRAME_PARMS *frame_parms=&eNB->frame_parms; uint8_t nCCE0,nCCE1; int sf; int frame = proc->frame_rx; int subframe = proc->subframe_rx; if (frame_parms->frame_type == FDD ) { sf = (subframe<4) ? (subframe+6) : (subframe-4); if (eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[sf]>0) { *n1_pucch0 = frame_parms->pucch_config_common.n1PUCCH_AN + eNB->dlsch[(uint32_t)UE_id][0]->nCCE[sf]; *n1_pucch1 = -1; } else { *n1_pucch0 = -1; *n1_pucch1 = -1; } } else { switch (frame_parms->tdd_config) { case 1: // DL:S:UL:UL:DL:DL:S:UL:UL:DL if (subframe == 2) { // ACK subframes 5 and 6 /* if (eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[6]>0) { nCCE1 = eNB->dlsch[(uint32_t)UE_id][0]->nCCE[6]; *n1_pucch1 = get_Np(frame_parms->N_RB_DL,nCCE1,1) + nCCE1 + frame_parms->pucch_config_common.n1PUCCH_AN; } else *n1_pucch1 = -1;*/ if (eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[5]>0) { nCCE0 = eNB->dlsch[(uint32_t)UE_id][0]->nCCE[5]; *n1_pucch0 = get_Np(frame_parms->N_RB_DL,nCCE0,0) + nCCE0+ frame_parms->pucch_config_common.n1PUCCH_AN; } else *n1_pucch0 = -1; *n1_pucch1 = -1; } else if (subframe == 3) { // ACK subframe 9 if (eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[9]>0) { nCCE0 = eNB->dlsch[(uint32_t)UE_id][0]->nCCE[9]; *n1_pucch0 = get_Np(frame_parms->N_RB_DL,nCCE0,0) + nCCE0 +frame_parms->pucch_config_common.n1PUCCH_AN; } else *n1_pucch0 = -1; *n1_pucch1 = -1; } else if (subframe == 7) { // ACK subframes 0 and 1 //harq_ack[0].nCCE; //harq_ack[1].nCCE; if (eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[0]>0) { nCCE0 = eNB->dlsch[(uint32_t)UE_id][0]->nCCE[0]; *n1_pucch0 = get_Np(frame_parms->N_RB_DL,nCCE0,0) + nCCE0 + frame_parms->pucch_config_common.n1PUCCH_AN; } else *n1_pucch0 = -1; *n1_pucch1 = -1; } else if (subframe == 8) { // ACK subframes 4 //harq_ack[4].nCCE; if (eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[4]>0) { nCCE0 = eNB->dlsch[(uint32_t)UE_id][0]->nCCE[4]; *n1_pucch0 = get_Np(frame_parms->N_RB_DL,nCCE0,0) + nCCE0 + frame_parms->pucch_config_common.n1PUCCH_AN; } else *n1_pucch0 = -1; *n1_pucch1 = -1; } else { LOG_D(PHY,"[eNB %d] frame %d: phy_procedures_lte.c: get_n1pucch, illegal subframe %d for tdd_config %d\n", eNB->Mod_id, frame, subframe,frame_parms->tdd_config); return; } break; case 3: // DL:S:UL:UL:UL:DL:DL:DL:DL:DL if (subframe == 2) { // ACK subframes 5,6 and 1 (S in frame-2), forget about n-11 for the moment (S-subframe) if (eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[6]>0) { nCCE1 = eNB->dlsch[(uint32_t)UE_id][0]->nCCE[6]; *n1_pucch1 = get_Np(frame_parms->N_RB_DL,nCCE1,1) + nCCE1 + frame_parms->pucch_config_common.n1PUCCH_AN; } else *n1_pucch1 = -1; if (eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[5]>0) { nCCE0 = eNB->dlsch[(uint32_t)UE_id][0]->nCCE[5]; *n1_pucch0 = get_Np(frame_parms->N_RB_DL,nCCE0,0) + nCCE0+ frame_parms->pucch_config_common.n1PUCCH_AN; } else *n1_pucch0 = -1; } else if (subframe == 3) { // ACK subframes 7 and 8 LOG_D(PHY,"get_n1_pucch_eNB : subframe 3, subframe_tx[7] %d, subframe_tx[8] %d\n", eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[7],eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[8]); if (eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[8]>0) { nCCE1 = eNB->dlsch[(uint32_t)UE_id][0]->nCCE[8]; *n1_pucch1 = get_Np(frame_parms->N_RB_DL,nCCE1,1) + nCCE1 + frame_parms->pucch_config_common.n1PUCCH_AN; LOG_D(PHY,"nCCE1 %d, n1_pucch1 %d\n",nCCE1,*n1_pucch1); } else *n1_pucch1 = -1; if (eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[7]>0) { nCCE0 = eNB->dlsch[(uint32_t)UE_id][0]->nCCE[7]; *n1_pucch0 = get_Np(frame_parms->N_RB_DL,nCCE0,0) + nCCE0 +frame_parms->pucch_config_common.n1PUCCH_AN; LOG_D(PHY,"nCCE0 %d, n1_pucch0 %d\n",nCCE0,*n1_pucch0); } else *n1_pucch0 = -1; } else if (subframe == 4) { // ACK subframes 9 and 0 if (eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[0]>0) { nCCE1 = eNB->dlsch[(uint32_t)UE_id][0]->nCCE[0]; *n1_pucch1 = get_Np(frame_parms->N_RB_DL,nCCE1,1) + nCCE1 + frame_parms->pucch_config_common.n1PUCCH_AN; } else *n1_pucch1 = -1; if (eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[9]>0) { nCCE0 = eNB->dlsch[(uint32_t)UE_id][0]->nCCE[9]; *n1_pucch0 = get_Np(frame_parms->N_RB_DL,nCCE0,0) + nCCE0 +frame_parms->pucch_config_common.n1PUCCH_AN; } else *n1_pucch0 = -1; } else { LOG_D(PHY,"[eNB %d] Frame %d: phy_procedures_lte.c: get_n1pucch, illegal subframe %d for tdd_config %d\n", eNB->Mod_id,frame,subframe,frame_parms->tdd_config); return; } break; } // switch tdd_config // Don't handle the case M>2 *n1_pucch2 = -1; *n1_pucch3 = -1; } } void prach_procedures(PHY_VARS_eNB *eNB,uint8_t abstraction_flag) { LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; uint16_t preamble_energy_list[64],preamble_delay_list[64]; uint16_t preamble_max,preamble_energy_max; uint16_t i; int8_t UE_id; int subframe = eNB->proc.subframe_prach; int frame = eNB->proc.frame_prach; uint8_t CC_id = eNB->CC_id; memset(&preamble_energy_list[0],0,64*sizeof(uint16_t)); memset(&preamble_delay_list[0],0,64*sizeof(uint16_t)); if (abstraction_flag == 0) { LOG_D(PHY,"[eNB %d][RAPROC] Frame %d, Subframe %d : PRACH RX Signal Power : %d dBm\n",eNB->Mod_id, frame,subframe,dB_fixed(signal_energy(&eNB->common_vars.rxdata[0][0][subframe*fp->samples_per_tti],512)) - eNB->rx_total_gain_dB); rx_prach(eNB, preamble_energy_list, preamble_delay_list, frame, 0); } else { for (UE_id=0; UE_id<NB_UE_INST; UE_id++) { LOG_D(PHY,"[RAPROC] UE_id %d (%p), generate_prach %d, UE RSI %d, eNB RSI %d preamble index %d\n", UE_id,PHY_vars_UE_g[UE_id][CC_id],PHY_vars_UE_g[UE_id][CC_id]->generate_prach, PHY_vars_UE_g[UE_id][CC_id]->frame_parms.prach_config_common.rootSequenceIndex, fp->prach_config_common.rootSequenceIndex, PHY_vars_UE_g[UE_id][CC_id]->prach_PreambleIndex); if ((PHY_vars_UE_g[UE_id][CC_id]->generate_prach==1) && (PHY_vars_UE_g[UE_id][CC_id]->frame_parms.prach_config_common.rootSequenceIndex == fp->prach_config_common.rootSequenceIndex) ) { preamble_energy_list[PHY_vars_UE_g[UE_id][CC_id]->prach_PreambleIndex] = 800; preamble_delay_list[PHY_vars_UE_g[UE_id][CC_id]->prach_PreambleIndex] = 5; } } } preamble_energy_max = preamble_energy_list[0]; preamble_max = 0; for (i=1; i<64; i++) { if (preamble_energy_max < preamble_energy_list[i]) { preamble_energy_max = preamble_energy_list[i]; preamble_max = i; } } #ifdef DEBUG_PHY_PROC LOG_D(PHY,"[RAPROC] Most likely preamble %d, energy %d dB delay %d\n", preamble_max, preamble_energy_list[preamble_max], preamble_delay_list[preamble_max]); #endif if (preamble_energy_list[preamble_max] > 580) { UE_id = find_next_ue_index(eNB); if (UE_id>=0) { eNB->UE_stats[(uint32_t)UE_id].UE_timing_offset = preamble_delay_list[preamble_max]&0x1FFF; //limit to 13 (=11+2) bits eNB->UE_stats[(uint32_t)UE_id].sector = 0; LOG_D(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure (UE_id %d) with preamble %d, energy %d.%d dB, delay %d\n", eNB->Mod_id, eNB->CC_id, frame, subframe, UE_id, preamble_max, preamble_energy_max/10, preamble_energy_max%10, preamble_delay_list[preamble_max]); if (eNB->mac_enabled==1) { uint8_t update_TA=4; switch (fp->N_RB_DL) { case 6: update_TA = 16; break; case 25: update_TA = 4; break; case 50: update_TA = 2; break; case 100: update_TA = 1; break; } mac_xface->initiate_ra_proc(eNB->Mod_id, eNB->CC_id, frame, preamble_max, preamble_delay_list[preamble_max]*update_TA, 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); } } } void pucch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,int UE_id,int harq_pid,const uint8_t abstraction_flag) { LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; uint8_t SR_payload = 0,*pucch_payload=NULL,pucch_payload0[2]= {0,0},pucch_payload1[2]= {0,0}; int16_t n1_pucch0,n1_pucch1,n1_pucch2,n1_pucch3; uint8_t do_SR = 0; uint8_t pucch_sel = 0; int32_t metric0=0,metric1=0,metric0_SR=0; ANFBmode_t bundling_flag; PUCCH_FMT_t format; const int subframe = proc->subframe_rx; const int frame = proc->frame_rx; if ((eNB->dlsch[UE_id][0]) && (eNB->dlsch[UE_id][0]->rnti>0) && (eNB->ulsch[UE_id]->harq_processes[harq_pid]->subframe_scheduling_flag==0)) { // check SR availability do_SR = is_SR_subframe(eNB,proc,UE_id); // do_SR = 0; // Now ACK/NAK // First check subframe_tx flag for earlier subframes get_n1_pucch_eNB(eNB, proc, UE_id, &n1_pucch0, &n1_pucch1, &n1_pucch2, &n1_pucch3); LOG_D(PHY,"[eNB %d][PDSCH %x] Frame %d, subframe %d Checking for PUCCH (%d,%d,%d,%d) SR %d\n", eNB->Mod_id,eNB->dlsch[UE_id][0]->rnti, frame,subframe, n1_pucch0,n1_pucch1,n1_pucch2,n1_pucch3,do_SR); if ((n1_pucch0==-1) && (n1_pucch1==-1) && (do_SR==0)) { // no TX PDSCH that have to be checked and no SR for this UE_id } else { // otherwise we have some PUCCH detection to do // 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; } if (do_SR == 1) { eNB->UE_stats[UE_id].sr_total++; if (abstraction_flag == 0) metric0_SR = rx_pucch(eNB, pucch_format1, UE_id, eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex, 0, // n2_pucch 0, // shortened format, should be use_srs flag, later &SR_payload, frame, subframe, PUCCH1_THRES); #ifdef PHY_ABSTRACTION else { metric0_SR = rx_pucch_emul(eNB, UE_id, pucch_format1, 0, &SR_payload); LOG_D(PHY,"[eNB %d][SR %x] Frame %d subframe %d Checking SR (UE SR %d/%d)\n",eNB->Mod_id, eNB->ulsch[UE_id]->rnti,frame,subframe,SR_payload,eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex); } #endif 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, eNB->ulsch[UE_id]->rnti,frame,subframe); eNB->UE_stats[UE_id].sr_received++; if (eNB->first_sr[UE_id] == 1) { // this is the first request for uplink after Connection Setup, so clear HARQ process 0 use for Msg4 /* is this test necessary? */ if (eNB->dlsch[UE_id][0]->harq_processes[0]->status != SCH_IDLE) put_harq_pid_in_freelist(eNB->dlsch[UE_id][0], 0); eNB->first_sr[UE_id] = 0; eNB->dlsch[UE_id][0]->harq_processes[0]->round=0; eNB->dlsch[UE_id][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[UE_id]->rnti,frame,subframe); } if (eNB->mac_enabled==1) { mac_xface->SR_indication(eNB->Mod_id, eNB->CC_id, frame, eNB->dlsch[UE_id][0]->rnti,subframe); } } }// do_SR==1 if ((n1_pucch0==-1) && (n1_pucch1==-1)) { // just check for SR } else if (fp->frame_type==FDD) { // FDD // if SR was detected, use the n1_pucch from SR, else use n1_pucch0 // n1_pucch0 = (SR_payload==1) ? eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex:n1_pucch0; LOG_D(PHY,"Demodulating PUCCH for ACK/NAK: n1_pucch0 %d (%d), SR_payload %d\n",n1_pucch0,eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex,SR_payload); if (abstraction_flag == 0) { metric0 = rx_pucch(eNB, pucch_format1a, UE_id, (uint16_t)n1_pucch0, 0, //n2_pucch 0, // shortened format pucch_payload0, frame, subframe, PUCCH1a_THRES); if (metric0 < metric0_SR) metric0=rx_pucch(eNB, pucch_format1a, UE_id, eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex, 0, //n2_pucch 0, // shortened format pucch_payload0, frame, subframe, PUCCH1a_THRES); } else { #ifdef PHY_ABSTRACTION metric0 = rx_pucch_emul(eNB,UE_id, pucch_format1a, 0, pucch_payload0, subframe); #endif } #ifdef DEBUG_PHY_PROC LOG_D(PHY,"[eNB %d][PDSCH %x] Frame %d subframe %d pucch1a (FDD) payload %d (metric %d)\n", eNB->Mod_id, eNB->dlsch[UE_id][0]->rnti, frame,subframe, pucch_payload0[0],metric0); #endif process_HARQ_feedback(UE_id,eNB,proc, 0,// pusch_flag pucch_payload0, 2, SR_payload); } // FDD else { //TDD bundling_flag = eNB->pucch_config_dedicated[UE_id].tdd_AckNackFeedbackMode; // fix later for 2 TB case and format1b if ((fp->frame_type==FDD) || (bundling_flag==bundling) || ((fp->frame_type==TDD)&&(fp->tdd_config==1)&&((subframe!=2)||(subframe!=7)))) { format = pucch_format1a; } else { format = pucch_format1b; } // 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 if (abstraction_flag == 0) metric0_SR = rx_pucch(eNB, format, UE_id, eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex, 0, //n2_pucch 0, // shortened format pucch_payload0, frame, subframe, PUCCH1a_THRES); else { #ifdef PHY_ABSTRACTION metric0 = rx_pucch_emul(eNB,UE_id, format, 0, pucch_payload0, subframe); #endif } } else { //using n1_pucch0/n1_pucch1 resources #ifdef DEBUG_PHY_PROC LOG_D(PHY,"[eNB %d][PDSCH %x] Frame %d subframe %d Checking ACK/NAK (%d,%d,%d,%d) format %d\n",eNB->Mod_id, eNB->dlsch[UE_id][0]->rnti, frame,subframe, n1_pucch0,n1_pucch1,n1_pucch2,n1_pucch3,format); #endif metric0=0; metric1=0; // Check n1_pucch0 metric if (n1_pucch0 != -1) { if (abstraction_flag == 0) metric0 = rx_pucch(eNB, format, UE_id, (uint16_t)n1_pucch0, 0, // n2_pucch 0, // shortened format pucch_payload0, frame, subframe, PUCCH1a_THRES); else { #ifdef PHY_ABSTRACTION metric0 = rx_pucch_emul(eNB,UE_id, format, 0, pucch_payload0, subframe); #endif } } // Check n1_pucch1 metric if (n1_pucch1 != -1) { if (abstraction_flag == 0) metric1 = rx_pucch(eNB, format, UE_id, (uint16_t)n1_pucch1, 0, //n2_pucch 0, // shortened format pucch_payload1, frame, subframe, PUCCH1a_THRES); else { #ifdef PHY_ABSTRACTION metric1 = rx_pucch_emul(eNB,UE_id, format, 1, pucch_payload1, subframe); #endif } } } if (SR_payload == 1) { pucch_payload = pucch_payload0; if (bundling_flag == bundling) pucch_sel = 2; } else if (bundling_flag == multiplexing) { // multiplexing + no SR pucch_payload = (metric1>metric0) ? pucch_payload1 : pucch_payload0; pucch_sel = (metric1>metric0) ? 1 : 0; } else { // bundling + no SR if (n1_pucch1 != -1) pucch_payload = pucch_payload1; else if (n1_pucch0 != -1) pucch_payload = pucch_payload0; pucch_sel = 2; // indicate that this is a bundled ACK/NAK } #ifdef DEBUG_PHY_PROC LOG_D(PHY,"[eNB %d][PDSCH %x] Frame %d subframe %d ACK/NAK metric 0 %d, metric 1 %d, sel %d, (%d,%d)\n",eNB->Mod_id, eNB->dlsch[UE_id][0]->rnti, frame,subframe, metric0,metric1,pucch_sel,pucch_payload[0],pucch_payload[1]); #endif process_HARQ_feedback(UE_id,eNB,proc, 0,// pusch_flag pucch_payload, pucch_sel, SR_payload); } } } } void cba_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,int UE_id,int harq_pid,const uint8_t abstraction_flag) { uint8_t access_mode; int num_active_cba_groups; const int subframe = proc->subframe_rx; const int frame = proc->frame_rx; uint16_t rnti=0; int ret=0; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; num_active_cba_groups = eNB->ulsch[UE_id]->num_active_cba_groups; if ((eNB->ulsch[UE_id]) && (num_active_cba_groups > 0) && (eNB->ulsch[UE_id]->cba_rnti[UE_id%num_active_cba_groups]>0) && (eNB->ulsch[UE_id]->harq_processes[harq_pid]->subframe_cba_scheduling_flag==1)) { rnti=0; #ifdef DEBUG_PHY_PROC LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d Checking PUSCH/ULSCH CBA Reception for UE %d with cba rnti %x mode %s\n", eNB->Mod_id,harq_pid, frame,subframe, UE_id, (uint16_t)eNB->ulsch[UE_id]->cba_rnti[UE_id%num_active_cba_groups],mode_string[eNB->UE_stats[UE_id].mode]); #endif if (abstraction_flag==0) { rx_ulsch(eNB,proc, eNB->UE_stats[UE_id].sector, // this is the effective sector id UE_id, eNB->ulsch, 0); } #ifdef PHY_ABSTRACTION else { rx_ulsch_emul(eNB,proc, subframe, eNB->UE_stats[UE_id].sector, // this is the effective sector id UE_id); } #endif if (abstraction_flag == 0) { ret = ulsch_decoding(eNB,proc, UE_id, 0, // control_only_flag eNB->ulsch[UE_id]->harq_processes[harq_pid]->V_UL_DAI, eNB->ulsch[UE_id]->harq_processes[harq_pid]->nb_rb>20 ? 1 : 0); } #ifdef PHY_ABSTRACTION else { ret = ulsch_decoding_emul(eNB, UE_id, &rnti); } #endif if (eNB->ulsch[UE_id]->harq_processes[harq_pid]->cqi_crc_status == 1) { #ifdef DEBUG_PHY_PROC print_CQI(eNB->ulsch[UE_id]->harq_processes[harq_pid]->o,eNB->ulsch[UE_id]->harq_processes[harq_pid]->uci_format,0,fp->N_RB_DL); #endif access_mode = UNKNOWN_ACCESS; extract_CQI(eNB->ulsch[UE_id]->harq_processes[harq_pid]->o, eNB->ulsch[UE_id]->harq_processes[harq_pid]->uci_format, &eNB->UE_stats[UE_id], fp->N_RB_DL, &rnti, &access_mode); eNB->UE_stats[UE_id].rank = eNB->ulsch[UE_id]->harq_processes[harq_pid]->o_RI[0]; } eNB->ulsch[UE_id]->harq_processes[harq_pid]->subframe_cba_scheduling_flag=0; eNB->ulsch[UE_id]->harq_processes[harq_pid]->status= SCH_IDLE; if ((num_active_cba_groups > 0) && (UE_id + num_active_cba_groups < NUMBER_OF_UE_MAX) && (eNB->ulsch[UE_id+num_active_cba_groups]->cba_rnti[UE_id%num_active_cba_groups] > 0 ) && (eNB->ulsch[UE_id+num_active_cba_groups]->num_active_cba_groups> 0)) { #ifdef DEBUG_PHY_PROC LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d UE %d harq_pid %d resetting the subframe_scheduling_flag for Ue %d cba groups %d members\n", eNB->Mod_id,harq_pid,frame,subframe,UE_id,harq_pid, UE_id+num_active_cba_groups, UE_id%eNB->ulsch[UE_id]->num_active_cba_groups); #endif eNB->ulsch[UE_id+num_active_cba_groups]->harq_processes[harq_pid]->subframe_cba_scheduling_flag=1; eNB->ulsch[UE_id+num_active_cba_groups]->harq_processes[harq_pid]->status= CBA_ACTIVE; eNB->ulsch[UE_id+num_active_cba_groups]->harq_processes[harq_pid]->TBS=eNB->ulsch[UE_id]->harq_processes[harq_pid]->TBS; } if (ret == (1+MAX_TURBO_ITERATIONS)) { eNB->UE_stats[UE_id].ulsch_round_errors[harq_pid][eNB->ulsch[UE_id]->harq_processes[harq_pid]->round]++; eNB->ulsch[UE_id]->harq_processes[harq_pid]->phich_active = 1; eNB->ulsch[UE_id]->harq_processes[harq_pid]->phich_ACK = 0; eNB->ulsch[UE_id]->harq_processes[harq_pid]->round++; } // ulsch in error else { LOG_D(PHY,"[eNB %d][PUSCH %d] Frame %d subframe %d ULSCH received, setting round to 0, PHICH ACK\n", eNB->Mod_id,harq_pid, frame,subframe); eNB->ulsch[UE_id]->harq_processes[harq_pid]->phich_active = 1; eNB->ulsch[UE_id]->harq_processes[harq_pid]->phich_ACK = 1; eNB->ulsch[UE_id]->harq_processes[harq_pid]->round = 0; eNB->UE_stats[UE_id].ulsch_consecutive_errors = 0; #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,eNB->ulsch[UE_id]->harq_processes[harq_pid]->TBS>>3); for (j=0; j<eNB->ulsch[UE_id]->harq_processes[harq_pid]->TBS>>3; j++) LOG_T(PHY,"%x.",eNB->ulsch[UE_id]->harq_processes[harq_pid]->b[j]); LOG_T(PHY,"\n"); #endif #endif if (access_mode > UNKNOWN_ACCESS) { LOG_D(PHY,"[eNB %d] Frame %d, Subframe %d : received ULSCH SDU from CBA transmission, UE (%d,%x), CBA (group %d, rnti %x)\n", eNB->Mod_id, frame,subframe, UE_id, eNB->ulsch[UE_id]->rnti, UE_id % eNB->ulsch[UE_id]->num_active_cba_groups, eNB->ulsch[UE_id]->cba_rnti[UE_id%num_active_cba_groups]); // detect if there is a CBA collision if (eNB->cba_last_reception[UE_id%num_active_cba_groups] == 0 ) { mac_xface->rx_sdu(eNB->Mod_id, eNB->CC_id, frame,subframe, eNB->ulsch[UE_id]->rnti, eNB->ulsch[UE_id]->harq_processes[harq_pid]->b, eNB->ulsch[UE_id]->harq_processes[harq_pid]->TBS>>3, harq_pid, NULL); eNB->cba_last_reception[UE_id%num_active_cba_groups]+=1;//(subframe); } else { if (eNB->cba_last_reception[UE_id%num_active_cba_groups] == 1 ) LOG_N(PHY,"[eNB%d] Frame %d subframe %d : first CBA collision detected \n ", eNB->Mod_id,frame,subframe); LOG_N(PHY,"[eNB%d] Frame %d subframe %d : CBA collision set SR for UE %d in group %d \n ", eNB->Mod_id,frame,subframe, eNB->cba_last_reception[UE_id%num_active_cba_groups],UE_id%num_active_cba_groups ); eNB->cba_last_reception[UE_id%num_active_cba_groups]+=1; mac_xface->SR_indication(eNB->Mod_id, eNB->CC_id, frame, eNB->dlsch[UE_id][0]->rnti,subframe); } } // UNKNOWN_ACCESS } // ULSCH CBA not in error } } void phy_procedures_eNB_common_RX(PHY_VARS_eNB *eNB,const uint8_t abstraction_flag) { int i,l; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; void *rxp[fp->nb_antennas_rx]; unsigned int rxs; eNB_proc_t *proc = &eNB->proc; int subframe = proc->subframe_rx; int frame = proc->frame_rx; int prach_rx; uint16_t packet_type; uint32_t symbol_number; uint32_t symbol_mask, symbol_mask_full; struct timespec time_req, time_rem; time_req.tv_sec = 0; time_req.tv_nsec = 300000; if (subframe==9) { subframe=0; frame++; frame&=1023; } else { subframe++; } // VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_COMMON_RX,1); start_meas(&eNB->phy_proc_rx); #ifdef DEBUG_PHY_PROC LOG_D(PHY,"[eNB %d] Frame %d: Doing phy_procedures_eNB_RX(%d)\n",eNB->Mod_id,frame, subframe); #endif if (abstraction_flag==0) { // grab signal in chunks of 500 us (1 slot) if ((eNB->node_function == NGFI_RRU_IF4) || (eNB->node_function == eNodeB_3GPP)) { // acquisition from RF and front-end processing for (i=0; i<fp->nb_antennas_rx; i++) rxp[i] = (void*)&eNB->common_vars.rxdata[0][i][subframe*fp->samples_per_tti]; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 ); rxs = eNB->rfdevice.trx_read_func(&eNB->rfdevice, &proc->timestamp_rx, rxp, fp->samples_per_tti, fp->nb_antennas_rx); proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_tti*10))&1023; proc->subframe_rx = (proc->timestamp_rx / fp->samples_per_tti)%10; if (proc->first_rx == 0) { AssertFatal(proc->subframe_rx == subframe, "Received Timestamp doesn't correspond to the time we think it is (proc->subframe_rx %d, subframe %d)",proc->subframe_rx,subframe); AssertFatal(proc->frame_rx == frame, "Received Timestamp doesn't correspond to the time we think it is (proc->frame_rx %d frame %d)",proc->frame_rx,frame); } else { proc->first_rx = 0; } //printf("timestamp_rx %lu, frame %d(%d), subframe %d(%d)\n",proc->timestamp_rx,proc->frame_rx,frame,proc->subframe_rx,subframe); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff ); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX_ENB, frame ); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX_ENB, subframe ); if (rxs != fp->samples_per_tti) exit_fun( "problem receiving samples" ); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 ); // now do common RX processing for first slot in subframe VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_SLOT_FEP,1); remove_7_5_kHz(eNB,subframe<<1); remove_7_5_kHz(eNB,1+(subframe<<1)); for (l=0; l<fp->symbols_per_tti/2; l++) { slot_fep_ul(fp, &eNB->common_vars, l, subframe<<1, 0, 0 ); slot_fep_ul(fp, &eNB->common_vars, l, 1+(subframe<<1), 0, 0 ); } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_SLOT_FEP,0); if (eNB->node_function == NGFI_RRU_IF4 && is_prach_subframe(fp, frame, subframe)<=0) { /// **** send_IF4 of rxdataF to RCC (no prach now) **** /// VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF4, 1 ); //send_IF4(eNB, frame, subframe, IF4_PULFFT); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF4, 0 ); } /// **** send_IF4 of prach to RCC **** /// done in prach thread (below) // check if we have to detect PRACH first if (is_prach_subframe(fp,frame,subframe)>0) { // wake up thread for PRACH RX if (pthread_mutex_lock(&proc->mutex_prach) != 0) { LOG_E( PHY, "[eNB] ERROR pthread_mutex_lock for eNB PRACH thread %d (IC %d)\n", proc->instance_cnt_prach ); exit_fun( "error locking mutex_prach" ); return; } int cnt_prach = ++proc->instance_cnt_prach; // set timing for prach thread proc->frame_prach = frame; proc->subframe_prach = subframe; pthread_mutex_unlock( &proc->mutex_prach ); if (cnt_prach == 0) { // the thread was presumably waiting where it should and can now be woken up if (pthread_cond_signal(&proc->cond_prach) != 0) { LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB PRACH thread %d\n", proc->thread_index); exit_fun( "ERROR pthread_cond_signal" ); return; } } else { LOG_W( PHY,"[eNB] Frame %d, eNB PRACH thread busy!!\n", frame); exit_fun( "PRACH thread busy" ); return; } } } else if (eNB->node_function == NGFI_RCC_IF4) { /// **** recv_IF4 of rxdataF from RRU **** /// /// **** recv_IF4 of prachF from RRU **** /// // get frame/subframe information from IF4 interface // timed loop (200 us) symbol_mask = 0; symbol_mask_full = (1<<fp->symbols_per_tti)-1; prach_rx = 0; // Block from loop while testing symbol_mask = symbol_mask_full; nanosleep(&time_req, &time_rem); do { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_RECV_IF4, 1 ); //recv_IF4(eNB, frame, subframe, &packet_type, &symbol_number); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_RECV_IF4, 0 ); if (packet_type == IF4_PULFFT) { symbol_mask = symbol_mask | (1<<symbol_number); } else if (is_prach_subframe(fp,frame,subframe)>0 && packet_type == PRACH) { // wake up thread for PRACH RX prach_rx = 1; if (pthread_mutex_lock(&proc->mutex_prach) != 0) { LOG_E( PHY, "[eNB] ERROR pthread_mutex_lock for eNB PRACH thread %d (IC %d)\n", proc->instance_cnt_prach ); exit_fun( "error locking mutex_prach" ); return; } int cnt_prach = ++proc->instance_cnt_prach; // set timing for prach thread proc->frame_prach = frame; proc->subframe_prach = subframe; pthread_mutex_unlock( &proc->mutex_prach ); if (cnt_prach == 0) { // the thread was presumably waiting where it should and can now be woken up if (pthread_cond_signal(&proc->cond_prach) != 0) { LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB PRACH thread %d\n", proc->thread_index); exit_fun( "ERROR pthread_cond_signal" ); return; } } else { LOG_W( PHY,"[eNB] Frame %d, eNB PRACH thread busy!!\n", frame); exit_fun( "PRACH thread busy" ); return; } } } while( (symbol_mask != symbol_mask_full) && (prach_rx == 0)); // Tobi aka mr monaco: ETH } else { // should not get here AssertFatal(1==0, "Unknown eNB->node_function %d",eNB->node_function); } } else { // grab transport channel information from network interface } } void phy_procedures_eNB_uespec_RX(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,const uint8_t abstraction_flag,const relaying_type_t r_type) { //RX processing for ue-specific resources (i UNUSED(r_type); uint32_t ret=0,i,j,k; uint32_t harq_pid, harq_idx, round; uint8_t nPRS; int sync_pos; uint16_t rnti=0; uint8_t access_mode; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; const int subframe = proc->subframe_rx; const int frame = proc->frame_rx; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX,1); start_meas(&eNB->phy_proc_rx); #ifdef DEBUG_PHY_PROC LOG_D(PHY,"[eNB %d] Frame %d: Doing phy_procedures_eNB_RX(%d)\n",eNB->Mod_id,frame, subframe); #endif T(T_ENB_PHY_UL_TICK, T_INT(phy_vars_eNB->Mod_id), T_INT(frame), T_INT(subframe)); T(T_ENB_PHY_INPUT_SIGNAL, T_INT(phy_vars_eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(0), T_BUFFER(&phy_vars_eNB->lte_eNB_common_vars.rxdata[0][0][subframe*phy_vars_eNB->lte_frame_parms.samples_per_tti], phy_vars_eNB->lte_frame_parms.samples_per_tti * 4)); eNB->rb_mask_ul[0]=0; eNB->rb_mask_ul[1]=0; eNB->rb_mask_ul[2]=0; eNB->rb_mask_ul[3]=0; // Check for active processes in current subframe harq_pid = subframe2harq_pid(fp, frame,subframe); // reset the cba flag used for collision detection for (i=0; i < NUM_MAX_CBA_GROUP; i++) { eNB->cba_last_reception[i]=0; } // Do PUCCH processing first for (i=0; i<NUMBER_OF_UE_MAX; i++) { pucch_procedures(eNB,proc,i,harq_pid,abstraction_flag); } for (i=0; i<NUMBER_OF_UE_MAX; i++) { // check for Msg3 if (eNB->mac_enabled==1) { if (eNB->UE_stats[i].mode == RA_RESPONSE) { process_Msg3(eNB,proc,i,harq_pid); } } eNB->pusch_stats_rb[i][(frame*10)+subframe] = -63; eNB->pusch_stats_round[i][(frame*10)+subframe] = 0; eNB->pusch_stats_mcs[i][(frame*10)+subframe] = -63; if ((eNB->ulsch[i]) && (eNB->ulsch[i]->rnti>0) && (eNB->ulsch[i]->harq_processes[harq_pid]->subframe_scheduling_flag==1)) { // UE is has ULSCH scheduling round = eNB->ulsch[i]->harq_processes[harq_pid]->round; for (int rb=0; rb<=eNB->ulsch[i]->harq_processes[harq_pid]->nb_rb; rb++) { int rb2 = rb+eNB->ulsch[i]->harq_processes[harq_pid]->first_rb; eNB->rb_mask_ul[rb2>>5] |= (1<<(rb2&31)); } if (eNB->ulsch[i]->Msg3_flag == 1) { LOG_D(PHY,"[eNB %d] frame %d, subframe %d: Scheduling ULSCH Reception for Msg3 in Sector %d\n", eNB->Mod_id, frame, subframe, eNB->UE_stats[i].sector); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_ULSCH_MSG3,1); } else { LOG_D(PHY,"[eNB %d] frame %d, subframe %d: Scheduling ULSCH Reception for UE %d Mode %s\n", eNB->Mod_id, frame, subframe, i, mode_string[eNB->UE_stats[i].mode]); } nPRS = fp->pusch_config_common.ul_ReferenceSignalsPUSCH.nPRS[subframe<<1]; eNB->ulsch[i]->cyclicShift = (eNB->ulsch[i]->harq_processes[harq_pid]->n_DMRS2 + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift + nPRS)%12; if (fp->frame_type == FDD ) { int sf = (subframe<4) ? (subframe+6) : (subframe-4); if (eNB->dlsch[i][0]->subframe_tx[sf]>0) { // we have downlink transmission eNB->ulsch[i]->harq_processes[harq_pid]->O_ACK = 1; } else { eNB->ulsch[i]->harq_processes[harq_pid]->O_ACK = 0; } } 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, mcs %d, TBS %d, rv %d, cyclic_shift %d (n_DMRS2 %d, cyclicShift_common %d, nprs %d), O_ACK %d \n", eNB->Mod_id,harq_pid,frame,subframe, eNB->ulsch[i]->harq_processes[harq_pid]->dci_alloc, eNB->ulsch[i]->harq_processes[harq_pid]->rar_alloc, eNB->ulsch[i]->harq_processes[harq_pid]->round, eNB->ulsch[i]->harq_processes[harq_pid]->first_rb, eNB->ulsch[i]->harq_processes[harq_pid]->nb_rb, eNB->ulsch[i]->harq_processes[harq_pid]->mcs, eNB->ulsch[i]->harq_processes[harq_pid]->TBS, eNB->ulsch[i]->harq_processes[harq_pid]->rvidx, eNB->ulsch[i]->cyclicShift, eNB->ulsch[i]->harq_processes[harq_pid]->n_DMRS2, fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift, nPRS, eNB->ulsch[i]->harq_processes[harq_pid]->O_ACK); eNB->pusch_stats_rb[i][(frame*10)+subframe] = eNB->ulsch[i]->harq_processes[harq_pid]->nb_rb; eNB->pusch_stats_round[i][(frame*10)+subframe] = eNB->ulsch[i]->harq_processes[harq_pid]->round; eNB->pusch_stats_mcs[i][(frame*10)+subframe] = eNB->ulsch[i]->harq_processes[harq_pid]->mcs; start_meas(&eNB->ulsch_demodulation_stats); if (abstraction_flag==0) { rx_ulsch(eNB,proc, eNB->UE_stats[i].sector, // this is the effective sector id i, eNB->ulsch, 0); } #ifdef PHY_ABSTRACTION else { rx_ulsch_emul(eNB,proc, subframe, eNB->UE_stats[i].sector, // this is the effective sector id i); } #endif stop_meas(&eNB->ulsch_demodulation_stats); start_meas(&eNB->ulsch_decoding_stats); if (abstraction_flag == 0) { ret = ulsch_decoding(eNB,proc, i, 0, // control_only_flag eNB->ulsch[i]->harq_processes[harq_pid]->V_UL_DAI, eNB->ulsch[i]->harq_processes[harq_pid]->nb_rb>20 ? 1 : 0); } #ifdef PHY_ABSTRACTION else { ret = ulsch_decoding_emul(eNB,proc, i, &rnti); } #endif stop_meas(&eNB->ulsch_decoding_stats); LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d RNTI %x RX power (%d,%d) RSSI (%d,%d) N0 (%d,%d) dB ACK (%d,%d), decoding iter %d\n", eNB->Mod_id,harq_pid, frame,subframe, eNB->ulsch[i]->rnti, dB_fixed(eNB->pusch_vars[i]->ulsch_power[0]), dB_fixed(eNB->pusch_vars[i]->ulsch_power[1]), eNB->UE_stats[i].UL_rssi[0], eNB->UE_stats[i].UL_rssi[1], eNB->measurements->n0_power_dB[0], eNB->measurements->n0_power_dB[1], eNB->ulsch[i]->harq_processes[harq_pid]->o_ACK[0], eNB->ulsch[i]->harq_processes[harq_pid]->o_ACK[1], ret); //compute the expected ULSCH RX power (for the stats) eNB->ulsch[(uint32_t)i]->harq_processes[harq_pid]->delta_TF = get_hundred_times_delta_IF_eNB(eNB,i,harq_pid, 0); // 0 means bw_factor is not considered eNB->UE_stats[i].ulsch_decoding_attempts[harq_pid][eNB->ulsch[i]->harq_processes[harq_pid]->round]++; #ifdef DEBUG_PHY_PROC LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d UE %d harq_pid %d Clearing subframe_scheduling_flag\n", eNB->Mod_id,harq_pid,frame,subframe,i,harq_pid); #endif eNB->ulsch[i]->harq_processes[harq_pid]->subframe_scheduling_flag=0; if (eNB->ulsch[i]->harq_processes[harq_pid]->cqi_crc_status == 1) { #ifdef DEBUG_PHY_PROC //if (((frame%10) == 0) || (frame < 50)) print_CQI(eNB->ulsch[i]->harq_processes[harq_pid]->o,eNB->ulsch[i]->harq_processes[harq_pid]->uci_format,0,fp->N_RB_DL); #endif extract_CQI(eNB->ulsch[i]->harq_processes[harq_pid]->o, eNB->ulsch[i]->harq_processes[harq_pid]->uci_format, &eNB->UE_stats[i], fp->N_RB_DL, &rnti, &access_mode); eNB->UE_stats[i].rank = eNB->ulsch[i]->harq_processes[harq_pid]->o_RI[0]; } if (eNB->ulsch[i]->Msg3_flag == 1) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_ULSCH_MSG3,0); if (ret == (1+MAX_TURBO_ITERATIONS)) { T(T_ENB_PHY_ULSCH_UE_NACK, T_INT(phy_vars_eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(i), T_INT(phy_vars_eNB->ulsch_eNB[i]->rnti), T_INT(harq_pid)); eNB->UE_stats[i].ulsch_round_errors[harq_pid][eNB->ulsch[i]->harq_processes[harq_pid]->round]++; eNB->ulsch[i]->harq_processes[harq_pid]->phich_active = 1; eNB->ulsch[i]->harq_processes[harq_pid]->phich_ACK = 0; eNB->ulsch[i]->harq_processes[harq_pid]->round++; LOG_D(PHY,"[eNB][PUSCH %d] Increasing to round %d\n",harq_pid,eNB->ulsch[i]->harq_processes[harq_pid]->round); if (eNB->ulsch[i]->Msg3_flag == 1) { LOG_D(PHY,"[eNB %d/%d][RAPROC] frame %d, subframe %d, UE %d: Error receiving ULSCH (Msg3), round %d/%d\n", eNB->Mod_id, eNB->CC_id, frame,subframe, i, eNB->ulsch[i]->harq_processes[harq_pid]->round-1, fp->maxHARQ_Msg3Tx-1); LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d RNTI %x RX power (%d,%d) RSSI (%d,%d) N0 (%d,%d) dB ACK (%d,%d), decoding iter %d\n", eNB->Mod_id,harq_pid, frame,subframe, eNB->ulsch[i]->rnti, dB_fixed(eNB->pusch_vars[i]->ulsch_power[0]), dB_fixed(eNB->pusch_vars[i]->ulsch_power[1]), eNB->UE_stats[i].UL_rssi[0], eNB->UE_stats[i].UL_rssi[1], eNB->measurements->n0_power_dB[0], eNB->measurements->n0_power_dB[1], eNB->ulsch[i]->harq_processes[harq_pid]->o_ACK[0], eNB->ulsch[i]->harq_processes[harq_pid]->o_ACK[1], ret); if (eNB->ulsch[i]->harq_processes[harq_pid]->round == fp->maxHARQ_Msg3Tx) { LOG_D(PHY,"[eNB %d][RAPROC] maxHARQ_Msg3Tx reached, abandoning RA procedure for UE %d\n", eNB->Mod_id, i); eNB->UE_stats[i].mode = PRACH; if (eNB->mac_enabled==1) { mac_xface->cancel_ra_proc(eNB->Mod_id, eNB->CC_id, frame, eNB->UE_stats[i].crnti); } mac_phy_remove_ue(eNB->Mod_id,eNB->UE_stats[i].crnti); eNB->ulsch[(uint32_t)i]->Msg3_active = 0; //eNB->ulsch[i]->harq_processes[harq_pid]->phich_active = 0; } else { // activate retransmission for Msg3 (signalled to UE PHY by PHICH (not MAC/DCI) eNB->ulsch[(uint32_t)i]->Msg3_active = 1; get_Msg3_alloc_ret(fp, subframe, frame, &eNB->ulsch[i]->Msg3_frame, &eNB->ulsch[i]->Msg3_subframe); } LOG_D(PHY,"[eNB] Frame %d, Subframe %d: Msg3 in error, i = %d \n", frame,subframe,i); } // This is Msg3 error else { //normal ULSCH 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, eNB->ulsch[i]->harq_processes[harq_pid]->round-1, eNB->ulsch[i]->Mlimit, eNB->ulsch[i]->harq_processes[harq_pid]->o_ACK[0], eNB->ulsch[i]->harq_processes[harq_pid]->o_ACK[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, eNB->ulsch[i]->rnti,harq_pid, eNB->ulsch[i]->harq_processes[harq_pid]->round-1 ); #endif if (eNB->ulsch[i]->harq_processes[harq_pid]->round== eNB->ulsch[i]->Mlimit) { LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d UE %d ULSCH Mlimit %d reached\n", eNB->Mod_id,harq_pid, frame,subframe, i, eNB->ulsch[i]->Mlimit); eNB->ulsch[i]->harq_processes[harq_pid]->round=0; eNB->ulsch[i]->harq_processes[harq_pid]->phich_active=0; eNB->UE_stats[i].ulsch_errors[harq_pid]++; eNB->UE_stats[i].ulsch_consecutive_errors++; // indicate error to MAC mac_xface->rx_sdu(eNB->Mod_id, eNB->CC_id, frame,subframe, eNB->ulsch[i]->rnti, NULL, 0, harq_pid, &eNB->ulsch[i]->Msg3_flag); } } } // ulsch in error else { T(T_ENB_PHY_ULSCH_UE_ACK, T_INT(phy_vars_eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(i), T_INT(phy_vars_eNB->ulsch_eNB[i]->rnti), T_INT(harq_pid)); if (eNB->ulsch[i]->Msg3_flag == 1) { LOG_D(PHY,"[eNB %d][PUSCH %d] Frame %d subframe %d ULSCH received, setting round to 0, PHICH ACK\n", eNB->Mod_id,harq_pid, frame,subframe); LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d RNTI %x RX power (%d,%d) RSSI (%d,%d) N0 (%d,%d) dB ACK (%d,%d), decoding iter %d\n", eNB->Mod_id,harq_pid, frame,subframe, eNB->ulsch[i]->rnti, dB_fixed(eNB->pusch_vars[i]->ulsch_power[0]), dB_fixed(eNB->pusch_vars[i]->ulsch_power[1]), eNB->UE_stats[i].UL_rssi[0], eNB->UE_stats[i].UL_rssi[1], eNB->measurements->n0_power_dB[0], eNB->measurements->n0_power_dB[1], eNB->ulsch[i]->harq_processes[harq_pid]->o_ACK[0], eNB->ulsch[i]->harq_processes[harq_pid]->o_ACK[1], ret); } #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, eNB->ulsch[i]->rnti,harq_pid ); #endif for (j=0; j<fp->nb_antennas_rx; j++) //this is the RSSI per RB eNB->UE_stats[i].UL_rssi[j] = dB_fixed(eNB->pusch_vars[i]->ulsch_power[j]* (eNB->ulsch[i]->harq_processes[harq_pid]->nb_rb*12)/ fp->ofdm_symbol_size) - eNB->rx_total_gain_dB - hundred_times_log10_NPRB[eNB->ulsch[i]->harq_processes[harq_pid]->nb_rb-1]/100 - get_hundred_times_delta_IF_eNB(eNB,i,harq_pid, 0)/100; eNB->ulsch[i]->harq_processes[harq_pid]->phich_active = 1; eNB->ulsch[i]->harq_processes[harq_pid]->phich_ACK = 1; eNB->ulsch[i]->harq_processes[harq_pid]->round = 0; eNB->UE_stats[i].ulsch_consecutive_errors = 0; if (eNB->ulsch[i]->Msg3_flag == 1) { if (eNB->mac_enabled==1) { LOG_I(PHY,"[eNB %d][RAPROC] Frame %d Terminating ra_proc for harq %d, UE %d\n", eNB->Mod_id, frame,harq_pid,i); mac_xface->rx_sdu(eNB->Mod_id, eNB->CC_id, frame,subframe, eNB->ulsch[i]->rnti, eNB->ulsch[i]->harq_processes[harq_pid]->b, eNB->ulsch[i]->harq_processes[harq_pid]->TBS>>3, harq_pid, &eNB->ulsch[i]->Msg3_flag); // one-shot msg3 detection by MAC: empty PDU (e.g. CRNTI) if (eNB->ulsch[i]->Msg3_flag == 0 ) { eNB->UE_stats[i].mode = PRACH; mac_xface->cancel_ra_proc(eNB->Mod_id, eNB->CC_id, frame, eNB->UE_stats[i].crnti); mac_phy_remove_ue(eNB->Mod_id,eNB->UE_stats[i].crnti); eNB->ulsch[(uint32_t)i]->Msg3_active = 0; } // Msg3_flag == 0 } // mac_enabled==1 eNB->UE_stats[i].mode = PUSCH; eNB->ulsch[i]->Msg3_flag = 0; LOG_D(PHY,"[eNB %d][RAPROC] Frame %d : RX Subframe %d Setting UE %d mode to PUSCH\n",eNB->Mod_id,frame,subframe,i); for (k=0; k<8; k++) { //harq_processes for (j=0; j<eNB->dlsch[i][0]->Mlimit; j++) { eNB->UE_stats[i].dlsch_NAK[k][j]=0; eNB->UE_stats[i].dlsch_ACK[k][j]=0; eNB->UE_stats[i].dlsch_trials[k][j]=0; } eNB->UE_stats[i].dlsch_l2_errors[k]=0; eNB->UE_stats[i].ulsch_errors[k]=0; eNB->UE_stats[i].ulsch_consecutive_errors=0; for (j=0; j<eNB->ulsch[i]->Mlimit; j++) { eNB->UE_stats[i].ulsch_decoding_attempts[k][j]=0; eNB->UE_stats[i].ulsch_decoding_attempts_last[k][j]=0; eNB->UE_stats[i].ulsch_round_errors[k][j]=0; eNB->UE_stats[i].ulsch_round_fer[k][j]=0; } } eNB->UE_stats[i].dlsch_sliding_cnt=0; eNB->UE_stats[i].dlsch_NAK_round0=0; eNB->UE_stats[i].dlsch_mcs_offset=0; } // Msg3_flag==1 else { // Msg3_flag == 0 #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,eNB->ulsch[i]->harq_processes[harq_pid]->TBS>>3); for (j=0; j<eNB->ulsch[i]->harq_processes[harq_pid]->TBS>>3; j++) LOG_T(PHY,"%x.",eNB->ulsch[i]->harq_processes[harq_pid]->b[j]); LOG_T(PHY,"\n"); #endif #endif if (eNB->mac_enabled==1) { mac_xface->rx_sdu(eNB->Mod_id, eNB->CC_id, frame,subframe, eNB->ulsch[i]->rnti, eNB->ulsch[i]->harq_processes[harq_pid]->b, eNB->ulsch[i]->harq_processes[harq_pid]->TBS>>3, harq_pid, NULL); #ifdef LOCALIZATION start_meas(&eNB->localization_stats); aggregate_eNB_UE_localization_stats(eNB, i, frame, subframe, get_hundred_times_delta_IF_eNB(eNB,i,harq_pid, 1)/100); stop_meas(&eNB->localization_stats); #endif } // mac_enabled==1 } // Msg3_flag == 0 // estimate timing advance for MAC if (abstraction_flag == 0) { sync_pos = lte_est_timing_advance_pusch(eNB,i); eNB->UE_stats[i].timing_advance_update = sync_pos - fp->nb_prefix_samples/4; //to check } #ifdef DEBUG_PHY_PROC LOG_D(PHY,"[eNB %d] frame %d, subframe %d: user %d: timing advance = %d\n", eNB->Mod_id, frame, subframe, i, eNB->UE_stats[i].timing_advance_update); #endif } // ulsch not in error // process HARQ feedback #ifdef DEBUG_PHY_PROC LOG_D(PHY,"[eNB %d][PDSCH %x] Frame %d subframe %d, Processing HARQ feedback for UE %d (after PUSCH)\n",eNB->Mod_id, eNB->dlsch[i][0]->rnti, frame,subframe, i); #endif process_HARQ_feedback(i, eNB,proc, 1, // pusch_flag 0, 0, 0); #ifdef DEBUG_PHY_PROC LOG_D(PHY,"[eNB %d] Frame %d subframe %d, sect %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, eNB->UE_stats[i].sector, harq_pid, i, ret, eNB->ulsch[i]->harq_processes[harq_pid]->cqi_crc_status, eNB->ulsch[i]->harq_processes[harq_pid]->o_ACK[0], eNB->ulsch[i]->harq_processes[harq_pid]->o_ACK[1], eNB->UE_stats[i].ulsch_errors[harq_pid], eNB->UE_stats[i].ulsch_decoding_attempts[harq_pid][0]); #endif // dump stats to VCD if (i==0) { VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_MCS0+harq_pid,eNB->pusch_stats_mcs[0][(frame*10)+subframe]); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_RB0+harq_pid,eNB->pusch_stats_rb[0][(frame*10)+subframe]); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_ROUND0+harq_pid,eNB->pusch_stats_round[0][(frame*10)+subframe]); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_RSSI0+harq_pid,dB_fixed(eNB->pusch_vars[0]->ulsch_power[0])); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_RES0+harq_pid,ret); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_SFN0+harq_pid,(frame*10)+subframe); } } // ulsch[0] && ulsch[0]->rnti>0 && ulsch[0]->subframe_scheduling_flag == 1 // update ULSCH statistics for tracing if ((frame % 100 == 0) && (subframe == 4)) { for (harq_idx=0; harq_idx<8; harq_idx++) { for (round=0; round<eNB->ulsch[i]->Mlimit; round++) { if ((eNB->UE_stats[i].ulsch_decoding_attempts[harq_idx][round] - eNB->UE_stats[i].ulsch_decoding_attempts_last[harq_idx][round]) != 0) { eNB->UE_stats[i].ulsch_round_fer[harq_idx][round] = (100*(eNB->UE_stats[i].ulsch_round_errors[harq_idx][round] - eNB->UE_stats[i].ulsch_round_errors_last[harq_idx][round]))/ (eNB->UE_stats[i].ulsch_decoding_attempts[harq_idx][round] - eNB->UE_stats[i].ulsch_decoding_attempts_last[harq_idx][round]); } else { eNB->UE_stats[i].ulsch_round_fer[harq_idx][round] = 0; } eNB->UE_stats[i].ulsch_decoding_attempts_last[harq_idx][round] = eNB->UE_stats[i].ulsch_decoding_attempts[harq_idx][round]; eNB->UE_stats[i].ulsch_round_errors_last[harq_idx][round] = eNB->UE_stats[i].ulsch_round_errors[harq_idx][round]; } } } if ((frame % 100 == 0) && (subframe==4)) { eNB->UE_stats[i].dlsch_bitrate = (eNB->UE_stats[i].total_TBS - eNB->UE_stats[i].total_TBS_last); eNB->UE_stats[i].total_TBS_last = eNB->UE_stats[i].total_TBS; } // CBA (non-LTE) cba_procedures(eNB,proc,i,harq_pid,abstraction_flag); } // loop i=0 ... NUMBER_OF_UE_MAX-1 if (abstraction_flag == 0) { lte_eNB_I0_measurements(eNB, subframe, 0, eNB->first_run_I0_measurements); eNB->first_run_I0_measurements = 0; } #ifdef PHY_ABSTRACTION else { lte_eNB_I0_measurements_emul(eNB, 0); } #endif //} #ifdef EMOS phy_procedures_emos_eNB_RX(subframe,eNB); #endif VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX,0); stop_meas(&eNB->phy_proc_rx); } #undef DEBUG_PHY_PROC #ifdef Rel10 int phy_procedures_RN_eNB_TX(unsigned char last_slot, unsigned char next_slot, relaying_type_t r_type) { int do_proc=0;// do nothing switch(r_type) { case no_relay: do_proc= no_relay; // perform the normal eNB operation break; case multicast_relay: if (((next_slot >>1) < 6) || ((next_slot >>1) > 8)) do_proc = 0; // do nothing else // SF#6, SF#7 and SF#8 do_proc = multicast_relay; // do PHY procedures eNB TX break; default: // should'not be here LOG_W(PHY,"Not supported relay type %d, do nothing\n", r_type); do_proc=0; break; } return do_proc; } #endif /* void phy_procedures_eNB_lte(unsigned char subframe,PHY_VARS_eNB **eNB,uint8_t abstraction_flag, relaying_type_t r_type, PHY_VARS_RN *rn) { #if defined(ENABLE_ITTI) MessageDef *msg_p; const char *msg_name; instance_t instance; unsigned int Mod_id; int result; #endif int CC_id=0; VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX_ENB, eNB[0]->proc[subframe].frame_tx); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_LTE,1); start_meas(&eNB[0]->phy_proc); #if defined(ENABLE_ITTI) do { // Checks if a message has been sent to PHY sub-task itti_poll_msg (TASK_PHY_ENB, &msg_p); if (msg_p != NULL) { msg_name = ITTI_MSG_NAME (msg_p); instance = ITTI_MSG_INSTANCE (msg_p); Mod_id = instance; switch (ITTI_MSG_ID(msg_p)) { // Messages from eNB app case PHY_CONFIGURATION_REQ: LOG_I(PHY, "[eNB %d] Received %s\n", instance, msg_name); // TODO break; default: LOG_E(PHY, "[ENB %d] Received unexpected message %s\n", Mod_id, msg_name); break; } result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p); AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); } } while(msg_p != NULL); #endif for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { if ((((eNB[CC_id]->frame_parms.frame_type == TDD)&& (subframe_select(&eNB[CC_id]->frame_parms,eNB[CC_id]->proc[0].subframe_tx)==SF_DL))|| (eNB[CC_id]->frame_parms.frame_type == FDD))) { #ifdef Rel10 if (phy_procedures_RN_eNB_TX(eNB[CC_id]->proc[0].subframe_rx, eNB[CC_id]->proc[0].subframe_tx, r_type) != 0 ) #endif phy_procedures_eNB_TX(subframe,eNB[CC_id],abstraction_flag,r_type,rn); } if ((((eNB[CC_id]->frame_parms.frame_type == TDD )&& (subframe_select(&eNB[CC_id]->frame_parms,eNB[CC_id]->proc[0].subframe_rx)==SF_UL)) || (eNB[CC_id]->frame_parms.frame_type == FDD))) { phy_procedures_eNB_RX(subframe,eNB[CC_id],abstraction_flag,r_type); } if (subframe_select(&eNB[CC_id]->frame_parms,eNB[CC_id]->proc[0].subframe_tx)==SF_S) { #ifdef Rel10 if (phy_procedures_RN_eNB_TX(subframe, subframe, r_type) != 0 ) #endif phy_procedures_eNB_TX(subframe,eNB[CC_id],abstraction_flag,r_type,rn); } if ((subframe_select(&eNB[CC_id]->frame_parms,eNB[CC_id]->proc[0].subframe_rx)==SF_S)) { phy_procedures_eNB_S_RX(subframe,eNB[CC_id],abstraction_flag,r_type); } eNB[CC_id]->proc[0].frame_tx++; eNB[CC_id]->proc[0].frame_rx++; if (eNB[CC_id]->proc[0].frame_tx>=MAX_FRAME_NUMBER) // defined in impl_defs_top.h eNB[CC_id]->proc[0].frame_tx-=MAX_FRAME_NUMBER; if (eNB[CC_id]->proc[0].frame_rx>=MAX_FRAME_NUMBER) eNB[CC_id]->proc[0].frame_rx-=MAX_FRAME_NUMBER; } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_LTE,0); stop_meas(&eNB[0]->phy_proc); } */