/* * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under * the OAI Public License, Version 1.0 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * * http://www.openairinterface.org/?page_id=698 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance: * contact@openairinterface.org */ /*! \file phy_procedures_lte_eNB.c * \brief Implementation of eNB procedures from 36.213 LTE specifications * \author R. Knopp, F. Kaltenberger, N. Nikaein, X. Foukas, Michele Paffetti, Nick Ho * \date 2011 * \version 0.1 * \company Eurecom * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr,navid.nikaein@eurecom.fr, x.foukas@sms.ed.ac.uk, michele.paffetti@studio.unibo.it, nick133371@gmail.com * \note * \warning */ #include "PHY/defs.h" #include "PHY/defs_NB_IoT.h" #include "PHY/extern.h" #include "PHY/LTE_ESTIMATION/defs_NB_IoT.h" #include "PHY/LTE_TRANSPORT/defs_NB_IoT.h" #include "PHY/LTE_TRANSPORT/proto_NB_IoT.h" //#include "PHY/extern_NB_IoT.h" //where we get the global Sched_Rsp_t structure filled //#include "SCHED/defs.h" #include "SCHED/extern_NB_IoT.h" //#include "PHY/LTE_TRANSPORT/if4_tools.h" //#include "PHY/LTE_TRANSPORT/if5_tools.h" #include "RRC/LITE/proto_NB_IoT.h" #include "SIMULATION/TOOLS/defs.h" // purpose: included for taus() function //#ifdef EMOS //#include "SCHED/phy_procedures_emos.h" //#endif // for NB-IoT #include "SCHED/defs_NB_IoT.h" #include "openair2/RRC/LITE/proto_NB_IoT.h" #include "openair2/RRC/LITE/extern_NB_IoT.h" #include "RRC/LITE/MESSAGES/asn1_msg_NB_IoT.h" //#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 /* #if defined(FLEXRAN_AGENT_SB_IF) //Agent-related headers #include "ENB_APP/flexran_agent_extern.h" #include "ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h" #include "LAYER2/MAC/flexran_agent_mac_proto.h" #endif */ //#define DIAG_PHY ///#define NS_PER_SLOT 500000 ///#define PUCCH 1 //DCI_ALLOC_t dci_alloc[8]; ///#ifdef EMOS ///fifo_dump_emos_eNB emos_dump_eNB; ///#endif int npdsch_rep_to_array[3] = {4,8,16}; //TS 36.213 Table 16.4.1.3-3 int sib1_startFrame_to_array[4] = {0,16,32,48};//TS 36.213 Table 16.4.1.3-4 //New---------------------------------------------------- //return -1 whenever no SIB1-NB transmission occur. //return sib1_startFrame when transmission occur in the current frame uint32_t is_SIB1_NB_IoT(const frame_t frameP, long schedulingInfoSIB1, //from the mib int physCellId, //by configuration NB_IoT_eNB_NDLSCH_t *ndlsch_SIB1 ) { uint8_t nb_rep=0; // number of sib1-nb repetitions within the 256 radio frames uint32_t sib1_startFrame; uint32_t sib1_period_NB_IoT = 256;//from specs TS 36.331 (rf) uint8_t index; int offset; int period_nb; // the number of the actual period over the 1024 frames if(schedulingInfoSIB1 > 11 || schedulingInfoSIB1 < 0){ LOG_E(RRC, "is_SIB1_NB_IoT: schedulingInfoSIB1 value not allowed"); return 0; } //SIB1-NB period number period_nb = (int) frameP/sib1_period_NB_IoT; //number of repetitions nb_rep = npdsch_rep_to_array[schedulingInfoSIB1%3]; //based on number of rep. and the physical cell id we derive the starting radio frame (TS 36.213 Table 16.4.1.3-3/4) switch(nb_rep) { case 4: //physCellId%4 possible value are 0,1,2,3 sib1_startFrame = sib1_startFrame_to_array[physCellId%4]; break; case 8: //physCellId%2possible value are 0,1 sib1_startFrame = sib1_startFrame_to_array[physCellId%2]; break; case 16: //physCellId%2 possible value are 0,1 if(physCellId%2 == 0) sib1_startFrame = 0; else sib1_startFrame = 1; // the only case in which the starting frame is odd break; default: LOG_E(RRC, "Number of repetitions %d not allowed", nb_rep); return -1; } //check the actual frame w.r.t SIB1-NB starting frame if(frameP < sib1_startFrame + period_nb*256){ LOG_T(RRC, "the actual frame %d is before the SIB1-NB starting frame %d of the period--> bcch_sdu_legnth = 0", frameP, sib1_startFrame + period_nb*256); return -1; } //calculate offset between SIB1-NB repetitions (repetitions are equally spaced) offset = (sib1_period_NB_IoT-(16*nb_rep))/nb_rep; //loop over the SIB1-NB period for( int i = 0; i < nb_rep; i++) { //find the correct sib1-nb repetition interval in which the actual frame is //this is the start frame of a repetition index = sib1_startFrame+ i*(16+offset) + period_nb*256; //the actual frame is in a gap between two consecutive repetitions if(frameP < index) { ndlsch_SIB1->sib1_rep_start = 0; ndlsch_SIB1->relative_sib1_frame = 0; return -1; } //this is needed for ndlsch_procedure else if(frameP == index) { //the actual frame is the start of a new repetition (SIB1-NB should be retransmitted) ndlsch_SIB1->sib1_rep_start = 1; ndlsch_SIB1->relative_sib1_frame = 1; return sib1_startFrame; } else ndlsch_SIB1->sib1_rep_start = 0; //check in the current SIB1_NB repetition if(frameP>= index && frameP <= (index+15)) { //find if the actual frame is one of the "every other frame in 16 continuous frame" in which SIB1-NB is transmitted for(int y = 0; y < 16; y += 2) //every other frame (increment by 2) { if(frameP == index + y) { //this flag tell which is the number of the current frame w.r.t the 8th (over the continuous 16) in a repetition ndlsch_SIB1->relative_sib1_frame = y/2 + 1; //1st, 2nd, 3rd,... return sib1_startFrame; } } //if we are here means that the frame was inside the repetition interval but not considered for SIB1-NB transmission ndlsch_SIB1->relative_sib1_frame = 0; return -1; } } return -1; } /* For NB-IoT, we put NPBCH in later part, since it would be scheduled by MAC scheduler * It generates NRS/NPSS/NSSS * */ void common_signal_procedures_NB_IoT(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) { //LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms_NB_IoT; LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; NB_IoT_eNB_NPBCH_t *broadcast_str = &eNB->npbch; //NB_IoT_eNB_NDLSCH_t *sib1 = &eNB->ndlsch_SIB; //NB_IoT_eNB_NDLSCH_t *ndlsch = &eNB->ndlsch_SIB1; NB_IoT_eNB_NDLSCH_t *sib1 = eNB->ndlsch_SIB1; NB_IoT_eNB_NDLSCH_t *sib23 = eNB->ndlsch_SIB23; uint8_t *npbch_pdu = broadcast_str->pdu; int **txdataF = eNB->common_vars.txdataF[0]; uint32_t subframe = proc->subframe_tx; uint32_t frame = proc->frame_tx; //uint16_t Ntti = 10; //ntti = 10 int RB_IoT_ID=22; // XXX should be initialized (RB reserved for NB-IoT, PRB index) int With_NSSS=0; // With_NSSS = 1; if the frame include a sub-Frame with NSSS signal uint32_t hyper_frame=proc->HFN; fp->flag_free_sf =0; //////////////////////////////////////////////////////////////////////////////////// /* rrc_eNB_carrier_data_NB_IoT_t *carrier = &eNB_rrc_inst_NB_IoT->carrier[0]; if(frame%64==0 && subframe ==0) {//printf("dooooo MIB"); do_MIB_NB_IoT(carrier,1,frame,hyper_frame); } if(frame%64==1 && subframe ==0) { do_SIB1_NB_IoT_x(0,0,carrier,208,92,1,3584,28,2,hyper_frame); } */ ///////////////////////////////////////////////////////////////////////////////// //uint8_t *control_region_size = get_NB_IoT_SIB1_eutracontrolregionsize(); //int G=0; //NSSS only happened in the even frame int nsss_state = 0; if(frame%2==0) { With_NSSS = 1; } else { With_NSSS = 0; } ///////////////////////////////////////////////////////////////////////////////// //////////////////////////////// NPSS && NSSS ////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////// if(subframe == 5) { generate_npss_NB_IoT(txdataF, AMP, fp, 3, 10, RB_IoT_ID); } else if((subframe == 9) && (With_NSSS == 1)) { generate_sss_NB_IoT(txdataF, AMP, fp, 3, 18, frame, RB_IoT_ID); nsss_state = 1; } ///////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////// MIB ////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////// if(subframe == 0) { generate_npbch(broadcast_str, txdataF, AMP, fp, npbch_pdu, frame%64, RB_IoT_ID); } ///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////// SIB1 //////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////// int sib1_state = 0; if(subframe == 4) { sib1_state = generate_SIB1(sib1, txdataF, AMP, fp, frame, subframe, RB_IoT_ID, 0); } ///////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////// SIB23 //////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////// if( (subframe != 0) && (subframe != 5) && (sib1_state != 1) && (nsss_state != 1)) { generate_SIB23(sib23, txdataF, AMP, fp, frame, subframe, RB_IoT_ID); } if( (subframe != 0) && (subframe != 5) && (nsss_state != 1) && (fp->flag_free_sf == 0) ) { NB_IoT_eNB_NPDCCH_t *npdcch_str = eNB->npdcch_DCI; NB_IoT_eNB_NDLSCH_t *RAR = eNB->ndlsch_RAR; ///////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////// NPDCCH //////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////// generate_NPDCCH_NB_IoT(npdcch_str, txdataF, AMP, fp, frame, subframe, RB_IoT_ID); ///////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////// NPDSCH //////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////// generate_NDLSCH_NB_IoT(RAR, txdataF, AMP, fp, frame, subframe, RB_IoT_ID); /////////////////////////////////////////////////////////////////////////////////// } generate_pilots_NB_IoT(eNB, txdataF, AMP, subframe, RB_IoT_ID, With_NSSS); if(proc->frame_rx==1023 && proc->subframe_rx==9) { //printf("%d",hyper_frame); if(proc->HFN==1023) { proc->HFN=0; }else{ proc->HFN++; //printf("Update HFN:%d when frame:%d subframe:%d\n",proc->HFN,proc->frame_rx,proc->subframe_rx); } } } void phy_procedures_eNB_uespec_RX_NB_IoT(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) //UL_IND_NB_IoT_t *UL_INFO) { //RX processing for ue-specific resources (i //NB_IoT_DL_FRAME_PARMS *fp=&eNB->frame_parms_NB_IoT; const int subframe = proc->subframe_rx; const int frame = proc->frame_rx; /* ///////////////////// do we need this part for NB-IoT /////////////////////////////////// //check if any RB using in this UL subframe eNB->rb_mask_ul[0] = 0; eNB->rb_mask_ul[1] = 0; eNB->rb_mask_ul[2] = 0; eNB->rb_mask_ul[3] = 0; //////////////////////////////////////////////////////////////////////////////////////// */ npusch_procedures(eNB,proc); pthread_mutex_lock(&eNB->UL_INFO_mutex); // Fix me here, these should be locked eNB->UL_INFO.RX_NPUSCH.number_of_pdus = 0; eNB->UL_INFO.crc_ind.number_of_crcs = 0; pthread_mutex_unlock(&eNB->UL_INFO_mutex); // if (nfapi_mode == 0 || nfapi_mode == 1) { // If PNF or monolithic //} } /////////////////////////////////////////////////////////// backup //////////////////////////////////////////////////////// /*void phy_procedures_eNB_uespec_RX_NB_IoT(PHY_VARS_eNB_NB_IoT *eNB,eNB_rxtx_proc_t *proc, UL_IND_NB_IoT_t *UL_INFO) { //RX processing for ue-specific resources (i uint32_t ret=0,i,j,k; uint32_t harq_pid; // round; int sync_pos; uint16_t rnti=0; uint8_t access_mode; NB_IoT_DL_FRAME_PARMS *fp=&eNB->frame_parms_NB_IoT; const int subframe = proc->subframe_rx; const int frame = proc->frame_rx; // add hyper subframe here //NB-IoT IF module Common setting// UL_INFO->module_id = eNB->Mod_id; UL_INFO->CC_id = eNB->CC_id; UL_INFO->frame = frame; UL_INFO->subframe = subframe; T(T_ENB_PHY_UL_TICK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe)); T(T_ENB_PHY_INPUT_SIGNAL, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(0), T_BUFFER(&eNB->common_vars.rxdata[0][0][subframe*eNB->frame_parms_NB_IoT.samples_per_tti], eNB->frame_parms_NB_IoT.samples_per_tti * 4)); //if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)!=SF_UL)) return; //check if any RB using in this UL subframe eNB->rb_mask_ul[0] = 0; eNB->rb_mask_ul[1] = 0; eNB->rb_mask_ul[2] = 0; eNB->rb_mask_ul[3] = 0; // Check for active processes in current subframe // NB-IoT subframe2harq_pid is in dci_tools, always set the frame type to FDD, this would become simpler. harq_pid = subframe2harq_pid_NB_IoT(fp,frame,subframe); // delete the cba // delete the srs //Loop over the UE, i is the UE ID // for (i=0; i<NUMBER_OF_UE_MAX_NB_IoT; i++) { // delete srs // delete Pucch procedure // check for Msg3 if (eNB->mac_enabled==1) { if (eNB->UE_stats[i].mode == RA_RESPONSE_NB_IoT) { ///Process Msg3 TODO/// //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; //Check if this UE is has ULSCH scheduling/// if ((eNB->nulsch[i]) && (eNB->nulsch[i]->rnti>0) && (eNB->nulsch[i]->harq_process->subframe_scheduling_flag==1)) { // UE is has ULSCH scheduling //////////////////////////////////////round = eNB->nulsch[i]->harq_process->round; //commented to remove warning, to be added if round is used //NB-IoT The nb_rb always set to 1 // for (int rb=0;rb<=eNB->nulsch[i]->harq_process->nb_rb;rb++) { int rb2 = rb+eNB->nulsch[i]->harq_process->first_rb; eNB->rb_mask_ul[rb2>>5] |= (1<<(rb2&31)); } //Log for what kind of the ULSCH Reception// //Calculate for LTE C-RS// //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_NB_IoT ) { int sf = (subframe<4) ? (subframe+6) : (subframe-4); //After Downlink Data transmission, simply have a notice to received ACK from PUCCH, I think it's not use for now // if (eNB->ndlsch[i]->subframe_tx[sf]>0) // we have downlink transmission { eNB->nulsch[i]->harq_process->O_ACK = 1; } else { eNB->nulsch[i]->harq_process->O_ACK = 0; } } eNB->pusch_stats_rb[i][(frame*10)+subframe] = eNB->nulsch[i]->harq_process->nb_rb; eNB->pusch_stats_round[i][(frame*10)+subframe] = eNB->nulsch[i]->harq_process->round; eNB->pusch_stats_mcs[i][(frame*10)+subframe] = eNB->nulsch[i]->harq_process->mcs; rx_ulsch_NB_IoT(eNB, proc, eNB->UE_stats[i].sector, // this is the effective sector id i, eNB->nulsch, 0); ret = ulsch_decoding_NB_IoT(eNB,proc, i, 0, // control_only_flag eNB->nulsch[i]->harq_process->V_UL_DAI, eNB->nulsch[i]->harq_process->nb_rb>20 ? 1 : 0); //compute the expected ULSCH RX power (for the stats) eNB->nulsch[(uint32_t)i]->harq_process->delta_TF = get_hundred_times_delta_IF_eNB_NB_IoT(eNB,i,harq_pid, 0); // 0 means bw_factor is not considered eNB->UE_stats[i].nulsch_decoding_attempts[harq_pid][eNB->nulsch[i]->harq_process->round]++; eNB->nulsch[i]->harq_process->subframe_scheduling_flag=0; if (eNB->nulsch[i]->harq_process->cqi_crc_status == 1) { extract_CQI_NB_IoT(eNB->nulsch[i]->harq_process->o, eNB->nulsch[i]->harq_process->uci_format, &eNB->UE_stats[i], fp->N_RB_DL, &rnti, &access_mode); eNB->UE_stats[i].rank = eNB->nulsch[i]->harq_process->o_RI[0]; } if (ret == (1+MAX_TURBO_ITERATIONS)) { T(T_ENB_PHY_ULSCH_UE_NACK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(i), T_INT(eNB->nulsch[i]->rnti), T_INT(harq_pid)); eNB->UE_stats[i].ulsch_round_errors[harq_pid][eNB->nulsch[i]->harq_process->round]++; eNB->nulsch[i]->harq_process->phich_active = 1; eNB->nulsch[i]->harq_process->phich_ACK = 0; eNB->nulsch[i]->harq_process->round++; LOG_D(PHY,"[eNB][PUSCH %d] Increasing to round %d\n",harq_pid,eNB->nulsch[i]->harq_process->round); if (eNB->nulsch[i]->Msg3_flag == 1) { ///dump_ulsch(eNB,proc,i); //exit(-1);// //In NB-IoT MSG3 // // activate retransmission for Msg3 (signalled to UE PHY by DCI eNB->nulsch[(uint32_t)i]->Msg3_active = 1; // Need to check the procedure for NB-IoT (MSG3) retransmission // get_Msg3_alloc_ret(fp,subframe,frame,&eNB->ulsch[i]->Msg3_frame,&eNB->ulsch[i]->Msg3_subframe); //mac_xface->set_msg3_subframe(eNB->Mod_id, eNB->CC_id, frame, subframe, eNB->ulsch[i]->rnti,eNB->ulsch[i]->Msg3_frame, eNB->ulsch[i]->Msg3_subframe); T(T_ENB_PHY_MSG3_ALLOCATION, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(i), T_INT(eNB->nulsch[i]->rnti), T_INT(0), T_INT(eNB->nulsch[i]->Msg3_frame), T_INT(eNB->nulsch[i]->Msg3_subframe)); } // This is Msg3 error else { //normal ULSCH if (eNB->nulsch[i]->harq_process->round== eNB->nulsch[i]->Mlimit) { eNB->nulsch[i]->harq_process->round=0; eNB->nulsch[i]->harq_process->phich_active=0; eNB->UE_stats[i].ulsch_errors[harq_pid]++; eNB->UE_stats[i].ulsch_consecutive_errors++; //if (eNB->ulsch[i]->harq_processes[harq_pid]->nb_rb > 20) { // dump_ulsch(eNB,proc,i); // exit(-1); //} // indicate error to MAC if (eNB->mac_enabled == 1) { //instead rx_sdu to report The Uplink data not received successfully to MAC (UL_INFO->crc_ind.crc_pdu_list+i)->crc_indication_rel8.crc_flag = 1; UL_INFO->crc_ind.number_of_crcs++; (UL_INFO->RX_NPUSCH.rx_pdu_list+i)->rx_ue_information.rnti = eNB->nulsch[i]->rnti; (UL_INFO->RX_NPUSCH.rx_pdu_list+i)->data = NULL; (UL_INFO->RX_NPUSCH.rx_pdu_list+i)->rx_indication_rel8.length = 0; (UL_INFO->RX_NPUSCH.rx_pdu_list+i)->rx_ue_information.harq_pid = harq_pid; UL_INFO->RX_NPUSCH.number_of_pdus++; } } } } // ulsch in error else { T(T_ENB_PHY_ULSCH_UE_ACK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(i), T_INT(eNB->nulsch[i]->rnti), T_INT(harq_pid)); // Delete MSG3 log for the PHICH 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->nulsch[i]->harq_process->nb_rb*12) / fp->ofdm_symbol_size) - eNB->rx_total_gain_dB - hundred_times_log10_NPRB_NB_IoT[eNB->nulsch[i]->harq_process->nb_rb-1]/100 - get_hundred_times_delta_IF_eNB_NB_IoT(eNB,i,harq_pid, 0)/100; //for NB-IoT PHICH not work //eNB->ulsch[i]->harq_processes[harq_pid]->phich_active = 1; //eNB->ulsch[i]->harq_processes[harq_pid]->phich_ACK = 1;// eNB->nulsch[i]->harq_process->round = 0; eNB->UE_stats[i].ulsch_consecutive_errors = 0; if (eNB->nulsch[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); if (eNB->mac_enabled) { // store successful MSG3 in UL_Info instead rx_sdu (UL_INFO->crc_ind.crc_pdu_list+i)->crc_indication_rel8.crc_flag = 0; UL_INFO->crc_ind.number_of_crcs++; (UL_INFO->RX_NPUSCH.rx_pdu_list+i)->rx_ue_information.rnti = eNB->nulsch[i]->rnti; (UL_INFO->RX_NPUSCH.rx_pdu_list+i)->data = eNB->nulsch[i]->harq_process->b; (UL_INFO->RX_NPUSCH.rx_pdu_list+i)->rx_indication_rel8.length = eNB->nulsch[i]->harq_process->TBS>>3; (UL_INFO->RX_NPUSCH.rx_pdu_list+i)->rx_ue_information.harq_pid = harq_pid; UL_INFO->RX_NPUSCH.number_of_pdus++; } // Need check if this needed in NB-IoT // 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->nulsch[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); //Init HARQ parameters, need to check// for (k=0; k<8; k++) { //harq_processes for (j=0; j<eNB->ndlsch[i]->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->nulsch[i]->Mlimit; j++) { eNB->UE_stats[i].nulsch_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 if (eNB->mac_enabled == 1) { // store successful Uplink data in UL_Info instead rx_sdu (UL_INFO->crc_ind.crc_pdu_list+i)->crc_indication_rel8.crc_flag = 0; UL_INFO->crc_ind.number_of_crcs++; (UL_INFO->RX_NPUSCH.rx_pdu_list+i)->rx_ue_information.rnti = eNB->nulsch[i]->rnti; (UL_INFO->RX_NPUSCH.rx_pdu_list+i)->data = eNB->nulsch[i]->harq_process->b; (UL_INFO->RX_NPUSCH.rx_pdu_list+i)->rx_indication_rel8.length = eNB->nulsch[i]->harq_process->TBS>>3; (UL_INFO->RX_NPUSCH.rx_pdu_list+i)->rx_ue_information.harq_pid = harq_pid; UL_INFO->RX_NPUSCH.number_of_pdus++; } // mac_enabled==1 } // Msg3_flag == 0 // estimate timing advance for MAC sync_pos = NB_IoT_est_timing_advance_pusch(eNB,i); eNB->UE_stats[i].timing_advance_update = sync_pos - fp->nb_prefix_samples/4; //to check } // ulsch not in error // Process HARQ only in NPUSCH //process_HARQ_feedback(i, // eNB,proc, // 1, // pusch_flag // 0, // 0, // 0);/ } // ulsch[0] && ulsch[0]->rnti>0 && ulsch[0]->subframe_scheduling_flag == 1 // update ULSCH statistics for tracing } // loop i=0 ... NUMBER_OF_UE_MAX-1 } ////////////////////////////////////////////////////////////////end backup //////////////////////////////////////////////// #undef DEBUG_PHY_PROC /////Generate eNB ndlsch params for NB-IoT from the NPDCCH PDU of the DCI, modify the input to the Sched Rsp variable//// */ void generate_eNB_dlsch_params_NB_IoT(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t * proc,nfapi_dl_config_request_pdu_t *dl_config_pdu) { int UE_id = -1; LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; int frame = proc->frame_tx; int subframe = proc->subframe_tx; DCI_CONTENT *DCI_Content; DCI_format_NB_IoT_t DCI_format; NB_IoT_eNB_NDLSCH_t *ndlsch; NB_IoT_eNB_NPDCCH_t *npdcch; eNB->DCI_pdu = (DCI_PDU_NB_IoT*)malloc(sizeof(DCI_PDU_NB_IoT)); DCI_Content = (DCI_CONTENT*) malloc(sizeof(DCI_CONTENT)); // check DCI format is N1 (format 0) if(dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.dci_format == 0) { //check DCI format N1 is for RAR rnti_type in FAPI specs table 4-45 if(dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.rnti_type == 1) { //mapping the fapi parameters to the oai parameters DCI_format = DCIFormatN1_RAR; //DCI format N1 to RAR DCI_Content->DCIN1_RAR.type = 1; DCI_Content->DCIN1_RAR.orderIndicator = dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.npdcch_order_indication; DCI_Content->DCIN1_RAR.Scheddly = dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.scheduling_delay; DCI_Content->DCIN1_RAR.ResAssign = dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.resource_assignment; DCI_Content->DCIN1_RAR.mcs = dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.mcs; DCI_Content->DCIN1_RAR.RepNum = dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.repetition_number; DCI_Content->DCIN1_RAR.ndi = dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.new_data_indicator; DCI_Content->DCIN1_RAR.HARQackRes = dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.harq_ack_resource; DCI_Content->DCIN1_RAR.DCIRep = dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.dci_subframe_repetition_number; //TODO calculate the number of common repetitions //fp->nprach_config_common.number_repetition_RA = see TS 36.213 Table 16.1-3 // fill the dlsch_ra_NB structure for RAR, and packed the DCI PDU ndlsch = eNB->ndlsch_RAR; ndlsch->ndlsch_type = RAR; ndlsch->rnti = dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.rnti; npdcch = eNB->npdcch_DCI; LOG_D(PHY,"Generating pdcch params for DCIN1 RAR and packing DCI\n"); //LOG_I(PHY,"Rep of DCI is : %d\n",DCI_Content->DCIN1_RAR.RepNum); //LOG_I(PHY,"Generating dlsch params for RA_RNTI and packing DCI\n"); generate_eNB_dlsch_params_from_dci_NB_IoT(eNB, frame, subframe, DCI_Content, dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.rnti, DCI_format, npdcch, fp, dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.aggregation_level, dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.start_symbol, dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.ncce_index); //printf("PHY_vars_eNB_g[0][0]->ndlsch_RAR->rnti = %d\n",PHY_vars_eNB_g[0][0]->ndlsch_RAR->rnti); //eNB->dlsch_ra_NB->nCCE[subframe] = eNB->DCI_pdu->dci_alloc.firstCCE; } else { //managing data //TODO target/SIMU/USER?init_lte/init_lte_eNB we should allocate the ndlsch structures UE_id = find_ue_NB_IoT(dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.rnti, eNB); AssertFatal(UE_id != -1, "no ndlsch context available or no ndlsch context corresponding to that rnti\n"); //mapping the fapi parameters to the oai parameters DCI_format = DCIFormatN1; //DCI format N1 to DLSCH DCI_Content->DCIN1.type = 1; DCI_Content->DCIN1.orderIndicator = dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.npdcch_order_indication; DCI_Content->DCIN1.Scheddly = dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.scheduling_delay; DCI_Content->DCIN1.ResAssign = dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.resource_assignment; DCI_Content->DCIN1.mcs = dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.mcs; DCI_Content->DCIN1.RepNum = dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.repetition_number; DCI_Content->DCIN1.ndi = dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.new_data_indicator; DCI_Content->DCIN1.HARQackRes = dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.harq_ack_resource; DCI_Content->DCIN1.DCIRep = dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.dci_subframe_repetition_number; //set the NPDCCH UE-specific structure (calculate R) npdcch=eNB->npdcch[(uint8_t)UE_id]; AssertFatal(npdcch != NULL, "NPDCCH structure for UE specific is not exist\n"); npdcch->repetition_idx[(uint8_t)UE_id] = 0; //this is used for the encoding mechanism to understand that is the first transmission if(dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.aggregation_level) //whenever aggregation level is =1 we have only 1 repetition for USS npdcch->repetition_number[(uint8_t)UE_id] = 1; else { //see TS 36.213 Table 16.1-1 } //fill the ndlsch structure for UE and packed the DCI PD ndlsch = eNB->ndlsch[(uint8_t)UE_id]; //in the old implementation they also consider UE_id = 1; ndlsch->ndlsch_type = UE_Data; //parameters we don't consider pdsch config dedicated since not calling the phy config dedicated step2 LOG_I(PHY,"Generating dlsch params for DCIN1 data and packing DCI\n"); generate_eNB_dlsch_params_from_dci_NB_IoT(eNB, frame, subframe, DCI_Content, dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.rnti, DCI_format, npdcch, fp, dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.aggregation_level, dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.start_symbol, dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.ncce_index); //eNB->ndlsch[(uint8_t)UE_id]->nCCE[subframe] = eNB->DCI_pdu->dci_alloc[i].firstCCE; } } else if(dl_config_pdu->npdcch_pdu.npdcch_pdu_rel13.dci_format == 1) { DCI_format = DCIFormatN2; LOG_D(PHY,"Paging procedure not implemented\n"); } else LOG_E(PHY,"unknown DCI format for NB-IoT DL\n"); } void generate_eNB_ulsch_params_NB_IoT(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu) { int UE_id = -1; //int harq_pid = 0; DCI_CONTENT *DCI_Content; DCI_Content = (DCI_CONTENT*) malloc(sizeof(DCI_CONTENT)); //mapping the fapi parameters to the OAI parameters DCI_Content->DCIN0.type = 0; DCI_Content->DCIN0.scind = hi_dci0_pdu->npdcch_dci_pdu.npdcch_dci_pdu_rel13.subcarrier_indication; DCI_Content->DCIN0.ResAssign = hi_dci0_pdu->npdcch_dci_pdu.npdcch_dci_pdu_rel13.subcarrier_indication; DCI_Content->DCIN0.mcs = hi_dci0_pdu->npdcch_dci_pdu.npdcch_dci_pdu_rel13.mcs; DCI_Content->DCIN0.ndi = hi_dci0_pdu->npdcch_dci_pdu.npdcch_dci_pdu_rel13.new_data_indicator; DCI_Content->DCIN0.Scheddly = hi_dci0_pdu->npdcch_dci_pdu.npdcch_dci_pdu_rel13.scheduling_delay; DCI_Content->DCIN0.RepNum = hi_dci0_pdu->npdcch_dci_pdu.npdcch_dci_pdu_rel13.repetition_number; DCI_Content->DCIN0.rv = hi_dci0_pdu->npdcch_dci_pdu.npdcch_dci_pdu_rel13.redudancy_version; DCI_Content->DCIN0.DCIRep = hi_dci0_pdu->npdcch_dci_pdu.npdcch_dci_pdu_rel13.dci_subframe_repetition_number; UE_id = find_ue_NB_IoT(hi_dci0_pdu->npdcch_dci_pdu.npdcch_dci_pdu_rel13.rnti, eNB); AssertFatal(UE_id == -1, "no ndlsch context available or no ndlsch context corresponding to that rnti\n"); /*Log for generate ULSCH DCI*/ generate_eNB_ulsch_params_from_dci_NB_IoT(eNB, proc, DCI_Content, hi_dci0_pdu->npdcch_dci_pdu.npdcch_dci_pdu_rel13.rnti, DCIFormatN0, UE_id, hi_dci0_pdu->npdcch_dci_pdu.npdcch_dci_pdu_rel13.aggregation_level, hi_dci0_pdu->npdcch_dci_pdu.npdcch_dci_pdu_rel13.start_symbol); //LOG for ULSCH DCI Resource allocation //CBA is not used in NB-IoT eNB->nulsch[UE_id]->harq_process->subframe_scheduling_flag = 1; } /* * for NB-IoT ndlsch procedure * this function is called by the PHy procedure TX in 3 possible occasion: * 1) we manage BCCH pdu (SI) * 2) we manage RA dlsch pdu * 3) UE-specific dlsch pdu * ** we need to know if exist and which value has the eutracontrolRegionSize (TS 36.213 ch 16.4.1.4) whenever we are in In-band mode * ** CQI and PMI are not present in NB-IoT * ** redundancy version exist only in UL for NB-IoT and not in DL */ void npdsch_procedures(PHY_VARS_eNB_NB_IoT *eNB, eNB_rxtx_proc_t *proc, //Context data structure for RX/TX portion of subframe processing NB_IoT_eNB_NDLSCH_t *ndlsch, //int num_pdcch_symbols, //(BCOM says are not needed uint8_t *pdu ) { int frame = proc->frame_tx; int subframe = proc->subframe_tx; NB_IoT_DL_eNB_HARQ_t *ndlsch_harq = ndlsch->harq_process; int input_buffer_length = ndlsch_harq->TBS/8; // get in byte //the TBS is set in generate_dlsch_param NB_IoT_DL_FRAME_PARMS *fp = &eNB->frame_parms_NB_IoT; int G; uint8_t *DLSCH_pdu = NULL; uint8_t DLSCH_pdu_tmp[input_buffer_length+4]; //[768*8]; //uint8_t DLSCH_pdu_rar[256]; int i; LOG_D(PHY, "[eNB %"PRIu8"][PDSCH rnti%"PRIx16"] Frame %d, subframe %d: Generating PDSCH/DLSCH with input size = %"PRIu16", mcs %"PRIu8"(round %"PRIu8")\n", eNB->Mod_id, ndlsch->rnti, frame, subframe, input_buffer_length, ndlsch_harq->mcs, ndlsch_harq->round ); if(ndlsch_harq->round == 0) { //first transmission so we encode... because we generate the sequence if (eNB->mac_enabled == 1) { // set in lte-softmodem/main line 1646 DLSCH_pdu = pdu; /* * we don't need to manage the RAR here since should be managed in the MAC layer for two reasons: * 1)we should receive directly the pdu containing the RAR from the MAC in the schedule_response * 2)all the parameters for getting the MSG3 should be given by the UL_CONFIG.request (all inside the next schedule_response function) * */ //fill_rar shouduld be in the MAC //cancel ra procedure should be in the mac //scheduling request not implemented in NB-IoT //nulsch_param configuration for MSG3 should be considered in handling UL_Config.request //(in particular the nulsch structure for RAR is distinguished based on the harq_process->rar_alloc and the particular subframe in which we should have Msg3) } else { //XXX we should change taus function??? DLSCH_pdu = DLSCH_pdu_tmp; for (i=0; i<input_buffer_length; i++) DLSCH_pdu[i] = (unsigned char)(taus()&0xff); } } else { //We are doing a retransmission (harq round > 0 #ifdef DEBUG_PHY_PROC #ifdef DEBUG_DLSCH LOG_D(PHY,"[eNB] This DLSCH is a retransmission\n"); #endif #endif } if (eNB->abstraction_flag==0) { // used for simulation of the PHY?? //we can distinguish among the different kind of NDLSCH structure (example) switch(ndlsch->ndlsch_type) { case SIB1: break; case SI_Message: break; case RAR: //maybe not needed break; case UE_Data: //maybe not needed break; } /* * in any case inside the encoding procedure is re-checked if this is round 0 or no * in the case of harq_process round = 0 --> generate the sequence and put it into the parameter *c[r] * otherwise do nothing(only rate maching) */ /* * REASONING: * Encoding procedure will generate a Table with encoded data ( in ndlsch structure) * The table will go in input to the scrambling * --we should take care if there are repetitions of data or not because scrambling should be called at the first frame and subframe in which each repetition * begin (see params Nf, Ns) */ // 36-212 //encoding--------------------------- /* * * REASONING: * Encoding procedure will generate a Table with encoded data ( in ndlsch structure) * The table will go in input to the scrambling * --we should take care if there are repetitions of data or not because scrambling should be called at the first frame and subframe in which each repetition * begin (see params Nf, Ns) * * we should have as an iput parameter also G for the encoding based on the switch/case over eutracontrolRegionSize (if exist) and operationModeInfo if defined * NB: switch case of G is the same for npdsch and npdcch * * npdsch_start symbol index * -refers to TS 36.213 ch 16.4.1.4: * -if subframe k is a subframe for receiving the SIB1-NB * -- if operationModeInfo set to 00 or 01 (in band) --> npdsch_start_sysmbol = 3 * -- otherwise --> npdsch_start_symbol = 0 * -if the k subframe is not for SIB1-NB * --npdsch_start_symbol = eutracontrolregionsize (defined for in-band operating mode (mode 0,1 for FAPI specs) and take values 1,2,3 [units in number of OFDM symbol]) * - otherwise --> npdsch_start_symbol = 0 * (is the starting OFDM for the NPDSCH transmission in the first slot in a subframe k) * FAPI style: * npdsch_start symbol is stored in the ndlsch structure from the reception of the NPDLSCH PDU in the DL_CONFIG.request (so should be set by the MAC and put inside the schedule response) * Nsf needed as an input (number of subframe)-->inside harq_process of ndlsch */ switch(ndlsch->npdsch_start_symbol) { case 0: G = 304; break; case 1: G = 240; break; case 2: G = 224; break; case 3: G =200; break; default: LOG_E (PHY,"npdsch_start_index has unwanted value\n"); break; } //start_meas_NB_IoT(&eNB->dlsch_encoding_stats); LOG_I(PHY, "NB-IoT Encoding step\n"); // eNB->te(eNB, // DLSCH_pdu, // num_pdcch_symbols, // dlsch, // frame,subframe, // &eNB->dlsch_rate_matching_stats, // &eNB->dlsch_turbo_encoding_stats, // &eNB->dlsch_interleaving_stats); // stop_meas_NB_IoT(&eNB->dlsch_encoding_stats); // 36-211 //scrambling------------------------------------------- // start_meas_NB_IoT(&eNB->dlsch_scrambling_stats); LOG_I(PHY, "NB-IoT Scrambling step\n"); /* * SOME RELEVANT FACTS: * * */ // 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), // 0, // subframe<<1); //stop_meas_NB_IoT(&eNB->dlsch_scrambling_stats); //modulation------------------------------------------- //start_meas_NB_IoT(&eNB->dlsch_modulation_stats); LOG_I(PHY, "NB-IoT Modulation step\n"); // dlsch_modulation(eNB, // eNB->common_vars.txdataF[0], // AMP, // subframe, // num_pdcch_symbols, // dlsch, // dlsch1); //stop_meas_NB_IoT(&eNB->dlsch_modulation_stats); } #ifdef PHY_ABSTRACTION else { //start_meas_NB_IoT(&eNB->dlsch_encoding_stats); //dlsch_encoding_emul(eNB, //DLSCH_pdu, //dlsch); // stop_meas_NB_IoT(&eNB->dlsch_encoding_stats); } #endif ndlsch->active = 0; } extern int oai_exit; /* * ASSUMPTION * * The MAC schedule the schedule_response in a SUBFRAME BASE (at least because otherwise we have problem with our assumptions on SI transmission) * *Since in FAPI specs seems to not manage the information for the sceduling of system information: * Assume that the MAC layer manage the scheduling for the System information (SI messages) transmission while MIB and SIB1 are done directly at PHY layer * This means that the MAC scheduler will send to the PHY the NDLSCH PDU and MIB PDU (DL_CONFIG.request)each time they should be transmitted. In particular: ***MIB-NB *schedule_response containing a n-BCH PDU is transmitted only at the beginning of the MIB period, then repetitions are made directly by the PHY layer (see FAPI specs pag 94 N-BCH 3.2.4.2) *if no new N-BCH PDU is trasmitted at SFN mod 64=0 then stop MIB transmission ***SIB1-NB *schedule response containing a NDLSCH pdu (with appropiate configuration) will be transmitted only at the beginning of each SIB1-NB period (256 rf) *then repetitions are managed directly by the PHY layer *if no new NDLSCH pdu (configured for SIB1-NB) at SFN mod 256 = 0 is transmitted. stop SIB1-NB transmission ****SI Messages * -schedule_response is transmitted by the MAC in every subframe needed for the SI transmission (NDLSCH should have a proper configuration) * -if the schedule_response carry any SDU for SI-Message (SDU!= NULL)--> put the SDU in the PHY buffer to be encoded ecc... and start the transmission * -if the schedule_response not carry any SDU (SDU == NULL) but NDLSCH is properly set for SI, then PHY continue transmit the remaining part of the previous SDU * (this because the PHY layer have no logic of repetition_pattern, si_window ecc.. so should be continuously instructed the PHY when to transmit. * * Furthermore, SI messages are transmitted in more that 1 subframe (2 or 8) and therefore MAC layer need to count how many subframes are available in the current frame for transmit it * and take in consideration that other frames are needed before starting the transmission of a new one) * * *We assume that whenever the NDLSCH pdu is a BCCH type, we consider as if it's a SIB1 while in other case can be data or SI-message depending on the RNTI * * **relevant aspects for the System information Transmission (Table 4-47 NDLSCH FAPi specs) * 1)RNTI type = 0 (contains a BCCH) * 2)Repetition number == scheduling info SIB1 mapped into 4-8-16 * 3)RNTI (0xFFFF = SI-RNTI) * (see schedule_response implementation) * */ /* * This function is triggered by the schedule_response * (the frequency at which is transmitted to the PHY depends on the MAC scheduler implementation) * (in OAI in principle is every subframe) */ void phy_procedures_eNB_TX_NB_IoT(PHY_VARS_eNB_NB_IoT *eNB, eNB_rxtx_proc_t *proc, int do_meas) { int frame = proc->frame_tx; int subframe = proc->subframe_tx; uint32_t aa; DCI_PDU_NB_IoT *dci_pdu = eNB->DCI_pdu; NB_IoT_DL_FRAME_PARMS *fp = &eNB->frame_parms_NB_IoT; int8_t UE_id = 0; int **txdataF = eNB->common_vars.txdataF[0]; uint32_t sib1_startFrame = -1; //NB_IoT_eNB_NPDCCH_t*npdcch; if(do_meas == 1) //start_meas_NB_IoT(&eNB->phy_proc_tx); /*the original scheduler "eNB_dlsch_ulsch_scheduler" now is no more done here but is triggered directly from UL_Indication (IF-Module Function)*/ // clear the transmit data array for the current subframe for (aa=0; aa<fp->nb_antenna_ports_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)); } //generate NPSS/NSSS // common_signal_procedures_NB_IoT(eNB,proc); // to uncomment after NB-IoT testing //Generate MIB if(subframe ==0 && (eNB->npbch != NULL)) { if(eNB->npbch->pdu != NULL) { //BCOM function /* * -the function get the MIB pdu and schedule the transmission over the 64 radio frame * -need to check the subframe #0 (since encoding functions only check the frame) * this functions should be called every frame (the function will transmit the remaining part of MIB) * ( XXX Should check when the schedule_responce is transmitted by MAC scheduler) * RB-ID only for the case of in-band operation but should be always considered * (in stand alone i can put whatever the number)in other case consider the PRB index in the Table R&Shwartz pag 9 * */ generate_npbch(eNB->npbch, txdataF, AMP, fp, eNB->npbch->pdu, frame%64, fp->NB_IoT_RB_ID); } //In the last frame in which the MIB-NB should be transmitted after we point to NULL since maybe we stop MIB trasnmission //this should be in line with FAPI specs pag 94 (BCH procedure in Downlink 3.2.4.2 for NB-IoT) if(frame%64 == 63) { eNB->npbch->pdu = NULL; } } //Check for SIB1-NB transmission /* * * the function should be called for each frame * Parameters needed: * -sib1-NB pdu if new one (should be given by the MAC at the start of each SIB1-NB period) * -when start a new SIB1-NB repetition (sib1_rep_start) * -the frame number relative to the 16 continuous frame within a repetition (relative_sib1_frame) 1st, 2nd ... * * we check that the transmission should occurr in subframe #4 * * consider that if at the start of the new SIB1-NB period the MAC will not send an NPDSCH for the SIB1-NB transmission then SIB1-NB will be not transmitted (pdu = NULL) * */ if(subframe == 4 && eNB->ndlsch_SIB1 != NULL && eNB->ndlsch_SIB1->harq_process->status == ACTIVE_NB_IoT) { //check if current frame is for SIB1-NB transmission (if yes get the starting frame of SIB1-NB) and set the flag for the encoding sib1_startFrame = is_SIB1_NB_IoT(frame, (long)eNB->ndlsch_SIB1->harq_process->repetition_number, fp->Nid_cell, eNB->ndlsch_SIB1); //set the flags if(sib1_startFrame != -1 && eNB->ndlsch_SIB1->harq_process->pdu != NULL) { npdsch_procedures(eNB, proc, eNB->ndlsch_SIB1, //since we have no DCI for system information, this is filled directly when we receive the NDLSCH pdu from DL_CONFIG.request message eNB->ndlsch_SIB1->harq_process->pdu); } //at the end of the period we put the PDU to NULL since we have to wait for the new one from the MAC for starting the next SIB1-NB transmission if((frame-sib1_startFrame)%256 == 255) { //whenever we will not receive a new sdu from MAC at the start of the next SIB1-NB period we prevent future SIB1-NB transmission (may just only of the two condition is necessary) eNB->ndlsch_SIB1->harq_process->status = DISABLED; eNB->ndlsch_SIB1->harq_process->pdu = NULL; } } //Check for SI transmission /* *Parameters needed: * -total number of subframes for the transmission (2-8) (inside the NDLSCH structure --> HARQ process -->resource_assignment) * XXX: in reality this flag is not needed because is enough to check if the PDU is NULL (continue the transmission) or not (new SI transmission) * -SI_start (inside ndlsch structure): flag for indicate the starting of the SI transmission within the SI window (new PDU is received by the MAC) otherwise the PHY continue to transmit * what have in its buffer (so check the remaining encoded data continuously) * * SI transmission should not occurr in reserved subframes * subframe = 0 (MIB-NB) * subframe = 4 (SIB1-NB) but depends on the frame * subframe = 5 (NPSS) * subframe = 9 (NSSS) but depends on the frame (if is even) * * [This condition should be known by the MAC layer so it should trigger an DLSCH pdu only at proper instants] * * XXX Important: in the case the SI-window finish the PHY layer should have also being able to conclude all the SI transmission in time * (because this is managed by the MAC layer that stops transmitting the SDU to PHY in advance because is counting the remaining subframe for the transmission) * * *XXX important: set the flag HARQ process->status to DISABLE when PHY finished the SI-transmission over the 2 or 8 subframes *XXX important: whenever we enter for some error in the ndlsch_procedure with a pdu that is NULL but all the data of the SI have been transmitted (pdu_buffer_index = 0) *XXX --> generate error *XXX: the npdlsch_procedure in this case should be only called when is triggered by the MAC schedule_response (use the status flag set by the schedule_response) * */ if(eNB->ndlsch_SI->harq_process->status == ACTIVE_NB_IoT && (eNB->ndlsch_SIB1->harq_process->status != ACTIVE_NB_IoT || subframe != 4)) //condition on SIB1-NB { if(frame%2 == 0)//condition on NSSS (subframe 9 not available) { if(eNB->ndlsch_SI != NULL && subframe!= 0 && subframe != 5 && subframe != 9) { //check if the PDU != NULL will be done inside just for understanding if a new SI message need to be transmitted or not npdsch_procedures(eNB, proc, eNB->ndlsch_SI, //since we have no DCI for system information, this is filled directly when we receive the DL_CONFIG.request message eNB->ndlsch_SI->harq_process->pdu); eNB->ndlsch_SI->harq_process->status = DISABLED_NB_IoT; } } else {//this frame not foresee the transmission of NSSS (subframe 9 is available) if(eNB->ndlsch_SI != NULL && subframe!= 0 && subframe != 5) { npdsch_procedures(eNB, proc, eNB->ndlsch_SI, //since we have no DCI for system information, this is filled directly when we receive the DL_CONFIG.request message eNB->ndlsch_SI->harq_process->pdu); eNB->ndlsch_SI->harq_process->status = DISABLED_NB_IoT; } } } ///check for RAR transmission if(eNB->ndlsch_ra != NULL && eNB->ndlsch_ra->active == 1 && (eNB->ndlsch_SIB1->harq_process->status != ACTIVE_NB_IoT || subframe != 4)) //condition on SIB1-NB { if(frame%2 == 0)//condition on NSSS (subframe 9 not available) { if(eNB->ndlsch_SI != NULL && subframe!= 0 && subframe != 5 && subframe != 9) { npdsch_procedures(eNB, proc, eNB->ndlsch_ra, //should be filled ?? (in the old implementation was filled when from DCI we generate_dlsch_params eNB->ndlsch_ra->harq_process->pdu); //it should be activated only when we receive the proper DCIN1_RAR eNB->ndlsch_ra->active= 0; } } else //this frame not foresee the transmission of NSSS (subframe 9 is available) { if(eNB->ndlsch_SI != NULL && subframe!= 0 && subframe != 5) { npdsch_procedures(eNB, proc, eNB->ndlsch_ra, //should be filled ?? (in the old implementation was filled when from DCI we generate_dlsch_params eNB->ndlsch_ra->harq_process->pdu); //it should be activated only when we receive the proper DCIN1_RAR eNB->ndlsch_ra->active= 0; // maybe this is already done inside the ndlsch_procedure } } } //check for UE specific transmission /* * Delays between DCI transmission and NDLSCH transmission are taken in consideration by the MAC scheduler by sending in the proper subframe the scheduler_response * (TS 36.213 ch 16.4.1: DCI format N1, N2, ending in subframe n intended for the UE, the UE shall decode, starting from subframe n+5 DL subframe, * the corresponding NPDSCH transmission over the N consecutive NB/IoT DL subframes according to NPDCCH information) * Transmission over more subframe and Repetitions are managed directly by the PHY layer * We should have only 1 ue-specific ndlsch structure active at each time (active flag is set = 1 only at the corresponding NDLSCH pdu reception and not at the DCI time * (NDLSCH transmission should be compliant with the FAPI procedure Figure 3-49) * * XXX how are managed the transmission and repetitions over the NPDSCH: * -repetitions over the NPDSCH channel are defined inside the DCI * -need to know the repetition number R (see specs) * -repetition are made following a pattern rule (e.g. 00, 11 ...) (see specs) * --whenever R>4 then repetition pattern rule changes * -possibility to have DL-GAP (OPTIONAL) otherwise no gap in DCI transmission * * XXX During repetitions of DCI or NDLSCH we receive no schedule_response form MAC * */ //this should give only 1 result (since only 1 ndlsch procedure is activated at once) so we brak after the transmission for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX_NB_IoT; UE_id++) { if(eNB->ndlsch[(uint8_t)UE_id] != NULL && eNB->ndlsch[(uint8_t)UE_id]->active == 1 && (eNB->ndlsch_SIB1->harq_process->status != ACTIVE_NB_IoT || subframe != 4)) //condition on sib1-NB { if(frame%2 == 0)//condition on NSSS (subframe 9 not available) { if( subframe!= 0 && subframe != 5 && subframe != 9) { npdsch_procedures(eNB, proc, eNB->ndlsch[(uint8_t)UE_id], eNB->ndlsch[(uint8_t)UE_id]->harq_process->pdu); break; } } else //this frame not foresee the transmission of NSSS (subframe 9 is available) { if( subframe!= 0 && subframe != 5) { npdsch_procedures(eNB, proc, eNB->ndlsch[(uint8_t)UE_id], eNB->ndlsch[(uint8_t)UE_id]->harq_process->pdu); break; } } } } //no dedicated phy config /*If we have DCI to generate do it now * * DCI in NB-IoT are transmitted over NPDCCH search spaces as described in TS 36.213 ch 16.6 * * Don-t care about the concept of search space since will be managed by the MAC. * MAC also evaluate the starting position of NPDCCH transmission and will send the corresponding scheduling_response * * * The PHY layer should evaluate R (repetitions of DCI) based on: * -L (aggregation level) --> inside the NPDCCH PDU * -Rmax * -DCI subframe repetition number (2 bits) --> inside the NPDCCH PDU * -TS 36.213 Table 16.6/1/2/3 * * * The higher layer parms (Rmax): * -npdcch-NumRepetitions (UE-specific) [inside the NPDCCH UE-specific strucuture] --> configured through phyconfigDedicated * -npdcch-NumRepetitionPaging (common) * -npdcch-NumRepetitions-RA (common) [inside the NB_IoT_DL_FRAME_PARMS-> nprach_ParametersList] --> configured in phy_config_sib2 * * PROBLEM: in FAPI specs seems there is no way to trasnmit Rmax to the PHY (waiting for answers) * * *Rmax is also needed for evaluate the scheduling delay for NDLSCH (see scheduling delay field in NPDCCH PDU FAPI) * * *Scrambling re-initialization is needed at the beginning of the Search Space or every 4th NPDCCH subframe (See TS 36.211) * (this is taken in cosideration by the NPDCCH parameter "scrambling re-initialization batch index" in FAPI specs (Table 4-45) * ****whenever we have aggregation level = 1 for UE-specific the R is always = 1 (see table 16.6-1) ****DCI DL transmission should not happen in case of reference signals or SI messages (this function should be triggered every subframe) * * */ for(UE_id = 0 ; UE_id < NUMBER_OF_UE_MAX_NB_IoT; UE_id++) { if(eNB->npdcch[(uint8_t)UE_id] != NULL && eNB->npdcch[(uint8_t)UE_id]->rnti[(uint8_t)UE_id] == dci_pdu->dci_alloc->rnti && (eNB->ndlsch_SIB1->harq_process->status != ACTIVE_NB_IoT || subframe != 4)) { if(frame%2 == 0)//condition on NSSS (subframe 9 not available) { if( subframe!= 0 && subframe != 5 && subframe != 9) { generate_dci_top_NB_IoT(eNB->npdcch[(uint8_t)UE_id], dci_pdu->Num_dci, dci_pdu->dci_alloc, AMP, fp, eNB->common_vars.txdataF[0], subframe, dci_pdu->npdcch_start_symbol); //this parameter depends by eutraControlRegionSize (see TS36.213 16.6.1) eNB->npdcch[(uint8_t)UE_id]->repetition_idx[(uint8_t)UE_id]++; //can do also inside also the management break; } } else //this frame not foresee the transmission of NSSS (subframe 9 is available) { if( subframe!= 0 && subframe != 5) { generate_dci_top_NB_IoT(eNB->npdcch[(uint8_t)UE_id], dci_pdu->Num_dci, dci_pdu->dci_alloc, AMP, fp, eNB->common_vars.txdataF[0], subframe, dci_pdu->npdcch_start_symbol); //this parameter depends by eutraControlRegionSize (see TS36.213 16.6.1) eNB->npdcch[(uint8_t)UE_id]->repetition_idx[(uint8_t)UE_id]++; //can do also inside also the management break; } } } } } uint32_t rx_nprach_NB_IoT(PHY_VARS_eNB *eNB, int frame, uint8_t subframe, uint16_t *rnti, uint16_t *preamble_index, uint16_t *timing_advance) { uint32_t estimated_TA; //int frame,frame_mod; // subframe, // subframe = eNB->proc.subframe_prach; // frame = eNB->proc.frame_prach; //printf("frame = %i \n sf = %i\n",frame,subframe); // frame_mod = 0;//(frame)%32; //if (subframe==1 && frame_mod==0 && frame!=0){ //if (frame_mod==0 && frame!=0){ //printf("\n frame_in = %i\n",frame); estimated_TA = process_nprach_NB_IoT(eNB,frame,subframe,rnti,preamble_index,timing_advance); //printf("estim = %i\n",estimated_TA); // } return estimated_TA; } void fill_crc_indication_NB_IoT(PHY_VARS_eNB *eNB,int UE_id,int frame,int subframe,uint8_t crc_flag) { pthread_mutex_lock(&eNB->UL_INFO_mutex); // nfapi_crc_indication_pdu_t* crc_pdu_list nfapi_crc_indication_pdu_t *pdu = &eNB->UL_INFO.crc_ind.crc_pdu_list[0]; //[eNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs]; ///eNB->UL_INFO.crc_ind.sfn_sf = frame<<4 | subframe; //eNB->UL_INFO.crc_ind.header.message_id = NFAPI_CRC_INDICATION; //eNB->UL_INFO.crc_ind.crc_indication_body.tl.tag = NFAPI_CRC_INDICATION_BODY_TAG; //pdu->instance_length = 0; // don't know what to do with this // pdu->rx_ue_information.handle = handle; pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; pdu->rx_ue_information.rnti = eNB->ulsch[UE_id]->rnti; pdu->crc_indication_rel8.tl.tag = NFAPI_CRC_INDICATION_REL8_TAG; pdu->crc_indication_rel8.crc_flag = crc_flag; eNB->UL_INFO.crc_ind.number_of_crcs++; //LOG_D(PHY, "%s() rnti:%04x crcs:%d crc_flag:%d\n", __FUNCTION__, pdu->rx_ue_information.rnti, eNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs, crc_flag); pthread_mutex_unlock(&eNB->UL_INFO_mutex); } void npusch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) { uint32_t i; LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; NB_IoT_eNB_NULSCH_t *nulsch; NB_IoT_UL_eNB_HARQ_t *nulsch_harq; nulsch = eNB->ulsch_NB_IoT[0]; nulsch_harq = nulsch->harq_process; const int subframerx = proc->subframe_rx; const int framerx = proc->frame_rx; //for (i=0; i<NUMBER_OF_UE_MAX; i++) for (i=0; i<1; i++) { //ulsch_NB_IoT = eNB->ulsch_NB_IoT[i]; //ulsch_harq = ulsch_NB_IoT->harq_process; nulsch->Msg3_active = 1; nulsch->Msg3_flag = 1; // if eNB is ready to receive UL data // define a flag to trigger on or off the decoding process //if ((ulsch) && (ulsch->rnti>0) && (ulsch_harq->status == ACTIVE) && (ulsch_harq->frame == frame) && (ulsch_harq->subframe == subframe) && (ulsch_harq->handled == 0)) uint16_t N_slots = get_UL_slots_per_RU_NB_IoT(nulsch_harq->subcarrier_spacing, nulsch_harq->subcarrier_indication, nulsch->npusch_format)*get_UL_N_ru_NB_IoT(nulsch_harq->mcs,nulsch_harq->resource_assignment,nulsch->Msg3_flag); if ((nulsch->Msg3_active == 1) && (nulsch->Msg3_flag == 1)) // && (ulsch_harq->frame == framerx) && (ulsch_harq->subframe == subframerx)) { if(nulsch->flag_scramble == 1) { nulsch->Msg3_frame = framerx; nulsch->Msg3_subframe = subframerx; nulsch->flag_scramble = 0; } rx_ulsch_Gen_NB_IoT(eNB, proc, 0, // this is the effective sector id 0, nulsch, nulsch->npusch_format, //npusch_format, // 1, 2 22, // 22 , to be included in // to be replaced by NB_IoT_start ?? 1, // 0 (3.75 KHz) or 1 (15 KHz) nulsch->rnti, //= 65522 nulsch->Msg3_subframe, // first received subframe nulsch->Msg3_frame, // first received frame N_slots, // total number of occupied slots = get_nb_slot_per_RU * NB_of_RU get_UL_sc_index_start_NB_IoT(nulsch_harq->subcarrier_spacing,nulsch_harq->subcarrier_indication,nulsch->npusch_format), get_UL_N_ru_NB_IoT(nulsch_harq->mcs,nulsch_harq->resource_assignment,nulsch->Msg3_flag), // N_RU //if 0<get_numb_UL_sc_NB_IoT(uint8_t subcarrier_spacing, uint8_t I_sc, uint8_t npush_format),// Nsc, nulsch_harq->mcs, // I_mcs nulsch_harq->TBS, // A = TBS N_slots/2, ///proc->counter_msg3, // this represents the number of Subframe after encoding the msg3 // proc->counter_msg3 subframerx, 0, nulsch->Msg3_flag); } else if((nulsch->Msg3_active == 1) && (nulsch->Msg3_flag == 0)){ //// case of NPUSCH other than Msg3 rx_ulsch_Gen_NB_IoT(eNB, proc, 0, // this is the effective sector id 0, nulsch, nulsch->npusch_format, //npusch_format, // 1, 2 22, // 22 , to be included in // to be replaced by NB_IoT_start ?? 1, // 0 (3.75 KHz) or 1 (15 KHz) nulsch->rnti, //= 65522 nulsch->Msg3_subframe, // first received subframe nulsch->Msg3_frame, // first received frame N_slots, // total number of occupied slots = get_nb_slot_per_RU * NB_of_RU get_UL_sc_index_start_NB_IoT(nulsch_harq->subcarrier_spacing,nulsch_harq->subcarrier_indication,nulsch->npusch_format), get_UL_N_ru_NB_IoT(nulsch_harq->mcs,nulsch_harq->resource_assignment,nulsch->Msg3_flag), // N_RU nulsch_harq->mcs, // I_mcs nulsch_harq->TBS, // A = TBS N_slots/2, ///proc->counter_msg3, // this represents the number of Subframe after encoding the msg3 // proc->counter_msg3 subframerx, 0, nulsch->Msg3_flag); } } // for UE loop }