/* * 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 eNB_scheduler_primitives.c * \brief primitives used by eNB for BCH, RACH, ULSCH, DLSCH scheduling * \author Navid Nikaein and Raymond Knopp * \date 2010 - 2014 * \email: navid.nikaein@eurecom.fr * \version 1.0 * @ingroup _mac */ #include "assertions.h" #include "PHY/defs.h" #include "PHY/extern.h" #include "SCHED/defs.h" #include "SCHED/extern.h" #include "LAYER2/MAC/defs.h" #include "LAYER2/MAC/extern.h" #include "LAYER2/MAC/proto.h" #include "UTIL/LOG/log.h" #include "UTIL/LOG/vcd_signal_dumper.h" #include "UTIL/OPT/opt.h" #include "OCG.h" #include "OCG_extern.h" #include "RRC/LITE/extern.h" #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" //#include "LAYER2/MAC/pre_processor.c" #include "pdcp.h" #if defined(ENABLE_ITTI) # include "intertask_interface.h" #endif #include "T.h" #define ENABLE_MAC_PAYLOAD_DEBUG #define DEBUG_eNB_SCHEDULER 1 int choose(int n,int k) { int res = 1; int res2 = 1; int i; if (k>n) return(0); if (n==k) return(1); for (i=n;i>k;i--) res*=i; for (i=2;i<=(n-k);i++) res2*=i; return(res/res2); } // Patented algorithm from Yang et al, US Patent 2009, "Channel Quality Indexing and Reverse Indexing" void reverse_index(int N,int M,int r,int *v) { int BaseValue=0; int IncreaseValue,ThresholdValue; int sumV; int i; r = choose(N,M) - 1 - r; memset((void*)v,0,M*sizeof(int)); sumV=0; i=M; while (i>0 && r>0) { IncreaseValue = choose(N-M+1-sumV-v[i-1]+i-2,i-1); ThresholdValue = BaseValue+IncreaseValue; if (r>=ThresholdValue) { v[i-1]++; BaseValue=ThresholdValue; } else { r=r-BaseValue; sumV+=v[i-1]; i--; BaseValue=0; } } } int to_prb(int dl_Bandwidth) { int prbmap[6] = {6,15,25,50,75,100}; AssertFatal(dl_Bandwidth < 6,"dl_Bandwidth is 0..5\n"); return(prbmap[dl_Bandwidth]); } int to_rbg(int dl_Bandwidth) { int rbgmap[6] = {6,8,13,17,19,25}; AssertFatal(dl_Bandwidth < 6,"dl_Bandwidth is 0..5\n"); return(rbgmap[dl_Bandwidth]); } int get_phich_resource_times6(COMMON_channels_t *cc) { int phichmap[4] = {1,3,6,12}; AssertFatal(cc!=NULL,"cc is null\n"); AssertFatal(cc->mib!=NULL,"cc->mib is null\n"); AssertFatal((cc->mib->message.phich_Config.phich_Resource>=0) && (cc->mib->message.phich_Config.phich_Resource<4), "phich_Resource %d not in 0..3\n",(int)cc->mib->message.phich_Config.phich_Resource); return(phichmap[cc->mib->message.phich_Config.phich_Resource]); } uint16_t mac_computeRIV(uint16_t N_RB_DL,uint16_t RBstart,uint16_t Lcrbs) { uint16_t RIV; if (Lcrbs<=(1+(N_RB_DL>>1))) RIV = (N_RB_DL*(Lcrbs-1)) + RBstart; else RIV = (N_RB_DL*(N_RB_DL+1-Lcrbs)) + (N_RB_DL-1-RBstart); return(RIV); } uint8_t getQm(uint8_t mcs) { if (mcs<10) return(2); else if (mcs<17) return(4); else return (6); } void get_Msg3alloc(COMMON_channels_t *cc, sub_frame_t current_subframe, frame_t current_frame, frame_t *frame, sub_frame_t *subframe) { // Fill in other TDD Configuration!!!! if (cc->tdd_Config==NULL) { // FDD *subframe = current_subframe+6; if (*subframe>9) { *subframe = *subframe-10; *frame = (current_frame+1) & 1023; } else { *frame=current_frame; } } else { // TDD if (cc->tdd_Config->subframeAssignment == 1) { switch (current_subframe) { case 0: *subframe = 7; *frame = current_frame; break; case 4: *subframe = 2; *frame = (current_frame+1) & 1023; break; case 5: *subframe = 2; *frame = (current_frame+1) & 1023; break; case 9: *subframe = 7; *frame = (current_frame+1) & 1023; break; } } else if (cc->tdd_Config->subframeAssignment == 3) { switch (current_subframe) { case 0: case 5: case 6: *subframe = 2; *frame = (current_frame+1) & 1023; break; case 7: *subframe = 3; *frame = (current_frame+1) & 1023; break; case 8: *subframe = 4; *frame = (current_frame+1) & 1023; break; case 9: *subframe = 2; *frame = (current_frame+2) & 1023; break; } } else if (cc->tdd_Config->subframeAssignment == 4) { switch (current_subframe) { case 0: case 4: case 5: case 6: *subframe = 2; *frame = (current_frame+1) & 1023; break; case 7: *subframe = 3; *frame = (current_frame+1) & 1023; break; case 8: case 9: *subframe = 2; *frame = (current_frame+2) & 1023; break; } } else if (cc->tdd_Config->subframeAssignment == 5) { switch (current_subframe) { case 0: case 4: case 5: case 6: *subframe = 2; *frame = (current_frame+1) & 1023; break; case 7: case 8: case 9: *subframe = 2; *frame = (current_frame+2) & 1023; break; } } } } void get_Msg3allocret(COMMON_channels_t *cc, sub_frame_t current_subframe, frame_t current_frame, frame_t *frame, sub_frame_t *subframe) { if (cc->tdd_Config == NULL) { //FDD /* always retransmit in n+8 */ *subframe = current_subframe + 8; if (*subframe > 9) { *subframe = *subframe - 10; *frame = (current_frame + 1) & 1023; } else { *frame = current_frame; } } else { if (cc->tdd_Config->subframeAssignment == 1) { // original PUSCH in 2, PHICH in 6 (S), ret in 2 // original PUSCH in 3, PHICH in 9, ret in 3 // original PUSCH in 7, PHICH in 1 (S), ret in 7 // original PUSCH in 8, PHICH in 4, ret in 8 *frame = (current_frame+1) & 1023; } else if (cc->tdd_Config->subframeAssignment == 3) { // original PUSCH in 2, PHICH in 8, ret in 2 next frame // original PUSCH in 3, PHICH in 9, ret in 3 next frame // original PUSCH in 4, PHICH in 0, ret in 4 next frame *frame=(current_frame+1) & 1023; } else if (cc->tdd_Config->subframeAssignment == 4) { // original PUSCH in 2, PHICH in 8, ret in 2 next frame // original PUSCH in 3, PHICH in 9, ret in 3 next frame *frame=(current_frame+1) & 1023; } else if (cc->tdd_Config->subframeAssignment == 5) { // original PUSCH in 2, PHICH in 8, ret in 2 next frame *frame=(current_frame+1) & 1023; } } } uint8_t subframe2harqpid(COMMON_channels_t *cc,frame_t frame,sub_frame_t subframe) { uint8_t ret = 255; AssertFatal(cc!=NULL,"cc is null\n"); if (cc->tdd_Config == NULL) { // FDD ret = (((frame<<1)+subframe)&7); } else { switch (cc->tdd_Config->subframeAssignment) { case 1: if ((subframe==2) || (subframe==3) || (subframe==7) || (subframe==8)) switch (subframe) { case 2: case 3: ret = (subframe-2); break; case 7: case 8: ret = (subframe-5); break; default: AssertFatal(1==0,"subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",subframe,(int)cc->tdd_Config->subframeAssignment); break; } break; case 2: AssertFatal((subframe==2) || (subframe==7), "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",subframe,(int)cc->tdd_Config->subframeAssignment); ret = (subframe/7); break; case 3: AssertFatal((subframe>1) && (subframe<5), "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",subframe,(int)cc->tdd_Config->subframeAssignment); ret = (subframe-2); break; case 4: AssertFatal((subframe>1) && (subframe<4), "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",subframe,(int)cc->tdd_Config->subframeAssignment); ret = (subframe-2); break; case 5: AssertFatal(subframe==2, "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",subframe,(int)cc->tdd_Config->subframeAssignment); ret = (subframe-2); break; default: AssertFatal(1==0,"subframe2_harq_pid, Unsupported TDD mode %d\n",(int)cc->tdd_Config->subframeAssignment); } } return ret; } uint8_t get_Msg3harqpid(COMMON_channels_t *cc, frame_t frame, sub_frame_t current_subframe) { uint8_t ul_subframe=0; uint32_t ul_frame=0; if (cc->tdd_Config == NULL) { // FDD ul_subframe = (current_subframe>3) ? (current_subframe-4) : (current_subframe+6); ul_frame = (current_subframe>3) ? ((frame+1)&1023) : frame; } else { switch (cc->tdd_Config->subframeAssignment) { case 1: switch (current_subframe) { case 9: case 0: ul_subframe = 7; break; case 5: case 7: ul_subframe = 2; break; } break; case 3: switch (current_subframe) { case 0: case 5: case 6: ul_subframe = 2; break; case 7: ul_subframe = 3; break; case 8: ul_subframe = 4; break; case 9: ul_subframe = 2; break; } break; case 4: switch (current_subframe) { case 0: case 5: case 6: case 8: case 9: ul_subframe = 2; break; case 7: ul_subframe = 3; break; } break; case 5: ul_subframe =2; break; default: LOG_E(PHY,"get_Msg3_harq_pid: Unsupported TDD configuration %d\n",(int)cc->tdd_Config->subframeAssignment); AssertFatal(1==0,"get_Msg3_harq_pid: Unsupported TDD configuration"); break; } } return(subframe2harqpid(cc,ul_frame,ul_subframe)); } uint32_t pdcchalloc2ulframe(COMMON_channels_t *ccP,uint32_t frame, uint8_t n) { uint32_t ul_frame; if ((ccP->tdd_Config) && (ccP->tdd_Config->subframeAssignment == 1) && ((n==1)||(n==6))) // tdd_config 0,1 SF 1,5 ul_frame = (frame + (n==1 ? 0 : 1)); else if ((ccP->tdd_Config) && (ccP->tdd_Config->subframeAssignment == 6) && ((n==0)||(n==1)||(n==5)||(n==6))) ul_frame = (frame + (n>=5 ? 1 : 0)); else if ((ccP->tdd_Config) && (ccP->tdd_Config->subframeAssignment == 6) && (n==9)) // tdd_config 6 SF 9 ul_frame = (frame+1); else ul_frame = (frame+(n>=6 ? 1 : 0)); LOG_D(PHY, "frame %d subframe %d: PUSCH frame = %d\n", frame, n, ul_frame); return ul_frame; } uint8_t pdcchalloc2ulsubframe(COMMON_channels_t *ccP,uint8_t n) { uint8_t ul_subframe; if ((ccP->tdd_Config) && (ccP->tdd_Config->subframeAssignment == 1) && ((n==1)||(n==6))) // tdd_config 0,1 SF 1,5 ul_subframe = ((n+6)%10); else if ((ccP->tdd_Config) && (ccP->tdd_Config->subframeAssignment == 6) && ((n==0)||(n==1)||(n==5)||(n==6))) ul_subframe = ((n+7)%10); else if ((ccP->tdd_Config) && (ccP->tdd_Config->subframeAssignment == 6) && (n==9)) // tdd_config 6 SF 9 ul_subframe = ((n+5)%10); else ul_subframe = ((n+4)%10); LOG_D(PHY, "subframe %d: PUSCH subframe = %d\n", n, ul_subframe); return ul_subframe; } int is_UL_sf(COMMON_channels_t *ccP,sub_frame_t subframeP) { // if FDD return dummy value if (ccP->tdd_Config == NULL) return(0); switch (ccP->tdd_Config->subframeAssignment) { case 1: switch (subframeP) { case 0: case 4: case 5: case 9: return(0); break; case 2: case 3: case 7: case 8: return(1); break; default: return(0); break; } break; case 3: if ((subframeP<=1) || (subframeP>=5)) return(0); else if ((subframeP>1) && (subframeP < 5)) return(1); else AssertFatal(1==0,"Unknown subframe number\n"); break; case 4: if ((subframeP<=1) || (subframeP>=4)) return(0); else if ((subframeP>1) && (subframeP < 4)) return(1); else AssertFatal(1==0,"Unknown subframe number\n"); break; case 5: if ((subframeP<=1) || (subframeP>=3)) return(0); else if ((subframeP>1) && (subframeP < 3)) return(1); else AssertFatal(1==0,"Unknown subframe number\n"); break; default: AssertFatal(1==0,"subframe %d Unsupported TDD configuration %d\n", subframeP,(int)ccP->tdd_Config->subframeAssignment); break; } } uint16_t get_pucch1_absSF(COMMON_channels_t *cc,uint16_t dlsch_absSF) { uint16_t sf,f,nextf; if (cc->tdd_Config==NULL) { //FDD n+4 return((dlsch_absSF + 4)%10240); } else { sf = dlsch_absSF%10; f = dlsch_absSF/10; nextf = (f+1)&1023; switch (cc->tdd_Config->subframeAssignment) { case 0: AssertFatal(1==0,"SFA 0 to be filled in now, :-)\n"); break; case 1: if ((sf==5) || (sf==6)) return((10*nextf) + 2); // ACK/NAK in SF 2 next frame else if (sf==9) return((10*nextf) + 3); // ACK/NAK in SF 3 next frame else if ((sf==0) || (sf==1)) return((10*f) + 2); // ACK/NAK in SF 7 same frame else AssertFatal(1==0,"Impossible dlsch subframe %d for TDD configuration 3\n",sf); break; case 2: if ((sf==4) || (sf==5) || (sf==6) || (sf==8)) return((10*nextf) + 2); // ACK/NAK in SF 2 next frame else if (sf==9) return((10*nextf) + 7); // ACK/NAK in SF 7 next frame else if ((sf==0) || (sf==1) || (sf==3)) return((10*f) + 7); // ACK/NAK in SF 7 same frame else AssertFatal(1==0,"Impossible dlsch subframe %d for TDD configuration 3\n",sf); break; case 3: if ((sf==5) || (sf==6) || (sf==7) || (sf==8) || (sf==9)) return((10*nextf) + (sf>>1)); // ACK/NAK in 2,3,4 resp. next frame else if (sf==1) return((10*nextf) + 2); // ACK/NAK in 2 next frame else if (sf==0) return((10*f) + 4); // ACK/NAK in 4 same frame else AssertFatal(1==0,"Impossible dlsch subframe %d for TDD configuration 3\n",sf); break; case 4: if ((sf==6) || (sf==7) || (sf==8) || (sf==9)) return(((10*nextf) + 3)%10240); // ACK/NAK in SF 3 next frame else if ((sf==0) || (sf==1) || (sf==4) || (sf==5)) return(((10*nextf) + 2)%10240); // ACK/NAK in SF 2 next frame else AssertFatal(1==0,"Impossible dlsch subframe %d for TDD configuration 4\n",sf); break; case 5: if ((sf==0) || (sf==1) || (sf==3) || (sf==4) || (sf==5) || (sf==6) || (sf==7) || (sf==8)) return(((10*nextf) + 2)%10240); // ACK/NAK in SF 3 next frame else if (sf==9) return(((10*(1+nextf)) + 2)%10240); // ACK/NAK in SF 2 next frame else AssertFatal(1==0,"Impossible dlsch subframe %d for TDD configuration 5\n",sf); break; case 6: AssertFatal(1==0,"SFA 6 To be filled in now, :-)\n"); break; default: AssertFatal(1==0,"Illegal TDD subframe Assigment %d\n",(int)cc->tdd_Config->subframeAssignment); break; } } AssertFatal(1==0,"Shouldn't get here\n"); } void get_srs_pos(COMMON_channels_t *cc,uint16_t isrs,uint16_t *psrsPeriodicity,uint16_t *psrsOffset) { if(cc->tdd_Config) { // TDD AssertFatal(isrs>=10,"2 ms SRS periodicity not supported"); if ((isrs>9)&&(isrs<15)) { *psrsPeriodicity=5; *psrsOffset=isrs-10; } if ((isrs>14)&&(isrs<25)) { *psrsPeriodicity=10; *psrsOffset=isrs-15; } if ((isrs>24)&&(isrs<45)) { *psrsPeriodicity=20; *psrsOffset=isrs-25; } if ((isrs>44)&&(isrs<85)) { *psrsPeriodicity=40; *psrsOffset=isrs-45; } if ((isrs>84)&&(isrs<165)) { *psrsPeriodicity=80; *psrsOffset=isrs-85; } if ((isrs>164)&&(isrs<325)) { *psrsPeriodicity=160; *psrsOffset=isrs-165; } if ((isrs>324)&&(isrs<645)) { *psrsPeriodicity=320; *psrsOffset=isrs-325; } AssertFatal(isrs<=644,"Isrs out of range %d>644\n",isrs); } // TDD else { // FDD if (isrs<2) { *psrsPeriodicity=2; *psrsOffset=isrs; } if ((isrs>1)&&(isrs<7)) { *psrsPeriodicity=5; *psrsOffset=isrs-2; } if ((isrs>6)&&(isrs<17)) { *psrsPeriodicity=10; *psrsOffset=isrs-7; } if ((isrs>16)&&(isrs<37)) { *psrsPeriodicity=20; *psrsOffset=isrs-17; } if ((isrs>36)&&(isrs<77)) { *psrsPeriodicity=40; *psrsOffset=isrs-37; } if ((isrs>76)&&(isrs<157)) { *psrsPeriodicity=80; *psrsOffset=isrs-77; } if ((isrs>156)&&(isrs<317)) { *psrsPeriodicity=160; *psrsOffset=isrs-157; } if ((isrs>316)&&(isrs<637)) { *psrsPeriodicity=320; *psrsOffset=isrs-317; } AssertFatal(isrs<=636,"Isrs out of range %d>636\n",isrs); } } void get_csi_params(COMMON_channels_t *cc,struct CQI_ReportPeriodic *cqi_ReportPeriodic,uint16_t *Npd,uint16_t *N_OFFSET_CQI,int *H) { uint16_t cqi_PMI_ConfigIndex = cqi_ReportPeriodic->choice.setup.cqi_pmi_ConfigIndex; uint8_t Jtab[6] = {0,2,2,3,4,4}; AssertFatal(cqi_ReportPeriodic!=NULL,"cqi_ReportPeriodic is null!\n"); if (cc->tdd_Config==NULL) { //FDD if (cqi_PMI_ConfigIndex <= 1) { // 2 ms CQI_PMI period *Npd = 2; *N_OFFSET_CQI = cqi_PMI_ConfigIndex; } else if (cqi_PMI_ConfigIndex <= 6) { // 5 ms CQI_PMI period *Npd = 5; *N_OFFSET_CQI = cqi_PMI_ConfigIndex-2; } else if (cqi_PMI_ConfigIndex <=16) { // 10ms CQI_PMI period *Npd = 10; *N_OFFSET_CQI = cqi_PMI_ConfigIndex-7; } else if (cqi_PMI_ConfigIndex <= 36) { // 20 ms CQI_PMI period *Npd = 20; *N_OFFSET_CQI = cqi_PMI_ConfigIndex-17; } else if (cqi_PMI_ConfigIndex <= 76) { // 40 ms CQI_PMI period *Npd = 40; *N_OFFSET_CQI = cqi_PMI_ConfigIndex-37; } else if (cqi_PMI_ConfigIndex <= 156) { // 80 ms CQI_PMI period *Npd = 80; *N_OFFSET_CQI = cqi_PMI_ConfigIndex-77; } else if (cqi_PMI_ConfigIndex <= 316) { // 160 ms CQI_PMI period *Npd = 160; *N_OFFSET_CQI = cqi_PMI_ConfigIndex-157; } else if (cqi_PMI_ConfigIndex > 317) { if (cqi_PMI_ConfigIndex <= 349) { // 32 ms CQI_PMI period *Npd = 32; *N_OFFSET_CQI = cqi_PMI_ConfigIndex-318; } else if (cqi_PMI_ConfigIndex <= 413) { // 64 ms CQI_PMI period *Npd = 64; *N_OFFSET_CQI = cqi_PMI_ConfigIndex-350; } else if (cqi_PMI_ConfigIndex <= 541) { // 128 ms CQI_PMI period *Npd = 128; *N_OFFSET_CQI = cqi_PMI_ConfigIndex-414; } } } else { // TDD if (cqi_PMI_ConfigIndex == 0) { // all UL subframes *Npd = 1; *N_OFFSET_CQI = 0; } else if (cqi_PMI_ConfigIndex <= 6) { // 5 ms CQI_PMI period *Npd = 5; *N_OFFSET_CQI = cqi_PMI_ConfigIndex-1; } else if (cqi_PMI_ConfigIndex <=16) { // 10ms CQI_PMI period *Npd = 10; *N_OFFSET_CQI = cqi_PMI_ConfigIndex-6; } else if (cqi_PMI_ConfigIndex <= 36) { // 20 ms CQI_PMI period *Npd = 20; *N_OFFSET_CQI = cqi_PMI_ConfigIndex-16; } else if (cqi_PMI_ConfigIndex <= 76) { // 40 ms CQI_PMI period *Npd = 40; *N_OFFSET_CQI = cqi_PMI_ConfigIndex-36; } else if (cqi_PMI_ConfigIndex <= 156) { // 80 ms CQI_PMI period *Npd = 80; *N_OFFSET_CQI = cqi_PMI_ConfigIndex-76; } else if (cqi_PMI_ConfigIndex <= 316) { // 160 ms CQI_PMI period *Npd = 160; *N_OFFSET_CQI = cqi_PMI_ConfigIndex-156; } } // get H if (cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_subbandCQI) *H = 1+(Jtab[cc->mib->message.dl_Bandwidth]*cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.choice.subbandCQI.k); else *H=1; } uint8_t get_dl_cqi_pmi_size_pusch(COMMON_channels_t *cc,uint8_t tmode,uint8_t ri, CQI_ReportModeAperiodic_t *cqi_ReportModeAperiodic) { int Ntab[6] = {0,4,7,9,10,13}; int N = Ntab[cc->mib->message.dl_Bandwidth]; int Ltab_uesel[6] = {0,6,9,13,15,18}; int L = Ltab_uesel[cc->mib->message.dl_Bandwidth]; AssertFatal(cqi_ReportModeAperiodic != NULL,"cqi_ReportPeriodic is null!\n"); switch (*cqi_ReportModeAperiodic) { case CQI_ReportModeAperiodic_rm12: AssertFatal(tmode==4 || tmode==6 || tmode==8 || tmode==9 || tmode==10,"Illegal TM (%d) for CQI_ReportModeAperiodic_rm12\n",tmode); AssertFatal(cc->p_eNB<=4,"only up to 4 antenna ports supported here\n"); if (ri==1 && cc->p_eNB==2) return(4+(N<<1)); else if (ri==2 && cc->p_eNB==2) return(8+N); else if (ri==1 && cc->p_eNB==4) return(4+(N<<2)); else if (ri>1 && cc->p_eNB==4) return(8+(N<<2)); break; case CQI_ReportModeAperiodic_rm20: // Table 5.2.2.6.3-1 (36.212) AssertFatal(tmode==1 || tmode==2 || tmode==3 || tmode==7 || tmode==9 || tmode==10,"Illegal TM (%d) for CQI_ReportModeAperiodic_rm20\n",tmode); AssertFatal(tmode!=9 && tmode!=10,"TM9/10 will be handled later for CQI_ReportModeAperiodic_rm20\n"); return(4+2+L); break; case CQI_ReportModeAperiodic_rm22: // Table 5.2.2.6.3-2 (36.212) AssertFatal(tmode==4 || tmode==6 || tmode==8 || tmode==9 || tmode==10,"Illegal TM (%d) for CQI_ReportModeAperiodic_rm22\n",tmode); AssertFatal(tmode!=9 && tmode!=10,"TM9/10 will be handled later for CQI_ReportModeAperiodic_rm22\n"); if (ri==1 && cc->p_eNB==2) return(4+2+0+0+L+4); if (ri==2 && cc->p_eNB==2) return(4+2+4+2+L+2); if (ri==1 && cc->p_eNB==4) return(4+2+0+0+L+8); if (ri>=2 && cc->p_eNB==4) return(4+2+4+2+L+8); break; case CQI_ReportModeAperiodic_rm30: // Table 5.2.2.6.2-1 (36.212) AssertFatal(tmode==1 || tmode==2 || tmode==3 || tmode==7 || tmode==8 || tmode==9 || tmode==10,"Illegal TM (%d) for CQI_ReportModeAperiodic_rm30\n",tmode); AssertFatal(tmode!=8 && tmode!=9 && tmode!=10,"TM8/9/10 will be handled later for CQI_ReportModeAperiodic_rm30\n"); return(4+(N<<1)); break; case CQI_ReportModeAperiodic_rm31: // Table 5.2.2.6.2-2 (36.212) AssertFatal(tmode==4 || tmode==6 || tmode==8 || tmode==9 || tmode==10,"Illegal TM (%d) for CQI_ReportModeAperiodic_rm31\n",tmode); AssertFatal(tmode!=8 && tmode!=9 && tmode!=10,"TM8/9/10 will be handled later for CQI_ReportModeAperiodic_rm31\n"); if (ri==1 && cc->p_eNB==2) return(4+(N<<1)+0+0+2); else if (ri==2 && cc->p_eNB==2) return(4+(N<<1)+4+(N<<1)+1); else if (ri==1 && cc->p_eNB==4) return(4+(N<<1)+0+0+4); else if (ri>=2 && cc->p_eNB==4) return(4+(N<<1)+4+(N<<1)+4); break; case CQI_ReportModeAperiodic_rm32_v1250: AssertFatal(tmode==4 || tmode==6 || tmode==8 || tmode==9 || tmode==10,"Illegal TM (%d) for CQI_ReportModeAperiodic_rm32\n",tmode); AssertFatal(1==0,"CQI_ReportModeAperiodic_rm32_v1250 not supported yet\n"); break; case CQI_ReportModeAperiodic_rm10_v1310: // Table 5.2.2.6.1-1F/G (36.212) if (ri==1) return(4); // F else return(7); // G break; case CQI_ReportModeAperiodic_rm11_v1310: // Table 5.2.2.6.1-1H (36.212) AssertFatal(tmode==4 || tmode==6 || tmode==8 || tmode==9 || tmode==10,"Illegal TM (%d) for CQI_ReportModeAperiodic_rm11\n",tmode); AssertFatal(cc->p_eNB<=4,"only up to 4 antenna ports supported here\n"); if (ri==1 && cc->p_eNB==2) return(4+0+2); else if (ri==2 && cc->p_eNB==2) return(4+4+1); else if (ri==1 && cc->p_eNB==4) return(4+0+4); else if (ri>1 && cc->p_eNB==4) return(4+4+4); break; } AssertFatal(1==0,"Shouldn't get here\n"); return(0); } uint8_t get_rel8_dl_cqi_pmi_size(UE_sched_ctrl *sched_ctl,int CC_idP,COMMON_channels_t *cc,uint8_t tmode, struct CQI_ReportPeriodic *cqi_ReportPeriodic) { int no_pmi=0; // Ltab[6] = {0,log2(15/4/2),log2(25/4/2),log2(50/6/3),log2(75/8/4),log2(100/8/4)}; uint8_t Ltab[6] = {0,1,2,2,2,2}; uint8_t ri = sched_ctl->periodic_ri_received[CC_idP]; AssertFatal(cqi_ReportPeriodic != NULL,"cqi_ReportPeriodic is null!\n"); AssertFatal(cqi_ReportPeriodic->present != CQI_ReportPeriodic_PR_NOTHING, "cqi_ReportPeriodic->present == CQI_ReportPeriodic_PR_NOTHING!\n"); AssertFatal(cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present != CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING, "cqi_ReportPeriodic->cqi_FormatIndicatorPeriodic.choice.setup.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING!\n"); switch(tmode) { case 1: case 2: case 5: case 6: case 7: no_pmi=1; break; default: no_pmi=0; } if ((cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_widebandCQI) || (sched_ctl->feedback_cnt[CC_idP] == 0)) { // send wideband report every opportunity if wideband reporting mode is selected, else every H opportunities if (no_pmi == 1) return(4); else if ((cc->p_eNB==2) && (ri==1)) return(6); else if ((cc->p_eNB==2) && (ri==2)) return(8); else if ((cc->p_eNB==4) && (ri==1)) return(8); else if ((cc->p_eNB==4) && (ri==2)) return(11); else AssertFatal(1==0,"illegal combination p %d, ri %d, no_pmi %d\n",cc->p_eNB,ri,no_pmi); } else if (cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_subbandCQI) { if ((no_pmi == 1)||ri==1) return(4+Ltab[cc->mib->message.dl_Bandwidth]); else return(7+Ltab[cc->mib->message.dl_Bandwidth]); } AssertFatal(1==0,"Shouldn't get here : cqi_ReportPeriodic->present %d\n",cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present); } void fill_nfapi_dl_dci_1A(nfapi_dl_config_request_pdu_t *dl_config_pdu, uint8_t aggregation_level, uint16_t rnti, uint8_t rnti_type, uint8_t harq_process, uint8_t tpc, uint16_t resource_block_coding, uint8_t mcs, uint8_t ndi, uint8_t rv, uint8_t vrb_flag) { memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t)); dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; dl_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_dl_config_dci_dl_pdu)); dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1A; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = aggregation_level; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = rnti_type; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = harq_process; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = tpc; // no TPC dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = resource_block_coding; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = ndi; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = rv; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.virtual_resource_block_assignment_flag = vrb_flag; } void program_dlsch_acknak(module_id_t module_idP, int CC_idP,int UE_idP, frame_t frameP, sub_frame_t subframeP,uint8_t cce_idx) { eNB_MAC_INST *eNB = RC.mac[module_idP]; COMMON_channels_t *cc = eNB->common_channels; UE_list_t *UE_list = &eNB->UE_list; rnti_t rnti = UE_RNTI(module_idP,UE_idP); nfapi_ul_config_request_body_t *ul_req; nfapi_ul_config_request_pdu_t *ul_config_pdu; int use_simultaneous_pucch_pusch=0; nfapi_ul_config_ulsch_harq_information *ulsch_harq_information = NULL; nfapi_ul_config_harq_information *harq_information = NULL; #if defined(Rel10) || defined(Rel14) if ((UE_list->UE_template[CC_idP][UE_idP].physicalConfigDedicated->ext2) && (UE_list->UE_template[CC_idP][UE_idP].physicalConfigDedicated->ext2->pucch_ConfigDedicated_v1020) && (UE_list->UE_template[CC_idP][UE_idP].physicalConfigDedicated->ext2->pucch_ConfigDedicated_v1020->simultaneousPUCCH_PUSCH_r10) && (*UE_list->UE_template[CC_idP][UE_idP].physicalConfigDedicated->ext2->pucch_ConfigDedicated_v1020->simultaneousPUCCH_PUSCH_r10 == PUCCH_ConfigDedicated_v1020__simultaneousPUCCH_PUSCH_r10_true)) use_simultaneous_pucch_pusch=1; #endif // pucch1 and pusch feedback is similar, namely in n+k subframes from now // This is used in the following "if/else" condition to check if there isn't or is already an UL grant in n+k int16_t ul_absSF = get_pucch1_absSF(&cc[CC_idP],subframeP+(10*frameP)); if ((ul_config_pdu = has_ul_grant(module_idP,CC_idP, ul_absSF, rnti)) == NULL) { // no UL grant so // Program ACK/NAK alone Format 1a/b or 3 ul_req = &RC.mac[module_idP]->UL_req_tmp[CC_idP][ul_absSF%10].ul_config_request_body; ul_config_pdu = &ul_req->ul_config_pdu_list[ul_req->number_of_pdus]; // Do PUCCH fill_nfapi_uci_acknak(module_idP, CC_idP, rnti, (frameP*10)+subframeP, cce_idx); } else { /* there is already an existing UL grant so update it if needed * on top of some other UL resource (PUSCH,combined SR/CQI/HARQ on PUCCH, etc) */ switch(ul_config_pdu->pdu_type) { /* [ulsch] to [ulsch + harq] or [ulsch + harq on pucch] */ case NFAPI_UL_CONFIG_ULSCH_PDU_TYPE: if (use_simultaneous_pucch_pusch==1) { // Convert it to an NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE harq_information = &ul_config_pdu->ulsch_uci_harq_pdu.harq_information; ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE; LOG_D(MAC,"Frame %d, Subframe %d: Switched UCI HARQ to ULSCH UCI HARQ\n",frameP,subframeP); } else { // Convert it to an NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE ulsch_harq_information = &ul_config_pdu->ulsch_harq_pdu.harq_information; ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE; ul_config_pdu->ulsch_harq_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.n_srs_initial=0; // last symbol not punctured ul_config_pdu->ulsch_harq_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.initial_number_of_resource_blocks= ul_config_pdu->ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks; // we don't change the number of resource blocks across retransmissions yet LOG_D(MAC,"Frame %d, Subframe %d: Switched UCI HARQ to ULSCH HARQ\n",frameP,subframeP); } break; case NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE: AssertFatal(use_simultaneous_pucch_pusch == 1, "Cannot be NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE, simultaneous_pucch_pusch is active"); break; case NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE: AssertFatal(use_simultaneous_pucch_pusch == 0, "Cannot be NFAPI_UL_CONFIG_ULSCH_UCI_PDU_TYPE, simultaneous_pucch_pusch is inactive\n"); break; /* [ulsch + cqi] to [ulsch + cqi + harq] */ case NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE: // Convert it to an NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE ulsch_harq_information = &ul_config_pdu->ulsch_cqi_harq_ri_pdu.harq_information; ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE; /* TODO: check this - when converting from nfapi_ul_config_ulsch_cqi_ri_pdu to * nfapi_ul_config_ulsch_cqi_harq_ri_pdu, shouldn't we copy initial_transmission_parameters * from the one to the other? * Those two types are not compatible. 'initial_transmission_parameters' is not at the * place in both. */ ul_config_pdu->ulsch_cqi_harq_ri_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.n_srs_initial=0; // last symbol not punctured ul_config_pdu->ulsch_cqi_harq_ri_pdu.initial_transmission_parameters.initial_transmission_parameters_rel8.initial_number_of_resource_blocks= ul_config_pdu->ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks; // we don't change the number of resource blocks across retransmissions yet break; case NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE: AssertFatal(use_simultaneous_pucch_pusch == 0, "Cannot be NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE, simultaneous_pucch_pusch is active\n"); break; /* [ulsch + cqi on pucch] to [ulsch + cqi on pucch + harq on pucch] */ case NFAPI_UL_CONFIG_ULSCH_UCI_CSI_PDU_TYPE: // convert it to an NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE harq_information = &ul_config_pdu->ulsch_csi_uci_harq_pdu.harq_information; ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE; break; case NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE: AssertFatal(use_simultaneous_pucch_pusch == 1, "Cannot be NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE, simultaneous_pucch_pusch is inactive\n"); break; /* [sr] to [sr + harq] */ case NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE: // convert to NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE; harq_information = &ul_config_pdu->uci_sr_harq_pdu.harq_information; break; case NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE: /* nothing to do */ break; /* [cqi] to [cqi + harq] */ case NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE: // convert to NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE; harq_information = &ul_config_pdu->uci_cqi_harq_pdu.harq_information; break; case NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE: /* nothing to do */ break; /* [cqi + sr] to [cqr + sr + harq] */ case NFAPI_UL_CONFIG_UCI_CQI_SR_PDU_TYPE: // convert to NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE; harq_information = &ul_config_pdu->uci_cqi_sr_harq_pdu.harq_information; break; case NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE: /* nothing to do */ break; } } if (ulsch_harq_information) fill_nfapi_ulsch_harq_information(module_idP,CC_idP, rnti, ulsch_harq_information); if (harq_information) fill_nfapi_harq_information(module_idP,CC_idP, rnti, (frameP*10)+subframeP, harq_information, cce_idx); } uint8_t get_V_UL_DAI(module_id_t module_idP,int CC_idP,uint16_t rntiP) { nfapi_hi_dci0_request_body_t *HI_DCI0_req = &RC.mac[module_idP]->HI_DCI0_req[CC_idP].hi_dci0_request_body; nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = &HI_DCI0_req->hi_dci0_pdu_list[0]; for (int i=0;i<HI_DCI0_req->number_of_dci;i++) { if ((hi_dci0_pdu[i].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE)&& (hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti == rntiP)) return(hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.dl_assignment_index); } return(4); // this is rule from Section 7.3 in 36.213 } void fill_nfapi_ulsch_harq_information(module_id_t module_idP, int CC_idP, uint16_t rntiP, nfapi_ul_config_ulsch_harq_information *harq_information) { eNB_MAC_INST *eNB = RC.mac[module_idP]; COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; UE_list_t *UE_list = &eNB->UE_list; int UE_id = find_UE_id(module_idP,rntiP); PUSCH_ConfigDedicated_t *puschConfigDedicated; // PUSCH_ConfigDedicated_v1020_t *puschConfigDedicated_v1020; // PUSCH_ConfigDedicated_v1130_t *puschConfigDedicated_v1130; // PUSCH_ConfigDedicated_v1250_t *puschConfigDedicated_v1250; AssertFatal(UE_id>=0,"UE_id cannot be found, impossible\n"); AssertFatal(UE_list!=NULL,"UE_list is null\n"); AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated!=NULL,"physicalConfigDedicated for rnti %x is null\n",rntiP); AssertFatal((puschConfigDedicated = (PUSCH_ConfigDedicated_t *)UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pusch_ConfigDedicated)!=NULL,"physicalConfigDedicated->puschConfigDedicated for rnti %x is null\n",rntiP); #if defined(Rel14) || defined(Rel14) /* if (UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext2) puschConfigDedicated_v1020 = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext2->pusch_ConfigDedicated_v1020; #endif #ifdef Rel14 if (UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext4) puschConfigDedicated_v1130 = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext4->pusch_ConfigDedicated_v1130; if (UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext5) puschConfigDedicated_v1250 = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->ext5->pusch_ConfigDedicated_v1250; */ #endif harq_information->harq_information_rel10.delta_offset_harq = puschConfigDedicated->betaOffset_ACK_Index; AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated!=NULL,"pucch_ConfigDedicated is null!\n"); if ((UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode!=NULL)&& (*UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode==PUCCH_ConfigDedicated__tdd_AckNackFeedbackMode_multiplexing)) harq_information->harq_information_rel10.ack_nack_mode = 1; // multiplexing else harq_information->harq_information_rel10.ack_nack_mode = 0; // bundling switch(get_tmode(module_idP,CC_idP,UE_id)) { case 1: case 2: case 5: case 6: case 7: if (cc->tdd_Config==NULL) // FDD harq_information->harq_information_rel10.harq_size = 1; else { if (harq_information->harq_information_rel10.ack_nack_mode == 1) harq_information->harq_information_rel10.harq_size = get_V_UL_DAI(module_idP,CC_idP,rntiP); else harq_information->harq_information_rel10.harq_size = 1; } break; default: // for any other TM we need 2 bits harq if (cc->tdd_Config==NULL) { harq_information->harq_information_rel10.harq_size = 2; } else { if (harq_information->harq_information_rel10.ack_nack_mode == 1) harq_information->harq_information_rel10.harq_size = get_V_UL_DAI(module_idP,CC_idP,rntiP); else harq_information->harq_information_rel10.harq_size = 2; } break; } // get Tmode } void fill_nfapi_harq_information(module_id_t module_idP, int CC_idP, uint16_t rntiP, uint16_t absSFP, nfapi_ul_config_harq_information *harq_information, uint8_t cce_idxP) { eNB_MAC_INST *eNB = RC.mac[module_idP]; COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; UE_list_t *UE_list = &eNB->UE_list; int UE_id = find_UE_id(module_idP,rntiP); AssertFatal(UE_id>=0,"UE_id cannot be found, impossible\n"); AssertFatal(UE_list!=NULL,"UE_list is null\n"); AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated!=NULL,"physicalConfigDedicated for rnti %x is null\n",rntiP); harq_information->harq_information_rel11.num_ant_ports = 1; switch(get_tmode(module_idP,CC_idP,UE_id)) { case 1: case 2: case 5: case 6: case 7: if (cc->tdd_Config!=NULL) { AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated!=NULL, "pucch_ConfigDedicated is null for TDD!\n"); if ((UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode!=NULL)&& (*UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode==PUCCH_ConfigDedicated__tdd_AckNackFeedbackMode_multiplexing)) { harq_information->harq_information_rel10_tdd.harq_size = 2; // 2-bit ACK/NAK harq_information->harq_information_rel10_tdd.ack_nack_mode = 1; // multiplexing } else { harq_information->harq_information_rel10_tdd.harq_size = 1; // 1-bit ACK/NAK harq_information->harq_information_rel10_tdd.ack_nack_mode = 0; // bundling } harq_information->harq_information_rel10_tdd.n_pucch_1_0 = cc->radioResourceConfigCommon->pucch_ConfigCommon.n1PUCCH_AN + cce_idxP; harq_information->harq_information_rel10_tdd.number_of_pucch_resources = 1; } else { harq_information->harq_information_rel9_fdd.number_of_pucch_resources = 1; harq_information->harq_information_rel9_fdd.harq_size = 1; // 1-bit ACK/NAK harq_information->harq_information_rel9_fdd.n_pucch_1_0 = cc->radioResourceConfigCommon->pucch_ConfigCommon.n1PUCCH_AN + cce_idxP; } break; default: // for any other TM we need 2 bits harq if (cc->tdd_Config!=NULL) { AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated!=NULL, "pucch_ConfigDedicated is null for TDD!\n"); if ((UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode!=NULL)&& (*UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode==PUCCH_ConfigDedicated__tdd_AckNackFeedbackMode_multiplexing)) { harq_information->harq_information_rel10_tdd.ack_nack_mode = 1; // multiplexing } else { harq_information->harq_information_rel10_tdd.ack_nack_mode = 0; // bundling } harq_information->harq_information_rel10_tdd.harq_size = 2; harq_information->harq_information_rel10_tdd.n_pucch_1_0 = cc->radioResourceConfigCommon->pucch_ConfigCommon.n1PUCCH_AN + cce_idxP; harq_information->harq_information_rel10_tdd.number_of_pucch_resources = 1; } else { harq_information->harq_information_rel9_fdd.number_of_pucch_resources = 1; harq_information->harq_information_rel9_fdd.ack_nack_mode = 0; // 1a/b harq_information->harq_information_rel9_fdd.harq_size = 2; harq_information->harq_information_rel9_fdd.n_pucch_1_0 = cc->radioResourceConfigCommon->pucch_ConfigCommon.n1PUCCH_AN + cce_idxP; } break; } // get Tmode } uint16_t fill_nfapi_uci_acknak(module_id_t module_idP, int CC_idP, uint16_t rntiP, uint16_t absSFP, uint8_t cce_idxP) { eNB_MAC_INST *eNB = RC.mac[module_idP]; COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; int ackNAK_absSF = get_pucch1_absSF(cc,absSFP); nfapi_ul_config_request_body_t *ul_req = &eNB->UL_req_tmp[CC_idP][ackNAK_absSF%10].ul_config_request_body; nfapi_ul_config_request_pdu_t *ul_config_pdu = &ul_req->ul_config_pdu_list[ul_req->number_of_pdus]; memset((void*)ul_config_pdu,0,sizeof(nfapi_ul_config_request_pdu_t)); ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE; ul_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_ul_config_uci_harq_pdu)); ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.handle = 0; // don't know how to use this ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.rnti = rntiP; fill_nfapi_harq_information(module_idP,CC_idP, rntiP, absSFP, &ul_config_pdu->uci_harq_pdu.harq_information, cce_idxP); LOG_D(MAC,"Filled in UCI HARQ request for rnti %x SF %d.%d acknakSF %d.%d, cce_idxP %d-> n1_pucch %d\n",rntiP, absSFP/10,absSFP%10,ackNAK_absSF/10,ackNAK_absSF%10,cce_idxP,ul_config_pdu->uci_harq_pdu.harq_information.harq_information_rel9_fdd.n_pucch_1_0); ul_req->number_of_pdus++; return(((ackNAK_absSF/10)<<4) + (ackNAK_absSF%10)); } void fill_nfapi_dlsch_config(eNB_MAC_INST *eNB, nfapi_dl_config_request_body_t *dl_req, uint16_t length, uint16_t pdu_index, uint16_t rnti, uint8_t resource_allocation_type, uint8_t virtual_resource_block_assignment_flag, uint16_t resource_block_coding, uint8_t modulation, uint8_t redundancy_version, uint8_t transport_blocks, uint8_t transport_block_to_codeword_swap_flag, uint8_t transmission_scheme, uint8_t number_of_layers, uint8_t number_of_subbands, // uint8_t codebook_index, uint8_t ue_category_capacity, uint8_t pa, uint8_t delta_power_offset_index, uint8_t ngap, uint8_t nprb, uint8_t transmission_mode, uint8_t num_bf_prb_per_subband, uint8_t num_bf_vector ) { nfapi_dl_config_request_pdu_t *dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t)); dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; dl_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_dl_config_dlsch_pdu)); dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.length = length; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = pdu_index; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = rnti; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = resource_allocation_type; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = virtual_resource_block_assignment_flag; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = resource_block_coding; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = modulation; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = redundancy_version; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = transport_blocks; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = transport_block_to_codeword_swap_flag; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = transmission_scheme; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = number_of_layers; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = number_of_subbands; // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = codebook_index; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = ue_category_capacity; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = pa; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = delta_power_offset_index; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = ngap; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = nprb; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = transmission_mode; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = num_bf_prb_per_subband; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = num_bf_vector; dl_req->number_pdu++; } uint16_t fill_nfapi_tx_req(nfapi_tx_request_body_t *tx_req_body,uint16_t absSF,uint16_t pdu_length, uint16_t pdu_index, uint8_t *pdu) { nfapi_tx_request_pdu_t *TX_req = &tx_req_body->tx_pdu_list[tx_req_body->number_of_pdus]; LOG_D(MAC,"Filling TX_req %d for pdu length %d\n",tx_req_body->number_of_pdus,pdu_length); TX_req->pdu_length = pdu_length; TX_req->pdu_index = pdu_index; TX_req->num_segments = 1; TX_req->segments[0].segment_length = pdu_length; TX_req->segments[0].segment_data = pdu; tx_req_body->number_of_pdus++; return(((absSF/10)<<4) + (absSF%10)); } void fill_nfapi_ulsch_config_request_rel8(nfapi_ul_config_request_pdu_t *ul_config_pdu, uint8_t cqi_req, COMMON_channels_t *cc, struct PhysicalConfigDedicated *physicalConfigDedicated, uint8_t tmode, uint32_t handle, uint16_t rnti, uint8_t resource_block_start, uint8_t number_of_resource_blocks, uint8_t mcs, uint8_t cyclic_shift_2_for_drms, uint8_t frequency_hopping_enabled_flag, uint8_t frequency_hopping_bits, uint8_t new_data_indication, uint8_t redundancy_version, uint8_t harq_process_number, uint8_t ul_tx_mode, uint8_t current_tx_nb, uint8_t n_srs, uint16_t size ) { memset((void*)ul_config_pdu,0,sizeof(nfapi_ul_config_request_pdu_t)); ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_PDU_TYPE; ul_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_ul_config_ulsch_pdu)); ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.handle = handle; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.rnti = rnti; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.resource_block_start = resource_block_start; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.number_of_resource_blocks = number_of_resource_blocks; if (mcs<11) ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 2; else if (mcs<21) ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 4; else ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.modulation_type = 6; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.cyclic_shift_2_for_drms = cyclic_shift_2_for_drms; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_enabled_flag = frequency_hopping_enabled_flag; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.frequency_hopping_bits = frequency_hopping_bits; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.new_data_indication = new_data_indication; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.redundancy_version = redundancy_version; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.harq_process_number = harq_process_number; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.ul_tx_mode = ul_tx_mode; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.current_tx_nb = current_tx_nb; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.n_srs = n_srs; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.size = size; if (cqi_req == 1) { // Add CQI portion ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE; ul_config_pdu->pdu_size = (uint8_t)(2+sizeof(nfapi_ul_config_ulsch_cqi_ri_pdu)); ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.report_type = 1; ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.number_of_cc = 1; LOG_D(MAC,"report_type %d\n",ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.report_type); if (cc->p_eNB<=2 && (tmode==3||tmode==4||tmode==8||tmode==9||tmode==10)) ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 1; else if (cc->p_eNB<=2) ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 0; else if (cc->p_eNB==4) ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size = 2; AssertFatal(physicalConfigDedicated->cqi_ReportConfig!=NULL,"physicalConfigDedicated->cqi_ReportConfig is null!\n"); AssertFatal(physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic!=NULL,"physicalConfigDedicated->cqi_ReportModeAperiodic is null!\n"); AssertFatal(physicalConfigDedicated->pusch_ConfigDedicated!=NULL,"physicalConfigDedicated->puschConfigDedicated is null!\n"); for (int ri=0; ri<(1<<ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].ri_size); ri++) ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.aperiodic_cqi_pmi_ri_report.cc[0].dl_cqi_pmi_size[ri] = get_dl_cqi_pmi_size_pusch(cc, tmode, 1+ri, physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic); ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.delta_offset_cqi = physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_CQI_Index; ul_config_pdu->ulsch_cqi_ri_pdu.cqi_ri_information.cqi_ri_information_rel9.delta_offset_ri = physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_RI_Index; } } #ifdef Rel14 void fill_nfapi_ulsch_config_request_emtc(nfapi_ul_config_request_pdu_t *ul_config_pdu, uint8_t ue_type, uint16_t total_number_of_repetitions, uint16_t repetition_number, uint16_t initial_transmission_sf_io) { // Re13 fields ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.ue_type = ue_type; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.total_number_of_repetitions = total_number_of_repetitions; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.repetition_number = repetition_number; ul_config_pdu->ulsch_pdu.ulsch_pdu_rel13.initial_transmission_sf_io = initial_transmission_sf_io; } int get_numnarrowbands(long dl_Bandwidth) { int nb_tab[6] = {1,2,4,8,12,16}; AssertFatal(dl_Bandwidth<7 || dl_Bandwidth>=0,"dl_Bandwidth not in [0..6]\n"); return(nb_tab[dl_Bandwidth]); } int get_numnarrowbandbits(long dl_Bandwidth) { int nbbits_tab[6] = {0,1,2,3,4,4}; AssertFatal(dl_Bandwidth<7 || dl_Bandwidth>=0,"dl_Bandwidth not in [0..6]\n"); return(nbbits_tab[dl_Bandwidth]); } //This implements the frame/subframe condition for first subframe of MPDCCH transmission (Section 9.1.5 36.213, Rel 13/14) int startSF_fdd_RA_times2[8] = {2,3,4,5,8,10,16,20}; int startSF_tdd_RA[7] = {1,2,4,5,8,10,20}; int mpdcch_sf_condition(eNB_MAC_INST *eNB,int CC_id, frame_t frameP,sub_frame_t subframeP,int rmax,MPDCCH_TYPES_t mpdcch_type,int UE_id) { struct PRACH_ConfigSIB_v1310 *ext4_prach = eNB->common_channels[CC_id].radioResourceConfigCommon_BR->ext4->prach_ConfigCommon_v1310; int T; EPDCCH_SetConfig_r11_t *epdcch_setconfig_r11; switch (mpdcch_type) { case TYPE0: AssertFatal(1==0,"MPDCCH Type 0 not handled yet\n"); break; case TYPE1: AssertFatal(1==0,"MPDCCH Type 1 not handled yet\n"); break; case TYPE1A: AssertFatal(1==0,"MPDCCH Type 1A not handled yet\n"); break; case TYPE2: // RAR AssertFatal(ext4_prach->mpdcch_startSF_CSS_RA_r13!=NULL, "mpdcch_startSF_CSS_RA_r13 is null\n"); AssertFatal(rmax>0,"rmax is 0!\b"); if (eNB->common_channels[CC_id].tdd_Config==NULL) //FDD T = rmax*startSF_fdd_RA_times2[ext4_prach->mpdcch_startSF_CSS_RA_r13->choice.fdd_r13]>>1; else //TDD T = rmax*startSF_tdd_RA[ext4_prach->mpdcch_startSF_CSS_RA_r13->choice.tdd_r13]; break; case TYPE2A: AssertFatal(1==0,"MPDCCH Type 2A not handled yet\n"); break; case TYPEUESPEC: epdcch_setconfig_r11= eNB->UE_list.UE_template[CC_id][UE_id].physicalConfigDedicated->ext4->epdcch_Config_r11->config_r11.choice.setup.setConfigToAddModList_r11->list.array[0] ; AssertFatal(epdcch_setconfig_r11 != NULL," epdcch_setconfig_r11 is null for UE specific \n"); AssertFatal(epdcch_setconfig_r11->ext2 != NULL," ext2 doesn't exist in epdcch config ' \n"); if (eNB->common_channels[CC_id].tdd_Config==NULL) //FDD T = rmax*startSF_fdd_RA_times2[epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.mpdcch_StartSF_UESS_r13.choice.fdd_r13]>>1; else //TDD T = rmax*startSF_tdd_RA[epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.mpdcch_StartSF_UESS_r13.choice.tdd_r13]; break; default: return(0); } AssertFatal(T>0,"T is 0!\n"); if (((10*frameP) + subframeP)%T == 0) return(1); else return(0); } int narrowband_to_first_rb(COMMON_channels_t *cc, int nb_index) { switch (cc->mib->message.dl_Bandwidth) { case 0: // 6 PRBs, N_NB=1, i_0=0 return(0); break; case 3: // 50 PRBs, N_NB=8, i_0=1 return((int)(1+(6*nb_index))); break; case 5: // 100 PRBs, N_NB=16, i_0=2 return((int)(2+(6*nb_index))); break; case 1: // 15 PRBs N_NB=2, i_0=1 if (nb_index>0) return(1); else return(0); break; case 2: // 25 PRBs, N_NB=4, i_0=0 if (nb_index>1) return(1+(6*nb_index)); else return((6*nb_index)); break; case 4: // 75 PRBs, N_NB=12, i_0=1 if (nb_index>5) return(2+(6*nb_index)); else return(1+(6*nb_index)); break; default: AssertFatal(1==0,"Impossible dl_Bandwidth %d\n",(int)cc->mib->message.dl_Bandwidth); break; } } #endif //------------------------------------------------------------------------------ void init_ue_sched_info(void) //------------------------------------------------------------------------------ { module_id_t i,j,k; for (i=0; i<NUMBER_OF_eNB_MAX; i++) { for (k=0; k<MAX_NUM_CCs; k++) { for (j=0; j<NUMBER_OF_UE_MAX; j++) { // init DL eNB_dlsch_info[i][k][j].weight = 0; eNB_dlsch_info[i][k][j].subframe = 0; eNB_dlsch_info[i][k][j].serving_num = 0; eNB_dlsch_info[i][k][j].status = S_DL_NONE; // init UL eNB_ulsch_info[i][k][j].subframe = 0; eNB_ulsch_info[i][k][j].serving_num = 0; eNB_ulsch_info[i][k][j].status = S_UL_NONE; } } } } //------------------------------------------------------------------------------ unsigned char get_ue_weight(module_id_t module_idP, int CC_idP, int ue_idP) //------------------------------------------------------------------------------ { return(eNB_dlsch_info[module_idP][CC_idP][ue_idP].weight); } //------------------------------------------------------------------------------ int find_UE_id(module_id_t mod_idP, rnti_t rntiP) //------------------------------------------------------------------------------ { int UE_id; UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { if (UE_list->active[UE_id] != TRUE) continue; if (UE_list->UE_template[UE_PCCID(mod_idP,UE_id)][UE_id].rnti==rntiP) { return(UE_id); } } return(-1); } //------------------------------------------------------------------------------ int find_RA_id(module_id_t mod_idP, int CC_idP, rnti_t rntiP) //------------------------------------------------------------------------------ { int RA_id; AssertFatal(RC.mac[mod_idP],"RC.mac[%d] is null\n",mod_idP); RA_TEMPLATE *RA_template = (RA_TEMPLATE *)&RC.mac[mod_idP]->common_channels[CC_idP].RA_template[0]; for (RA_id = 0; RA_id < NB_RA_PROC_MAX; RA_id++) { LOG_D(MAC,"Checking RA_id %d for %x : RA_active %d, wait_ack_Msg4 %d\n", RA_id,rntiP, RA_template[RA_id].RA_active, RA_template[RA_id].wait_ack_Msg4); if (RA_template[RA_id].RA_active==TRUE && RA_template[RA_id].wait_ack_Msg4 == 0 && RA_template[RA_id].rnti == rntiP) return(RA_id); } return(-1); } //------------------------------------------------------------------------------ int UE_num_active_CC(UE_list_t *listP,int ue_idP) //------------------------------------------------------------------------------ { return(listP->numactiveCCs[ue_idP]); } //------------------------------------------------------------------------------ int UE_PCCID(module_id_t mod_idP,int ue_idP) //------------------------------------------------------------------------------ { return(RC.mac[mod_idP]->UE_list.pCC_id[ue_idP]); } //------------------------------------------------------------------------------ rnti_t UE_RNTI(module_id_t mod_idP, int ue_idP) //------------------------------------------------------------------------------ { rnti_t rnti = RC.mac[mod_idP]->UE_list.UE_template[UE_PCCID(mod_idP,ue_idP)][ue_idP].rnti; if (rnti>0) { return (rnti); } LOG_D(MAC,"[eNB %d] Couldn't find RNTI for UE %d\n",mod_idP,ue_idP); //display_backtrace(); return(NOT_A_RNTI); } //------------------------------------------------------------------------------ boolean_t is_UE_active(module_id_t mod_idP, int ue_idP) //------------------------------------------------------------------------------ { return(RC.mac[mod_idP]->UE_list.active[ue_idP]); } /* uint8_t find_active_UEs(module_id_t module_idP,int CC_id){ module_id_t ue_mod_id = 0; rnti_t rnti = 0; uint8_t nb_active_ue = 0; for (ue_mod_id=0;ue_mod_id<NUMBER_OF_UE_MAX;ue_mod_id++) { if (((rnti=eNB_mac_inst[module_idP][CC_id].UE_template[ue_mod_id].rnti) !=0)&&(eNB_mac_inst[module_idP][CC_id].UE_template[ue_mod_id].ul_active==TRUE)){ if (mac_xface->get_eNB_UE_stats(module_idP,rnti) != NULL){ // check at the phy enb_ue state for this rnti nb_active_ue++; } else { // this ue is removed at the phy => remove it at the mac as well mac_remove_ue(module_idP, CC_id, ue_mod_id); } } } return(nb_active_ue); } */ // get aggregation (L) form phy for a give UE unsigned char get_aggregation (uint8_t bw_index, uint8_t cqi, uint8_t dci_fmt) { unsigned char aggregation=3; switch (dci_fmt){ case format0: aggregation = cqi2fmt0_agg[bw_index][cqi]; break; case format1: case format1A: case format1B: case format1D: aggregation = cqi2fmt1x_agg[bw_index][cqi]; break; case format2: case format2A: case format2B: case format2C: case format2D: aggregation = cqi2fmt2x_agg[bw_index][cqi]; break; case format1C: case format1E_2A_M10PRB: case format3: case format3A: case format4: default: LOG_W(MAC,"unsupported DCI format %d\n",dci_fmt); } LOG_D(MAC,"Aggregation level %d (cqi %d, bw_index %d, format %d)\n", 1<<aggregation, cqi,bw_index,dci_fmt); return 1<<aggregation; } void dump_ue_list(UE_list_t *listP, int ul_flag) { int j; if ( ul_flag == 0 ) { for (j=listP->head; j>=0; j=listP->next[j]) { LOG_T(MAC,"node %d => %d\n",j,listP->next[j]); } } else { for (j=listP->head_ul; j>=0; j=listP->next_ul[j]) { LOG_T(MAC,"node %d => %d\n",j,listP->next_ul[j]); } } } int add_new_ue(module_id_t mod_idP, int cc_idP, rnti_t rntiP,int harq_pidP #ifdef Rel14 ,uint8_t rach_resource_type #endif ) { int UE_id; int i, j; UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; LOG_D(MAC,"[eNB %d, CC_id %d] Adding UE with rnti %x (next avail %d, num_UEs %d)\n",mod_idP,cc_idP,rntiP,UE_list->avail,UE_list->num_UEs); dump_ue_list(UE_list,0); for (i = 0; i < NUMBER_OF_UE_MAX; i++) { if (UE_list->active[i] == TRUE) continue; UE_id = i; UE_list->UE_template[cc_idP][UE_id].rnti = rntiP; UE_list->UE_template[cc_idP][UE_id].configured = FALSE; UE_list->numactiveCCs[UE_id] = 1; UE_list->numactiveULCCs[UE_id] = 1; UE_list->pCC_id[UE_id] = cc_idP; UE_list->ordered_CCids[0][UE_id] = cc_idP; UE_list->ordered_ULCCids[0][UE_id] = cc_idP; UE_list->num_UEs++; UE_list->active[UE_id] = TRUE; #ifdef Rel14 UE_list->UE_template[cc_idP][UE_id].rach_resource_type = rach_resource_type ; #endif memset((void*)&UE_list->UE_sched_ctrl[UE_id],0,sizeof(UE_sched_ctrl)); memset((void*)&UE_list->eNB_UE_stats[cc_idP][UE_id],0,sizeof(eNB_UE_STATS)); UE_list->UE_sched_ctrl[UE_id].ta_update = 31; for (j=0; j<8; j++) { UE_list->UE_template[cc_idP][UE_id].oldNDI[j] = (j==0)?1:0; // 1 because first transmission is with format1A (Msg4) for harq_pid 0 UE_list->UE_template[cc_idP][UE_id].oldNDI_UL[j] = (j==harq_pidP)?0:1; // 1st transmission is with Msg3; UE_list->UE_sched_ctrl[UE_id].round[cc_idP][j] = 8; UE_list->UE_sched_ctrl[UE_id].round_UL[cc_idP][j] = 0; } eNB_ulsch_info[mod_idP][cc_idP][UE_id].status = S_UL_WAITING; eNB_dlsch_info[mod_idP][cc_idP][UE_id].status = S_DL_WAITING; LOG_D(MAC,"[eNB %d] Add UE_id %d on Primary CC_id %d: rnti %x\n",mod_idP,UE_id,cc_idP,rntiP); dump_ue_list(UE_list,0); return(UE_id); } printf("MAC: cannot add new UE for rnti %x\n", rntiP); LOG_E(MAC,"error in add_new_ue(), could not find space in UE_list, Dumping UE list\n"); dump_ue_list(UE_list,0); return(-1); } //------------------------------------------------------------------------------ int rrc_mac_remove_ue(module_id_t mod_idP,rnti_t rntiP) //------------------------------------------------------------------------------ { int i; UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; int UE_id = find_UE_id(mod_idP,rntiP); int pCC_id; if (UE_id == -1) { LOG_W(MAC,"rrc_mac_remove_ue: UE %x not found\n", rntiP); return 0; } pCC_id = UE_PCCID(mod_idP,UE_id); LOG_I(MAC,"Removing UE %d from Primary CC_id %d (rnti %x)\n",UE_id,pCC_id, rntiP); dump_ue_list(UE_list,0); UE_list->active[UE_id] = FALSE; UE_list->num_UEs--; if (UE_list->head == UE_id) UE_list->head=UE_list->next[UE_id]; else UE_list->next[prev(UE_list,UE_id,0)]=UE_list->next[UE_id]; if (UE_list->head_ul == UE_id) UE_list->head_ul=UE_list->next_ul[UE_id]; else UE_list->next_ul[prev(UE_list,UE_id,0)]=UE_list->next_ul[UE_id]; // clear all remaining pending transmissions UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID0] = 0; UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID1] = 0; UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID2] = 0; UE_list->UE_template[pCC_id][UE_id].bsr_info[LCGID3] = 0; UE_list->UE_template[pCC_id][UE_id].ul_SR = 0; UE_list->UE_template[pCC_id][UE_id].rnti = NOT_A_RNTI; UE_list->UE_template[pCC_id][UE_id].ul_active = FALSE; eNB_ulsch_info[mod_idP][pCC_id][UE_id].rnti = NOT_A_RNTI; eNB_ulsch_info[mod_idP][pCC_id][UE_id].status = S_UL_NONE; eNB_dlsch_info[mod_idP][pCC_id][UE_id].rnti = NOT_A_RNTI; eNB_dlsch_info[mod_idP][pCC_id][UE_id].status = S_DL_NONE; // check if this has an RA process active RA_TEMPLATE *RA_template; for (i=0;i<NB_RA_PROC_MAX;i++) { RA_template = (RA_TEMPLATE *)&RC.mac[mod_idP]->common_channels[pCC_id].RA_template[i]; if (RA_template->rnti == rntiP){ RA_template->RA_active=FALSE; RA_template->generate_rar=0; RA_template->generate_Msg4=0; RA_template->wait_ack_Msg4=0; RA_template->timing_offset=0; RA_template->RRC_timer=20; RA_template->rnti = 0; //break; } } return 0; } int prev(UE_list_t *listP, int nodeP, int ul_flag) { int j; if (ul_flag == 0 ) { if (nodeP==listP->head) { return(nodeP); } for (j=listP->head; j>=0; j=listP->next[j]) { if (listP->next[j]==nodeP) { return(j); } } } else { if (nodeP==listP->head_ul) { return(nodeP); } for (j=listP->head_ul; j>=0; j=listP->next_ul[j]) { if (listP->next_ul[j]==nodeP) { return(j); } } } LOG_E(MAC,"error in prev(), could not find previous to %d in UE_list %s, should never happen, Dumping UE list\n", nodeP, (ul_flag == 0)? "DL" : "UL"); dump_ue_list(listP, ul_flag); return(-1); } void swap_UEs(UE_list_t *listP,int nodeiP, int nodejP, int ul_flag) { int prev_i,prev_j,next_i,next_j; LOG_T(MAC,"Swapping UE %d,%d\n",nodeiP,nodejP); dump_ue_list(listP,ul_flag); prev_i = prev(listP,nodeiP,ul_flag); prev_j = prev(listP,nodejP,ul_flag); AssertFatal((prev_i>=0) && (prev_j>=0), "swap_UEs: problem"); if (ul_flag == 0) { next_i = listP->next[nodeiP]; next_j = listP->next[nodejP]; } else { next_i = listP->next_ul[nodeiP]; next_j = listP->next_ul[nodejP]; } LOG_T(MAC,"[%s] next_i %d, next_i, next_j %d, head %d \n", (ul_flag == 0)? "DL" : "UL", next_i,next_j,listP->head); if (ul_flag == 0 ) { if (next_i == nodejP) { // case ... p(i) i j n(j) ... => ... p(j) j i n(i) ... LOG_T(MAC,"Case ... p(i) i j n(j) ... => ... p(j) j i n(i) ...\n"); listP->next[nodeiP] = next_j; listP->next[nodejP] = nodeiP; if (nodeiP==listP->head) { // case i j n(j) listP->head = nodejP; } else { listP->next[prev_i] = nodejP; } } else if (next_j == nodeiP) { // case ... p(j) j i n(i) ... => ... p(i) i j n(j) ... LOG_T(MAC,"Case ... p(j) j i n(i) ... => ... p(i) i j n(j) ...\n"); listP->next[nodejP] = next_i; listP->next[nodeiP] = nodejP; if (nodejP==listP->head) { // case j i n(i) listP->head = nodeiP; } else { listP->next[prev_j] = nodeiP; } } else { // case ... p(i) i n(i) ... p(j) j n(j) ... listP->next[nodejP] = next_i; listP->next[nodeiP] = next_j; if (nodeiP==listP->head) { LOG_T(MAC,"changing head to %d\n",nodejP); listP->head=nodejP; listP->next[prev_j] = nodeiP; } else if (nodejP==listP->head) { LOG_D(MAC,"changing head to %d\n",nodeiP); listP->head=nodeiP; listP->next[prev_i] = nodejP; } else { listP->next[prev_i] = nodejP; listP->next[prev_j] = nodeiP; } } } else { // ul_flag if (next_i == nodejP) { // case ... p(i) i j n(j) ... => ... p(j) j i n(i) ... LOG_T(MAC,"[UL] Case ... p(i) i j n(j) ... => ... p(j) j i n(i) ...\n"); listP->next_ul[nodeiP] = next_j; listP->next_ul[nodejP] = nodeiP; if (nodeiP==listP->head_ul) { // case i j n(j) listP->head_ul = nodejP; } else { listP->next_ul[prev_i] = nodejP; } } else if (next_j == nodeiP) { // case ... p(j) j i n(i) ... => ... p(i) i j n(j) ... LOG_T(MAC,"[UL]Case ... p(j) j i n(i) ... => ... p(i) i j n(j) ...\n"); listP->next_ul[nodejP] = next_i; listP->next_ul[nodeiP] = nodejP; if (nodejP==listP->head_ul) { // case j i n(i) listP->head_ul = nodeiP; } else { listP->next_ul[prev_j] = nodeiP; } } else { // case ... p(i) i n(i) ... p(j) j n(j) ... listP->next_ul[nodejP] = next_i; listP->next_ul[nodeiP] = next_j; if (nodeiP==listP->head_ul) { LOG_T(MAC,"[UL]changing head to %d\n",nodejP); listP->head_ul=nodejP; listP->next_ul[prev_j] = nodeiP; } else if (nodejP==listP->head_ul) { LOG_T(MAC,"[UL]changing head to %d\n",nodeiP); listP->head_ul=nodeiP; listP->next_ul[prev_i] = nodejP; } else { listP->next_ul[prev_i] = nodejP; listP->next_ul[prev_j] = nodeiP; } } } LOG_T(MAC,"After swap\n"); dump_ue_list(listP,ul_flag); } /* #if defined(Rel10) || defined(Rel14) unsigned char generate_mch_header( unsigned char *mac_header, unsigned char num_sdus, unsigned short *sdu_lengths, unsigned char *sdu_lcids, unsigned char msi, unsigned char short_padding, unsigned short post_padding) { SCH_SUBHEADER_FIXED *mac_header_ptr = (SCH_SUBHEADER_FIXED *)mac_header; uint8_t first_element=0,last_size=0,i; uint8_t mac_header_control_elements[2*num_sdus],*ce_ptr; ce_ptr = &mac_header_control_elements[0]; if ((short_padding == 1) || (short_padding == 2)) { mac_header_ptr->R = 0; mac_header_ptr->E = 0; mac_header_ptr->LCID = SHORT_PADDING; first_element=1; last_size=1; } if (short_padding == 2) { mac_header_ptr->E = 1; mac_header_ptr++; mac_header_ptr->R = 0; mac_header_ptr->E = 0; mac_header_ptr->LCID = SHORT_PADDING; last_size=1; } // SUBHEADER for MSI CE if (msi != 0) {// there is MSI MAC Control Element if (first_element>0) { mac_header_ptr->E = 1; mac_header_ptr+=last_size; } else { first_element = 1; } if (num_sdus*2 < 128) { ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->R = 0; ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->E = 0; ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->F = 0; ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->LCID = MCH_SCHDL_INFO; ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->L = num_sdus*2; last_size=2; } else { ((SCH_SUBHEADER_LONG *)mac_header_ptr)->R = 0; ((SCH_SUBHEADER_LONG *)mac_header_ptr)->E = 0; ((SCH_SUBHEADER_LONG *)mac_header_ptr)->F = 1; ((SCH_SUBHEADER_LONG *)mac_header_ptr)->LCID = MCH_SCHDL_INFO; ((SCH_SUBHEADER_LONG *)mac_header_ptr)->L = (num_sdus*2)&0x7fff; last_size=3; } // Create the MSI MAC Control Element here } // SUBHEADER for MAC SDU (MCCH+MTCHs) for (i=0;i<num_sdus;i++) { if (first_element>0) { mac_header_ptr->E = 1; mac_header_ptr+=last_size; } else { first_element = 1; } if (sdu_lengths[i] < 128) { ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->R = 0; ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->E = 0; ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->F = 0; ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->LCID = sdu_lcids[i]; ((SCH_SUBHEADER_SHORT *)mac_header_ptr)->L = (unsigned char)sdu_lengths[i]; last_size=2; } else { ((SCH_SUBHEADER_LONG *)mac_header_ptr)->R = 0; ((SCH_SUBHEADER_LONG *)mac_header_ptr)->E = 0; ((SCH_SUBHEADER_LONG *)mac_header_ptr)->F = 1; ((SCH_SUBHEADER_LONG *)mac_header_ptr)->LCID = sdu_lcids[i]; ((SCH_SUBHEADER_LONG *)mac_header_ptr)->L = (unsigned short) sdu_lengths[i]&0x7fff; last_size=3; } } if (post_padding>0) {// we have lots of padding at the end of the packet mac_header_ptr->E = 1; mac_header_ptr+=last_size; // add a padding element mac_header_ptr->R = 0; mac_header_ptr->E = 0; mac_header_ptr->LCID = SHORT_PADDING; mac_header_ptr++; } else { // no end of packet padding // last SDU subhead is of fixed type (sdu length implicitly to be computed at UE) mac_header_ptr++; } // Copy MSI Control Element to the end of the MAC Header if it presents if ((ce_ptr-mac_header_control_elements) > 0) { // printf("Copying %d bytes for control elements\n",ce_ptr-mac_header_control_elements); memcpy((void*)mac_header_ptr,mac_header_control_elements,ce_ptr-mac_header_control_elements); mac_header_ptr+=(unsigned char)(ce_ptr-mac_header_control_elements); } return((unsigned char*)mac_header_ptr - mac_header); } #endif */ // This has to be updated to include BSR information uint8_t UE_is_to_be_scheduled(module_id_t module_idP,int CC_id,uint8_t UE_id) { UE_TEMPLATE *UE_template = &RC.mac[module_idP]->UE_list.UE_template[CC_id][UE_id]; UE_sched_ctrl *UE_sched_ctl = &RC.mac[module_idP]->UE_list.UE_sched_ctrl[UE_id]; // do not schedule UE if UL is not working if (UE_sched_ctl->ul_failure_timer>0) return(0); if (UE_sched_ctl->ul_out_of_sync>0) return(0); LOG_D(MAC,"[eNB %d][PUSCH] Checking UL requirements UE %d/%x\n",module_idP,UE_id,UE_RNTI(module_idP,UE_id)); if ((UE_template->bsr_info[LCGID0]>0) || (UE_template->bsr_info[LCGID1]>0) || (UE_template->bsr_info[LCGID2]>0) || (UE_template->bsr_info[LCGID3]>0) || (UE_template->ul_SR>0) || // uplink scheduling request ((UE_sched_ctl->ul_inactivity_timer>20)&& (UE_sched_ctl->ul_scheduled==0))|| // every 2 frames when RRC_CONNECTED ((UE_sched_ctl->ul_inactivity_timer>10)&& (UE_sched_ctl->ul_scheduled==0)&& (mac_eNB_get_rrc_status(module_idP,UE_RNTI(module_idP,UE_id)) < RRC_CONNECTED))) // every Frame when not RRC_CONNECTED { LOG_D(MAC,"[eNB %d][PUSCH] UE %d/%x should be scheduled (BSR0 %d,SR %d)\n",module_idP,UE_id,UE_RNTI(module_idP,UE_id), UE_template->bsr_info[LCGID0], UE_template->ul_SR); return(1); } else { return(0); } } uint8_t get_tmode(module_id_t module_idP,int CC_idP,int UE_idP) { eNB_MAC_INST *eNB = RC.mac[module_idP]; COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; struct PhysicalConfigDedicated *physicalConfigDedicated = eNB->UE_list.physicalConfigDedicated[CC_idP][UE_idP]; if (physicalConfigDedicated == NULL ) { // RRCConnectionSetup not received by UE yet AssertFatal(cc->p_eNB<=2,"p_eNB is %d, should be <2\n",cc->p_eNB); return(cc->p_eNB); } else { AssertFatal(physicalConfigDedicated->antennaInfo!=NULL, "antennaInfo is null for CCId %d, UEid %d\n",CC_idP,UE_idP); AssertFatal(physicalConfigDedicated->antennaInfo->present != PhysicalConfigDedicated__antennaInfo_PR_NOTHING, "antennaInfo (mod_id %d, CC_id %d) is set to NOTHING\n",module_idP,CC_idP); if (physicalConfigDedicated->antennaInfo->present == PhysicalConfigDedicated__antennaInfo_PR_explicitValue) { return(physicalConfigDedicated->antennaInfo->choice.explicitValue.transmissionMode); } else if (physicalConfigDedicated->antennaInfo->present == PhysicalConfigDedicated__antennaInfo_PR_defaultValue) { AssertFatal(cc->p_eNB<=2,"p_eNB is %d, should be <2\n",cc->p_eNB); return(cc->p_eNB); } else AssertFatal(1==0,"Shouldn't be here\n"); } } int8_t get_ULharq(module_id_t module_idP,int CC_idP,uint16_t frameP,uint8_t subframeP) { uint8_t ret = -1; eNB_MAC_INST *eNB = RC.mac[module_idP]; COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; if (cc->tdd_Config==NULL) { // FDD ret = (((frameP<<1)+subframeP)&7); } else { switch (cc->tdd_Config->subframeAssignment) { case 1: if ((subframeP==2) || (subframeP==3) || (subframeP==7) || (subframeP==8)) switch (subframeP) { case 2: case 3: ret = (subframeP-2); break; case 7: case 8: ret = (subframeP-5); break; default: AssertFatal(1==0,"subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",subframeP,(int)cc->tdd_Config->subframeAssignment); break; } break; case 2: AssertFatal((subframeP==2) || (subframeP==7), "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",subframeP,(int)cc->tdd_Config->subframeAssignment); ret = (subframeP/7); break; case 3: AssertFatal((subframeP>1) && (subframeP<5), "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",subframeP,(int)cc->tdd_Config->subframeAssignment); ret = (subframeP-2); break; case 4: AssertFatal((subframeP>1) && (subframeP<4), "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",subframeP,(int)cc->tdd_Config->subframeAssignment); ret = (subframeP-2); break; case 5: AssertFatal(subframeP==2, "subframe2_harq_pid, Illegal subframe %d for TDD mode %d\n",subframeP,(int)cc->tdd_Config->subframeAssignment); ret = (subframeP-2); break; default: AssertFatal(1==0,"subframe2_harq_pid, Unsupported TDD mode %d\n",(int)cc->tdd_Config->subframeAssignment); break; } } AssertFatal(ret!=-1, "invalid harq_pid(%d) at SFN/SF = %d/%d\n", (int8_t)ret, frameP, subframeP); return ret; } uint16_t getRIV(uint16_t N_RB_DL,uint16_t RBstart,uint16_t Lcrbs) { uint16_t RIV; if (Lcrbs<=(1+(N_RB_DL>>1))) RIV = (N_RB_DL*(Lcrbs-1)) + RBstart; else RIV = (N_RB_DL*(N_RB_DL+1-Lcrbs)) + (N_RB_DL-1-RBstart); return(RIV); } uint32_t allocate_prbs(int UE_id,unsigned char nb_rb, int N_RB_DL, uint32_t *rballoc) { int i; uint32_t rballoc_dci=0; unsigned char nb_rb_alloc=0; for (i=0; i<(N_RB_DL-2); i+=2) { if (((*rballoc>>i)&3)==0) { *rballoc |= (3<<i); rballoc_dci |= (1<<((12-i)>>1)); nb_rb_alloc+=2; } if (nb_rb_alloc==nb_rb) { return(rballoc_dci); } } if ((N_RB_DL&1)==1) { if ((*rballoc>>(N_RB_DL-1)&1)==0) { *rballoc |= (1<<(N_RB_DL-1)); rballoc_dci |= 1; } } return(rballoc_dci); } int get_bw_index(module_id_t module_id, uint8_t CC_id) { int bw_index=0; int N_RB_DL = to_prb(RC.mac[module_id]->common_channels[CC_id].mib->message.dl_Bandwidth); switch (N_RB_DL) { case 6: // 1.4 MHz bw_index=0; break; case 25: // 5HMz bw_index=1; break; case 50: // 10HMz bw_index=2; break; case 100: // 20HMz bw_index=3; break; default: bw_index=1; LOG_W(MAC,"[eNB %d] N_RB_DL %d unknown for CC_id %d, setting bw_index to 1\n", module_id, N_RB_DL,CC_id); break; } return bw_index; } int get_min_rb_unit(module_id_t module_id, uint8_t CC_id) { int min_rb_unit=0; int N_RB_DL = to_prb(RC.mac[module_id]->common_channels[CC_id].mib->message.dl_Bandwidth); switch (N_RB_DL) { case 6: // 1.4 MHz min_rb_unit=1; break; case 25: // 5HMz min_rb_unit=2; break; case 50: // 10HMz min_rb_unit=3; break; case 100: // 20HMz min_rb_unit=4; break; default: min_rb_unit=2; LOG_W(MAC,"[eNB %d] N_DL_RB %d unknown for CC_id %d, setting min_rb_unit to 2\n", module_id, N_RB_DL, CC_id); break; } return min_rb_unit; } uint32_t allocate_prbs_sub(int nb_rb, int N_RB_DL, int N_RBG, uint8_t *rballoc) { int check=0;//check1=0,check2=0; uint32_t rballoc_dci=0; //uint8_t number_of_subbands=13; LOG_T(MAC,"*****Check1RBALLOC****: %d%d%d%d (nb_rb %d,N_RBG %d)\n", rballoc[3],rballoc[2],rballoc[1],rballoc[0],nb_rb,N_RBG); while((nb_rb >0) && (check < N_RBG)) { //printf("rballoc[%d] %d\n",check,rballoc[check]); if(rballoc[check] == 1) { rballoc_dci |= (1<<((N_RBG-1)-check)); switch (N_RB_DL) { case 6: nb_rb--; break; case 25: if ((check == N_RBG-1)) { nb_rb--; } else { nb_rb-=2; } break; case 50: if ((check == N_RBG-1)) { nb_rb-=2; } else { nb_rb-=3; } break; case 100: nb_rb-=4; break; } } // printf("rb_alloc %x\n",rballoc_dci); check = check+1; // check1 = check1+2; } // rballoc_dci = (rballoc_dci)&(0x1fff); LOG_T(MAC,"*********RBALLOC : %x\n",rballoc_dci); // exit(-1); return (rballoc_dci); } int get_subbandsize(uint8_t dl_Bandwidth) { uint8_t ss[6] = {6,4,4,6,8,8}; AssertFatal(dl_Bandwidth<6,"dl_Bandwidth %d is out of bounds\n",dl_Bandwidth); return(ss[dl_Bandwidth]); } int get_nb_subband(int N_RB_DL) { int nb_sb=0; switch (N_RB_DL) { case 6: nb_sb=0; break; case 15: nb_sb = 4; // sb_size =4 case 25: nb_sb = 7; // sb_size =4, 1 sb with 1PRB, 6 with 2 RBG, each has 2 PRBs break; case 50: // sb_size =6 nb_sb = 9; break; case 75: // sb_size =8 nb_sb = 10; break; case 100: // sb_size =8 , 1 sb with 1 RBG + 12 sb with 2RBG, each RBG has 4 PRBs nb_sb = 13; break; default: nb_sb=0; break; } return nb_sb; } void init_CCE_table(int module_idP,int CC_idP) { memset(RC.mac[module_idP]->CCE_table[CC_idP],0,800*sizeof(int)); } int get_nCCE_offset(int *CCE_table, const unsigned char L, const int nCCE, const int common_dci, const unsigned short rnti, const unsigned char subframe) { int search_space_free,m,nb_candidates = 0,l,i; unsigned int Yk; /* printf("CCE Allocation: "); for (i=0;i<nCCE;i++) printf("%d.",CCE_table[i]); printf("\n"); */ if (common_dci == 1) { // check CCE(0 ... L-1) nb_candidates = (L==4) ? 4 : 2; nb_candidates = min(nb_candidates,nCCE/L); // printf("Common DCI nb_candidates %d, L %d\n",nb_candidates,L); for (m = nb_candidates-1 ; m >=0 ; m--) { search_space_free = 1; for (l=0; l<L; l++) { // printf("CCE_table[%d] %d\n",(m*L)+l,CCE_table[(m*L)+l]); if (CCE_table[(m*L) + l] == 1) { search_space_free = 0; break; } } if (search_space_free == 1) { // printf("returning %d\n",m*L); for (l=0; l<L; l++) CCE_table[(m*L)+l]=1; return(m*L); } } return(-1); } else { // Find first available in ue specific search space // according to procedure in Section 9.1.1 of 36.213 (v. 8.6) // compute Yk Yk = (unsigned int)rnti; for (i=0; i<=subframe; i++) Yk = (Yk*39827)%65537; Yk = Yk % (nCCE/L); switch (L) { case 1: case 2: nb_candidates = 6; break; case 4: case 8: nb_candidates = 2; break; default: DevParam(L, nCCE, rnti); break; } LOG_D(MAC,"rnti %x, Yk = %d, nCCE %d (nCCE/L %d),nb_cand %d\n",rnti,Yk,nCCE,nCCE/L,nb_candidates); for (m = 0 ; m < nb_candidates ; m++) { search_space_free = 1; for (l=0; l<L; l++) { int cce = (((Yk+m)%(nCCE/L))*L) + l; if (cce >= nCCE || CCE_table[cce] == 1) { search_space_free = 0; break; } } if (search_space_free == 1) { for (l=0; l<L; l++) CCE_table[(((Yk+m)%(nCCE/L))*L)+l]=1; return(((Yk+m)%(nCCE/L))*L); } } return(-1); } } void dump_CCE_table(int *CCE_table,const int nCCE,const unsigned short rnti,const int subframe,int L) { int nb_candidates = 0,i; unsigned int Yk; printf("CCE 0: "); for (i=0;i<nCCE;i++) { printf("%1d.",CCE_table[i]); if ((i&7) == 7) printf("\n CCE %d: ",i); } Yk = (unsigned int)rnti; for (i=0; i<=subframe; i++) Yk = (Yk*39827)%65537; Yk = Yk % (nCCE/L); switch (L) { case 1: case 2: nb_candidates = 6; break; case 4: case 8: nb_candidates = 2; break; default: DevParam(L, nCCE, rnti); break; } printf("rnti %x, Yk*L = %d, nCCE %d (nCCE/L %d),nb_cand*L %d\n",rnti,Yk*L,nCCE,nCCE/L,nb_candidates*L); } uint16_t getnquad(COMMON_channels_t *cc, uint8_t num_pdcch_symbols,uint8_t mi) { uint16_t Nreg=0; AssertFatal(cc!=NULL,"cc is null\n"); AssertFatal(cc->mib!=NULL,"cc->mib is null\n"); int N_RB_DL = to_prb(cc->mib->message.dl_Bandwidth); int phich_resource = get_phich_resource_times6(cc); uint8_t Ngroup_PHICH = (phich_resource*N_RB_DL)/48; if (((phich_resource*N_RB_DL)%48) > 0) Ngroup_PHICH++; if (cc->Ncp == 1) { Ngroup_PHICH<<=1; } Ngroup_PHICH*=mi; if ((num_pdcch_symbols>0) && (num_pdcch_symbols<4)) switch (N_RB_DL) { case 6: Nreg=12+(num_pdcch_symbols-1)*18; break; case 25: Nreg=50+(num_pdcch_symbols-1)*75; break; case 50: Nreg=100+(num_pdcch_symbols-1)*150; break; case 100: Nreg=200+(num_pdcch_symbols-1)*300; break; default: return(0); } // printf("Nreg %d (%d)\n",Nreg,Nreg - 4 - (3*Ngroup_PHICH)); return(Nreg - 4 - (3*Ngroup_PHICH)); } uint16_t getnCCE(COMMON_channels_t *cc, uint8_t num_pdcch_symbols, uint8_t mi) { AssertFatal(cc!=NULL,"cc is null\n"); return(getnquad(cc,num_pdcch_symbols,mi)/9); } uint8_t getmi(COMMON_channels_t *cc,int subframe) { AssertFatal(cc!=NULL,"cc is null\n"); // for FDD if (cc->tdd_Config==NULL) // FDD return 1; // for TDD switch (cc->tdd_Config->subframeAssignment) { case 0: if ((subframe==0) || (subframe==5)) return(2); else return(1); break; case 1: if ((subframe==0) || (subframe==5)) return(0); else return(1); break; case 2: if ((subframe==3) || (subframe==8)) return(1); else return(0); break; case 3: if ((subframe==0) || (subframe==8) || (subframe==9)) return(1); else return(0); break; case 4: if ((subframe==8) || (subframe==9)) return(1); else return(0); break; case 5: if (subframe==8) return(1); else return(0); break; case 6: return(1); break; default: return(0); } } uint16_t get_nCCE_max(COMMON_channels_t *cc, int num_pdcch_symbols,int subframe) { AssertFatal(cc!=NULL,"cc is null\n"); return(getnCCE(cc,num_pdcch_symbols, getmi(cc,subframe))); } // Allocate the CCEs int allocate_CCEs(int module_idP, int CC_idP, int subframeP, int test_onlyP) { int *CCE_table = RC.mac[module_idP]->CCE_table[CC_idP]; nfapi_dl_config_request_body_t *DL_req = &RC.mac[module_idP]->DL_req[CC_idP].dl_config_request_body; nfapi_hi_dci0_request_body_t *HI_DCI0_req = &RC.mac[module_idP]->HI_DCI0_req[CC_idP].hi_dci0_request_body; nfapi_dl_config_request_pdu_t *dl_config_pdu = &DL_req->dl_config_pdu_list[0]; nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = &HI_DCI0_req->hi_dci0_pdu_list[0]; int nCCE_max = get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP],1,subframeP); int fCCE; int i,j,idci; int nCCE=0; LOG_D(MAC,"Allocate CCEs subframe %d, test %d : (DL PDU %d, DL DCI %d, UL %d)\n",subframeP,test_onlyP,DL_req->number_pdu,DL_req->number_dci,HI_DCI0_req->number_of_dci); DL_req->number_pdcch_ofdm_symbols=1; try_again: init_CCE_table(module_idP,CC_idP); nCCE=0; for (i=0,idci=0;i<DL_req->number_pdu;i++) { // allocate DL common DCIs first if ((dl_config_pdu[i].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE)&& (dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti_type==2) ) { LOG_D(MAC,"Trying to allocate COMMON DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", idci,DL_req->number_dci+HI_DCI0_req->number_of_dci, DL_req->number_dci,HI_DCI0_req->number_of_dci, dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti, dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, nCCE,nCCE_max, DL_req->number_pdcch_ofdm_symbols); if (nCCE + (dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level) > nCCE_max) { if (DL_req->number_pdcch_ofdm_symbols == 3) goto failed; LOG_D(MAC,"Can't fit DCI allocations with %d PDCCH symbols, increasing by 1\n",DL_req->number_pdcch_ofdm_symbols); DL_req->number_pdcch_ofdm_symbols++; nCCE_max = get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP],DL_req->number_pdcch_ofdm_symbols,subframeP); goto try_again; } // number of CCEs left can potentially hold this allocation fCCE = get_nCCE_offset(CCE_table, dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, nCCE_max, 1, dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti, subframeP); if (fCCE == -1) { if (DL_req->number_pdcch_ofdm_symbols == 3) { LOG_D(MAC,"subframe %d: Dropping Allocation for RNTI %x\n", subframeP,dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti); for (j=0;j<=i;j++){ if (dl_config_pdu[j].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) LOG_D(MAC,"DCI %d/%d (%d,%d) : rnti %x dci format %d, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", j,DL_req->number_dci+HI_DCI0_req->number_of_dci, DL_req->number_dci,HI_DCI0_req->number_of_dci, dl_config_pdu[j].dci_dl_pdu.dci_dl_pdu_rel8.rnti, dl_config_pdu[j].dci_dl_pdu.dci_dl_pdu_rel8.dci_format, dl_config_pdu[j].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, nCCE,nCCE_max,DL_req->number_pdcch_ofdm_symbols); } //dump_CCE_table(CCE_table,nCCE_max,subframeP,dci_alloc->rnti,1<<dci_alloc->L); goto failed; } LOG_D(MAC,"Can't fit DCI allocations with %d PDCCH symbols (rnti condition), increasing by 1\n",DL_req->number_pdcch_ofdm_symbols); DL_req->number_pdcch_ofdm_symbols++; nCCE_max = get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP],DL_req->number_pdcch_ofdm_symbols,subframeP); goto try_again; } // fCCE==-1 // the allocation is feasible, rnti rule passes nCCE += dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level; LOG_D(MAC,"Allocating at nCCE %d\n",fCCE); if (test_onlyP == 0) { dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.cce_idx=fCCE; LOG_D(MAC,"Allocate COMMON DCI CCEs subframe %d, test %d => L %d fCCE %d\n",subframeP,test_onlyP,dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level,fCCE); } idci++; } } // for i = 0 ... num_DL_DCIs // no try to allocate UL DCIs for (i=0;i<HI_DCI0_req->number_of_dci+HI_DCI0_req->number_of_hi;i++) { // allocate UL DCIs if (hi_dci0_pdu[i].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE) { LOG_D(MAC,"Trying to allocate format 0 DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", idci,DL_req->number_dci+HI_DCI0_req->number_of_dci, DL_req->number_dci,HI_DCI0_req->number_of_dci, hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti,hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.aggregation_level, nCCE,nCCE_max, DL_req->number_pdcch_ofdm_symbols); if (nCCE + (hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.aggregation_level) > nCCE_max) { if (DL_req->number_pdcch_ofdm_symbols == 3) goto failed; LOG_D(MAC,"Can't fit DCI allocations with %d PDCCH symbols, increasing by 1\n",DL_req->number_pdcch_ofdm_symbols); DL_req->number_pdcch_ofdm_symbols++; nCCE_max = get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP],DL_req->number_pdcch_ofdm_symbols,subframeP); goto try_again; } // number of CCEs left can potentially hold this allocation fCCE = get_nCCE_offset(CCE_table, hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.aggregation_level, nCCE_max, 0, hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti, subframeP); if (fCCE == -1) { if (DL_req->number_pdcch_ofdm_symbols == 3) { LOG_D(MAC,"subframe %d: Dropping Allocation for RNTI %x\n", subframeP,hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti); for (j=0;j<=i;j++){ if (hi_dci0_pdu[j].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE) LOG_D(MAC,"DCI %d/%d (%d,%d) : rnti %x dci format %d, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", j,DL_req->number_dci+HI_DCI0_req->number_of_dci, DL_req->number_dci,HI_DCI0_req->number_of_dci, hi_dci0_pdu[j].dci_pdu.dci_pdu_rel8.rnti, hi_dci0_pdu[j].dci_pdu.dci_pdu_rel8.dci_format, hi_dci0_pdu[j].dci_pdu.dci_pdu_rel8.aggregation_level, nCCE,nCCE_max,DL_req->number_pdcch_ofdm_symbols); } //dump_CCE_table(CCE_table,nCCE_max,subframeP,dci_alloc->rnti,1<<dci_alloc->L); goto failed; } LOG_D(MAC,"Can't fit DCI allocations with %d PDCCH symbols (rnti condition), increasing by 1\n",DL_req->number_pdcch_ofdm_symbols); DL_req->number_pdcch_ofdm_symbols++; nCCE_max = get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP],DL_req->number_pdcch_ofdm_symbols,subframeP); goto try_again; } // fCCE==-1 // the allocation is feasible, rnti rule passes nCCE += hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.aggregation_level; LOG_D(MAC,"Allocating at nCCE %d\n",fCCE); if (test_onlyP == 0) { hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.cce_index=fCCE; LOG_D(MAC,"Allocate CCEs subframe %d, test %d\n",subframeP,test_onlyP); } idci++; } } // for i = 0 ... num_UL_DCIs for (i=0;i<DL_req->number_pdu;i++) { // allocate DL UE specific DCIs if ((dl_config_pdu[i].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE)&& (dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti_type==1)) { LOG_D(MAC,"Trying to allocate DL UE-SPECIFIC DCI %d/%d (%d,%d) : rnti %x, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", idci,DL_req->number_dci+HI_DCI0_req->number_of_dci, DL_req->number_dci,HI_DCI0_req->number_of_dci, dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti,dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, nCCE,nCCE_max, DL_req->number_pdcch_ofdm_symbols); if (nCCE + (dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level) > nCCE_max) { if (DL_req->number_pdcch_ofdm_symbols == 3) goto failed; LOG_D(MAC,"Can't fit DCI allocations with %d PDCCH symbols, increasing by 1\n",DL_req->number_pdcch_ofdm_symbols); DL_req->number_pdcch_ofdm_symbols++; nCCE_max = get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP],DL_req->number_pdcch_ofdm_symbols,subframeP); goto try_again; } // number of CCEs left can potentially hold this allocation fCCE = get_nCCE_offset(CCE_table, dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, nCCE_max, 0, dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti, subframeP); if (fCCE == -1) { if (DL_req->number_pdcch_ofdm_symbols == 3) { LOG_I(MAC,"subframe %d: Dropping Allocation for RNTI %x\n", subframeP,dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.rnti); for (j=0;j<=i;j++){ if (dl_config_pdu[j].pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE) LOG_I(MAC,"DCI %d/%d (%d,%d) : rnti %x dci format %d, aggreg %d nCCE %d / %d (num_pdcch_symbols %d)\n", j,DL_req->number_dci+HI_DCI0_req->number_of_dci, DL_req->number_dci,HI_DCI0_req->number_of_dci, dl_config_pdu[j].dci_dl_pdu.dci_dl_pdu_rel8.rnti, dl_config_pdu[j].dci_dl_pdu.dci_dl_pdu_rel8.dci_format, dl_config_pdu[j].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, nCCE,nCCE_max,DL_req->number_pdcch_ofdm_symbols); } //dump_CCE_table(CCE_table,nCCE_max,subframeP,dci_alloc->rnti,1<<dci_alloc->L); goto failed; } LOG_D(MAC,"Can't fit DCI allocations with %d PDCCH symbols (rnti condition), increasing by 1\n",DL_req->number_pdcch_ofdm_symbols); DL_req->number_pdcch_ofdm_symbols++; nCCE_max = get_nCCE_max(&RC.mac[module_idP]->common_channels[CC_idP],DL_req->number_pdcch_ofdm_symbols,subframeP); goto try_again; } // fCCE==-1 // the allocation is feasible, rnti rule passes nCCE += dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level; LOG_D(MAC,"Allocating at nCCE %d\n",fCCE); if (test_onlyP == 0) { dl_config_pdu[i].dci_dl_pdu.dci_dl_pdu_rel8.cce_idx=fCCE; LOG_D(MAC,"Allocate CCEs subframe %d, test %d\n",subframeP,test_onlyP); } idci++; } } // for i = 0 ... num_DL_DCIs return 0; failed: return -1; } /* uint8_t get_ul_req_index(module_id_t module_idP, int CC_idP, sub_frame_t subframeP) { if (RC.mac[module_idP]->common_channels[CC_idP].tdd_Config == NULL) return(0); switch (RC.mac[module_idP]->common_channels[CC_idP].tdd_Config->subframeAssignment) { case 0: case 1: case 2: case 6: return(0); case 3: // 1,5,6 -> 2, prog. 8, buffer 0 // 7,8 -> 3, prog. 9, buffer 1 // 9,0 -> 4, prog. 0, buffer 0 if ((subframeP == 7) || (subframeP == 8)) return(1); else return(0); case 4: // 0,1,4,5 -> 2, prog. 8, buffer 0 // 6,7,8,9 -> 3, prog. 9, buffer 1 if (subframeP<6) return(0); else return(1); return(1); break; case 5: // 9(-1),0,1,3,4,5,6,7,8,9 -> 2, prog 8, buffer 0 return(0); break; default: AssertFatal(1==0,"Should not get here, why is tdd_Config->subframeAssignment = %d\n",(int)RC.mac[module_idP]->common_channels[CC_idP].tdd_Config->subframeAssignment); break; } return(0); } */ nfapi_ul_config_request_pdu_t* has_ul_grant(module_id_t module_idP,int CC_idP,uint16_t absSFP,uint16_t rnti) { nfapi_ul_config_request_body_t *ul_req; nfapi_ul_config_request_pdu_t *ul_config_pdu; ul_req = &RC.mac[module_idP]->UL_req_tmp[CC_idP][absSFP%10].ul_config_request_body; ul_config_pdu = &ul_req->ul_config_pdu_list[0]; LOG_D(MAC,"Checking for rnti %x UL grant in subframeP %d (num pdu %d)\n",rnti,absSFP%10,ul_req->number_of_pdus); for (int i=0; i<ul_req->number_of_pdus;i++){ LOG_D(MAC,"PDU %d : type %d,rnti %x\n",i,ul_config_pdu[i].pdu_type,rnti); if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE)&& (ul_config_pdu[i].ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) return(&ul_config_pdu[i]); if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE)&& (ul_config_pdu[i].ulsch_cqi_ri_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) return(&ul_config_pdu[i]); if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE)&& (ul_config_pdu[i].ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) return(&ul_config_pdu[i]); if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE)&& (ul_config_pdu[i].ulsch_cqi_harq_ri_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) return(&ul_config_pdu[i]); if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE)&& (ul_config_pdu[i].uci_cqi_pdu.ue_information.ue_information_rel8.rnti == rnti)) return(&ul_config_pdu[i]); if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE)&& (ul_config_pdu[i].uci_sr_pdu.ue_information.ue_information_rel8.rnti == rnti)) return(&ul_config_pdu[i]); if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE)&& (ul_config_pdu[i].uci_harq_pdu.ue_information.ue_information_rel8.rnti == rnti)) return(&ul_config_pdu[i]); if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE)&& (ul_config_pdu[i].uci_sr_harq_pdu.ue_information.ue_information_rel8.rnti == rnti)) return(&ul_config_pdu[i]); if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_CQI_HARQ_PDU_TYPE)&& (ul_config_pdu[i].uci_cqi_harq_pdu.ue_information.ue_information_rel8.rnti == rnti)) return(&ul_config_pdu[i]); if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_CQI_SR_PDU_TYPE)&& (ul_config_pdu[i].uci_cqi_sr_pdu.ue_information.ue_information_rel8.rnti == rnti)) return(&ul_config_pdu[i]); if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_UCI_CQI_SR_HARQ_PDU_TYPE) && (ul_config_pdu[i].uci_cqi_sr_harq_pdu.ue_information.ue_information_rel8.rnti == rnti)) return(&ul_config_pdu[i]); if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_UCI_CSI_PDU_TYPE)&& (ul_config_pdu[i].ulsch_uci_csi_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) return(&ul_config_pdu[i]); if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_UCI_HARQ_PDU_TYPE)&& (ul_config_pdu[i].ulsch_uci_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) return(&ul_config_pdu[i]); if ((ul_config_pdu[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CSI_UCI_HARQ_PDU_TYPE)&& (ul_config_pdu[i].ulsch_csi_uci_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti == rnti)) return(&ul_config_pdu[i]); } return(NULL); // no ul grant at all for this UE } boolean_t CCE_allocation_infeasible(int module_idP, int CC_idP, int format_flag, int subframe, int aggregation, int rnti) { nfapi_dl_config_request_body_t *DL_req = &RC.mac[module_idP]->DL_req[CC_idP].dl_config_request_body; nfapi_dl_config_request_pdu_t *dl_config_pdu = &DL_req->dl_config_pdu_list[DL_req->number_pdu]; nfapi_hi_dci0_request_body_t *HI_DCI0_req = &RC.mac[module_idP]->HI_DCI0_req[CC_idP].hi_dci0_request_body; nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = &HI_DCI0_req->hi_dci0_pdu_list[HI_DCI0_req->number_of_dci+HI_DCI0_req->number_of_hi]; int ret; boolean_t res = FALSE; if (format_flag != 2) { // DL DCI if (DL_req->number_pdu == MAX_NUM_DL_PDU) { LOG_W(MAC, "Subframe %d: FAPI DL structure is full, skip scheduling UE %d\n", subframe, rnti); } else { dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = (format_flag == 0)?2:1; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = aggregation; DL_req->number_pdu++; LOG_D(MAC,"Subframe %d: Checking CCE feasibility format %d : (%x,%d) (%x,%d,%d)\n", subframe,format_flag,rnti,aggregation, dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti, dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type); ret = allocate_CCEs(module_idP,CC_idP,subframe,0); if (ret==-1) res = TRUE; DL_req->number_pdu--; } } else { // ue-specific UL DCI if (HI_DCI0_req->number_of_dci+HI_DCI0_req->number_of_hi == MAX_NUM_HI_DCI0_PDU) { LOG_W(MAC, "Subframe %d: FAPI UL structure is full, skip scheduling UE %d\n", subframe, rnti); } else { hi_dci0_pdu->pdu_type = NFAPI_HI_DCI0_DCI_PDU_TYPE; hi_dci0_pdu->dci_pdu.dci_pdu_rel8.rnti = rnti; hi_dci0_pdu->dci_pdu.dci_pdu_rel8.aggregation_level = aggregation; HI_DCI0_req->number_of_dci++; ret = allocate_CCEs(module_idP,CC_idP,subframe,0); if (ret==-1) res = TRUE; HI_DCI0_req->number_of_dci--; } } return res; } void extract_harq(module_id_t mod_idP,int CC_idP,int UE_id,frame_t frameP,sub_frame_t subframeP,void *harq_indication,int format) { UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; rnti_t rnti = UE_RNTI(mod_idP,UE_id); COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP]; nfapi_harq_indication_fdd_rel13_t *harq_indication_fdd; nfapi_harq_indication_tdd_rel13_t *harq_indication_tdd; uint16_t num_ack_nak; int numCC = UE_list->numactiveCCs[UE_id]; int pCCid = UE_list->pCC_id[UE_id]; int spatial_bundling = 0; int tmode[5]; int i,j; uint8_t *pdu; #ifdef Rel14 AssertFatal(UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->pucch_ConfigDedicated!=NULL,"pucch_ConfigDedicated is null!\n"); if ((UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->ext7) && (UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->ext7->pucch_ConfigDedicated_r13) && (((UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->ext7->pucch_ConfigDedicated_r13->spatialBundlingPUCCH_r13) && (format==0)) || ((UE_list->UE_template[pCCid][UE_id].physicalConfigDedicated->ext7->pucch_ConfigDedicated_r13->spatialBundlingPUSCH_r13) && (format==1)))) spatial_bundling = 1; #endif for (i=0;i<numCC;i++) tmode[i] = get_tmode(mod_idP,i,UE_id); if (cc->tdd_Config) { harq_indication_tdd = (nfapi_harq_indication_tdd_rel13_t *)harq_indication; // pdu = &harq_indication_tdd->harq_tb_n[0]; num_ack_nak = harq_indication_tdd->number_of_ack_nack; switch (harq_indication_tdd->mode) { case 0: // Format 1a/b AssertFatal(numCC==1,"numCC %d > 1, should not be using Format1a/b\n",numCC); break; case 1: // Channel Selection break; case 2: // Format 3 break; case 3: // Format 4 break; case 4: // Format 5 break; } } else { harq_indication_fdd = (nfapi_harq_indication_fdd_rel13_t *)harq_indication; num_ack_nak = harq_indication_fdd->number_of_ack_nack; pdu = &harq_indication_fdd->harq_tb_n[0]; uint8_t harq_pid = ((10*frameP) + subframeP + 10236)&7; switch (harq_indication_fdd->mode) { case 0: // Format 1a/b (10.1.2.1) AssertFatal(numCC==1,"numCC %d > 1, should not be using Format1a/b\n",numCC); if (tmode[0]==1 || tmode[0]==2 || tmode[0]==5 || tmode[0]==6 || tmode[0]==7) { // NOTE: have to handle the case of TM9-10 with 1 antenna port // single ACK/NAK bit AssertFatal(num_ack_nak==1,"num_ack_nak %d > 1 for 1 CC and single-layer transmission\n",num_ack_nak); AssertFatal(sched_ctl->round[CC_idP][harq_pid]<8,"Got ACK/NAK for inactive harq_pid %d for UE %d/%x\n",harq_pid,UE_id,rnti); AssertFatal(pdu[0] == 1 || pdu[0] == 2 || pdu[0] == 4, "Received ACK/NAK %d which is not 1 or 2 for harq_pid %d from UE %d/%x\n",pdu[0],harq_pid,UE_id,rnti); LOG_D(MAC,"Received %d for harq_pid %d\n",pdu[0],harq_pid); if (pdu[0] == 1) { // ACK sched_ctl->round[CC_idP][harq_pid]=8; // release HARQ process sched_ctl->tbcnt[CC_idP][harq_pid]=0; } else if (pdu[0] == 2 || pdu[0] == 4) // NAK (treat DTX as NAK) sched_ctl->round[CC_idP][harq_pid]++; // increment round } else { // one or two ACK/NAK bits AssertFatal(num_ack_nak>2,"num_ack_nak %d > 2 for 1 CC and TM3/4/8/9/10\n",num_ack_nak); if ((num_ack_nak==2) && (sched_ctl->round[CC_idP][harq_pid]<8) && (sched_ctl->tbcnt[CC_idP][harq_pid]==1) && (pdu[0] == 1) && (pdu[1] == 1)) { sched_ctl->round[CC_idP][harq_pid]=8; sched_ctl->tbcnt[CC_idP][harq_pid]=0; } if ((num_ack_nak==2) && (sched_ctl->round[CC_idP][harq_pid]<8) && (sched_ctl->tbcnt[CC_idP][harq_pid]==1) && (pdu[0] == 2) && (pdu[1] == 2)) sched_ctl->round[CC_idP][harq_pid]++; else if (((num_ack_nak==2) && (sched_ctl->round[CC_idP][harq_pid]<8) && (sched_ctl->tbcnt[0][harq_pid]==2) && (pdu[0] == 1) && (pdu[1] == 2)) || ((num_ack_nak==2) && (sched_ctl->round[CC_idP][harq_pid]<8) && (sched_ctl->tbcnt[CC_idP][harq_pid]==2) && (pdu[0] == 2) && (pdu[1] == 1))) { sched_ctl->round[CC_idP][harq_pid]++; sched_ctl->tbcnt[CC_idP][harq_pid]=1; } else if ((num_ack_nak==2) && (sched_ctl->round[CC_idP][harq_pid]<8) && (sched_ctl->tbcnt[CC_idP][harq_pid]==2) && (pdu[0] == 2) && (pdu[1] == 2)) sched_ctl->round[CC_idP][harq_pid]++; else AssertFatal(1==0,"Illegal ACK/NAK/round combination (%d,%d,%d,%d,%d) for harq_pid %d, UE %d/%x\n", num_ack_nak,sched_ctl->round[CC_idP][harq_pid],sched_ctl->round[CC_idP][harq_pid],pdu[0],pdu[1], harq_pid,UE_id, rnti); } break; case 1: // FDD Channel Selection (10.1.2.2.1), must be received for 2 serving cells AssertFatal(numCC==2,"Should not receive harq indication with channel selection with %d active CCs\n", numCC); if ((num_ack_nak == 2) && (sched_ctl->round[pCCid][harq_pid]<8) && (sched_ctl->round[1-pCCid][harq_pid]<8) && (sched_ctl->tbcnt[pCCid][harq_pid]==1) && (sched_ctl->tbcnt[1-pCCid][harq_pid]==1)) { AssertFatal(pdu[0]<=3,"pdu[0] %d is not ACK/NAK/DTX\n",pdu[0]); AssertFatal(pdu[1]<=3,"pdu[1] %d is not ACK/NAK/DTX\n",pdu[1]); if (pdu[0] == 1) sched_ctl->round[pCCid][harq_pid]=8; else sched_ctl->round[pCCid][harq_pid]++; if (pdu[1] == 1) sched_ctl->round[1-pCCid][harq_pid]=8; else sched_ctl->round[1-pCCid][harq_pid]++; } // A=2 else if ((num_ack_nak == 3) && (sched_ctl->round[pCCid][harq_pid]<8) && (sched_ctl->tbcnt[pCCid][harq_pid]==2) && (sched_ctl->round[1-pCCid][harq_pid]<8) && (sched_ctl->tbcnt[1-pCCid][harq_pid]==1)) { AssertFatal(pdu[0]<=3,"pdu[0] %d is not ACK/NAK/DTX\n",pdu[0]); AssertFatal(pdu[1]<=3,"pdu[1] %d is not ACK/NAK/DTX\n",pdu[1]); AssertFatal(pdu[2]<=3,"pdu[2] %d is not ACK/NAK/DTX\n",pdu[2]); AssertFatal(sched_ctl->tbcnt[pCCid][harq_pid] == 2,"sched_ctl->tbcnt[%d][%d] != 2 for UE %d/%x\n",pCCid,harq_pid,UE_id,rnti); AssertFatal(sched_ctl->tbcnt[1-pCCid][harq_pid] == 1,"sched_ctl->tbcnt[%d][%d] != 1 for UE %d/%x\n",1-pCCid,harq_pid,UE_id,rnti); if ((pdu[0] == 1) && (pdu[1] == 1)) { // both ACK sched_ctl->round[pCCid][harq_pid]=8; sched_ctl->tbcnt[pCCid][harq_pid]=0; } else if (((pdu[0] == 2) && (pdu[1] == 1))|| ((pdu[0] == 1) && (pdu[1] == 2))){ sched_ctl->round[pCCid][harq_pid]++; sched_ctl->tbcnt[pCCid][harq_pid]=1; } else sched_ctl->round[pCCid][harq_pid]++; if (pdu[2] == 1) sched_ctl->round[1-pCCid][harq_pid]=8; else sched_ctl->round[1-pCCid][harq_pid]++; } // A=3 primary cell has 2 TBs else if ((num_ack_nak == 3) && (sched_ctl->round[1-pCCid][harq_pid]<8) && (sched_ctl->round[pCCid][harq_pid]<8) && (sched_ctl->tbcnt[1-pCCid][harq_pid]==2) && (sched_ctl->tbcnt[pCCid][harq_pid]==1)) { AssertFatal(pdu[0]<=3,"pdu[0] %d is not ACK/NAK/DTX\n",pdu[0]); AssertFatal(pdu[1]<=3,"pdu[1] %d is not ACK/NAK/DTX\n",pdu[1]); AssertFatal(pdu[2]<=3,"pdu[2] %d is not ACK/NAK/DTX\n",pdu[2]); AssertFatal(sched_ctl->tbcnt[1-pCCid][harq_pid] == 2,"sched_ctl->tbcnt[%d][%d] != 2 for UE %d/%x\n",1-pCCid,harq_pid,UE_id,rnti); AssertFatal(sched_ctl->tbcnt[pCCid][harq_pid] == 1,"sched_ctl->tbcnt[%d][%d] != 1 for UE %d/%x\n",pCCid,harq_pid,UE_id,rnti); if ((pdu[0] == 1) && (pdu[1] == 1)) { // both ACK sched_ctl->round[1-pCCid][harq_pid]=8; sched_ctl->tbcnt[1-pCCid][harq_pid]=0; } else if (((pdu[0] >= 2) && (pdu[1] == 1))|| ((pdu[0] == 1) && (pdu[1] >= 2))){ // one ACK sched_ctl->round[1-pCCid][harq_pid]++; sched_ctl->tbcnt[1-pCCid][harq_pid]=1; } else // both NAK/DTX sched_ctl->round[1-pCCid][harq_pid]++; if (pdu[2] == 1) sched_ctl->round[pCCid][harq_pid]=8; else sched_ctl->round[pCCid][harq_pid]++; } // A=3 secondary cell has 2 TBs #if MAX_NUM_CCs>1 else if ((num_ack_nak == 4) && (sched_ctl->round[0][harq_pid]<8) && (sched_ctl->round[1][harq_pid]<8) && (sched_ctl->tbcnt[1-pCCid][harq_pid]==2) && (sched_ctl->tbcnt[pCCid][harq_pid]==2)) { AssertFatal(pdu[0]<=3,"pdu[0] %d is not ACK/NAK/DTX\n",pdu[0]); AssertFatal(pdu[1]<=3,"pdu[1] %d is not ACK/NAK/DTX\n",pdu[1]); AssertFatal(pdu[2]<=3,"pdu[2] %d is not ACK/NAK/DTX\n",pdu[2]); AssertFatal(pdu[3]<=3,"pdu[3] %d is not ACK/NAK/DTX\n",pdu[3]); AssertFatal(sched_ctl->tbcnt[0][harq_pid] == 2,"sched_ctl->tbcnt[0][%d] != 2 for UE %d/%x\n",harq_pid,UE_id,rnti); AssertFatal(sched_ctl->tbcnt[1][harq_pid] == 2,"sched_ctl->tbcnt[1][%d] != 2 for UE %d/%x\n",harq_pid,UE_id,rnti); if ((pdu[0] == 1) && (pdu[1] == 1)) { // both ACK sched_ctl->round[0][harq_pid]=8; sched_ctl->tbcnt[0][harq_pid]=0; } else if (((pdu[0] >= 2) && (pdu[1] == 1))|| ((pdu[0] == 1) && (pdu[1] >= 2))){ // one ACK sched_ctl->round[0][harq_pid]++; sched_ctl->tbcnt[0][harq_pid]=1; } else // both NAK/DTX sched_ctl->round[0][harq_pid]++; if ((pdu[2] == 1) && (pdu[3] == 1)) { // both ACK sched_ctl->round[1][harq_pid]=8; sched_ctl->tbcnt[1][harq_pid]=0; } else if (((pdu[2] >= 2) && (pdu[3] == 1))|| ((pdu[2] == 1) && (pdu[3] >= 2))){ // one ACK sched_ctl->round[1][harq_pid]++; sched_ctl->tbcnt[1][harq_pid]=1; } else // both NAK/DTX sched_ctl->round[1][harq_pid]++; } // A=4 both serving cells have 2 TBs #endif break; case 2: // Format 3 AssertFatal(numCC>2,"Should not receive harq indication with FDD format 3 with %d < 3 active CCs\n", numCC); for (i=0,j=0;i<numCC;i++) { if ((sched_ctl->round[i][harq_pid]<8)) { if (tmode[i]==1 || tmode[i]==2 || tmode[0]==5 || tmode[0]==6 || tmode[0]==7) { if (pdu[j] == 1) { sched_ctl->round[i][harq_pid]=8; sched_ctl->tbcnt[i][harq_pid]=0; } else if (pdu[j] == 2) sched_ctl->round[i][harq_pid]++; else AssertFatal(1==0,"Illegal harq_ack value for CC %d harq_pid %d (%d) UE %d/%x\n", i,harq_pid,pdu[j],UE_id,rnti); j++; } else if (spatial_bundling == 0) { if ((sched_ctl->tbcnt[i][harq_pid]==2) && (pdu[j] == 1) && (pdu[j+1]==1)) { sched_ctl->round[i][harq_pid]=8; sched_ctl->tbcnt[i][harq_pid]=0; } else if ((sched_ctl->tbcnt[i][harq_pid]==2) && (pdu[j] == 1) && (pdu[j+1]==2)) { sched_ctl->round[i][harq_pid]++; sched_ctl->tbcnt[i][harq_pid]=1; } else if ((sched_ctl->tbcnt[i][harq_pid]==2) && (pdu[j] == 2) && (pdu[j+1]==1)) { sched_ctl->round[i][harq_pid]++; sched_ctl->tbcnt[i][harq_pid]=1; } else if ((sched_ctl->tbcnt[i][harq_pid]==2) && (pdu[j] == 2) && (pdu[j+1]==2)) { sched_ctl->round[i][harq_pid]++; } else AssertFatal(1==0,"Illegal combination for CC %d harq_pid %d (%d,%d,%d) UE %d/%x\n", i,harq_pid,sched_ctl->tbcnt[i][harq_pid],pdu[j],pdu[j+1],UE_id,rnti); j+=2; } else if (spatial_bundling == 1) { if (pdu[j] == 1) { sched_ctl->round[i][harq_pid]=8; sched_ctl->tbcnt[i][harq_pid]=0; } else if (pdu[j] == 2) { sched_ctl->round[i][harq_pid]++; } else AssertFatal(1==0,"Illegal hack_nak value %d for CC %d harq_pid %d UE %d/%x\n", pdu[j],i,harq_pid,UE_id,rnti); j++; } else AssertFatal(1==0,"Illegal value for spatial_bundling %d\n",spatial_bundling); } } break; case 3: // Format 4 AssertFatal(1==0,"Should not receive harq indication with Format 4\n"); break; case 4: // Format 5 AssertFatal(1==0,"Should not receive harq indication with Format 5\n"); break; } } } void extract_pucch_csi(module_id_t mod_idP,int CC_idP,int UE_id, frame_t frameP,sub_frame_t subframeP,uint8_t *pdu, uint8_t length) { UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; COMMON_channels_t *cc=&RC.mac[mod_idP]->common_channels[CC_idP]; struct CQI_ReportPeriodic *cqi_ReportPeriodic; int no_pmi; uint8_t Ltab[6] = {0,2,4,4,4,4}; uint8_t Jtab[6] = {0,2,2,3,4,4}; int feedback_cnt; AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated != NULL, "physicalConfigDedicated is null for UE %d\n",UE_id); AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->cqi_ReportConfig != NULL,"cqi_ReportConfig is null for UE %d\n",UE_id); AssertFatal((cqi_ReportPeriodic = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic)!=NULL, "cqi_ReportPeriodic is null for UE %d\n",UE_id); // determine feedback mode AssertFatal(cqi_ReportPeriodic->present != CQI_ReportPeriodic_PR_NOTHING, "cqi_ReportPeriodic->present == CQI_ReportPeriodic_PR_NOTHING!\n"); AssertFatal(cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present != CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING, "cqi_ReportPeriodic->cqi_FormatIndicatorPeriodic.choice.setup.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_NOTHING!\n"); uint16_t Npd,N_OFFSET_CQI; int H,K,bandwidth_part,L,Lmask; int ri = sched_ctl->periodic_ri_received[CC_idP]; get_csi_params(cc,cqi_ReportPeriodic,&Npd,&N_OFFSET_CQI,&H); K =(H-1)/Jtab[cc->mib->message.dl_Bandwidth]; L = Ltab[cc->mib->message.dl_Bandwidth]; Lmask =L-1; feedback_cnt = (((frameP*10)+subframeP)/Npd)%H; if (feedback_cnt>0) bandwidth_part = (feedback_cnt-1)%K; else bandwidth_part = 0; switch(get_tmode(mod_idP,CC_idP,UE_id)) { case 1: case 2: case 3: case 7: no_pmi=1; break; case 4: case 5: case 6: no_pmi=0; break; default: // note: need to check TM8-10 without PMI/RI or with 1 antenna port (see Section 5.2.3.3.1 from 36.213) no_pmi=0; } if ((cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_widebandCQI) || (feedback_cnt==0)){ // Note: This implements only Tables: 5.3.3.1-1,5.3.3.1-1A and 5.3.3.1-2 from 36.213 (1,2,4 antenna ports Wideband CQI/PMI) if (no_pmi == 1) { // get spatial_diffcqi if needed sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0]&0xF; sched_ctl->periodic_wideband_spatial_diffcqi[CC_idP] = (pdu[0]>>4)&7; } else if ((cc->p_eNB==2) && (ri==1)) { // p=2 Rank 1 wideband CQI/PMI 6 bits sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0]&0xF; sched_ctl->periodic_wideband_pmi[CC_idP] = (pdu[0]>>4)&3; } else if ((cc->p_eNB==2) && (ri>1)) { // p=2 Rank 2 wideband CQI/PMI 8 bits sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0]&0xF; sched_ctl->periodic_wideband_spatial_diffcqi[CC_idP] = (pdu[0]>>4)&7; sched_ctl->periodic_wideband_pmi[CC_idP] = (pdu[0]>>7)&1; } else if ((cc->p_eNB==4) && (ri==1)) { // p=4 Rank 1 wideband CQI/PMI 8 bits sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0]&0xF; sched_ctl->periodic_wideband_pmi[CC_idP] = (pdu[0]>>4)&0x0F; } else if ((cc->p_eNB==4) && (ri>1)) { // p=4 Rank 2 wideband CQI/PMI 11 bits sched_ctl->periodic_wideband_cqi[CC_idP] = pdu[0]&0xF; sched_ctl->periodic_wideband_spatial_diffcqi[CC_idP] = (pdu[0]>>4)&7; sched_ctl->periodic_wideband_pmi[CC_idP] = (pdu[0]>>7)&0xF; } else AssertFatal(1==0,"illegal combination p %d, ri %d, no_pmi %d\n",cc->p_eNB,ri,no_pmi); } else if (cqi_ReportPeriodic->choice.setup.cqi_FormatIndicatorPeriodic.present == CQI_ReportPeriodic__setup__cqi_FormatIndicatorPeriodic_PR_subbandCQI) { // This is Table 5.2.3.3.2-2 for 36.213 if (ri==1) { //4+Ltab[cc->mib->message.dl_Bandwidth] bits sched_ctl->periodic_subband_cqi[CC_idP][(bandwidth_part*L)+((pdu[0]>>4)&Lmask)] = pdu[0]&0xF; } else if (ri>1) { //7+Ltab[cc->mib->message.dl_Bandwidth] bits; sched_ctl->periodic_subband_spatial_diffcqi[CC_idP][(bandwidth_part*L)+((pdu[0]>>7)&Lmask)] = (pdu[0]>>4)&7; sched_ctl->periodic_subband_cqi[CC_idP][(bandwidth_part*L)+((pdu[0]>>7)&Lmask)] = pdu[0]&0xF; } } } void extract_pusch_csi(module_id_t mod_idP,int CC_idP,int UE_id, frame_t frameP,sub_frame_t subframeP,uint8_t *pdu, uint8_t length) { UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP]; UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; int Ntab[6] = {0,4,7,9,10,13}; int Ntab_uesel[6] = {0,8,13,17,19,25}; int Ltab_uesel[6] = {0,6,9,13,15,18}; int Mtab_uesel[6] = {0,1,3,5,6,6}; int v[6]; int i; uint64_t p = *(uint64_t*)pdu; int curbyte, curbit; CQI_ReportModeAperiodic_t *cqi_ReportModeAperiodic; AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated != NULL, "physicalConfigDedicated is null for UE %d\n",UE_id); AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->cqi_ReportConfig != NULL,"cqi_ReportConfig is null for UE %d\n",UE_id); AssertFatal((cqi_ReportModeAperiodic = UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic)!=NULL, "cqi_ReportModeAperiodic is null for UE %d\n",UE_id); int N = Ntab[cc->mib->message.dl_Bandwidth]; int tmode = get_tmode(mod_idP,CC_idP,UE_id); int ri = sched_ctl->aperiodic_ri_received[CC_idP]; int r,diffcqi0=0,diffcqi1=0,pmi_uesel=0; int bw = cc->mib->message.dl_Bandwidth; int m; switch(*cqi_ReportModeAperiodic) { case CQI_ReportModeAperiodic_rm12: AssertFatal(0==1, "to be fixed, don't use p but pdu directly\n"); // wideband multiple PMI (TM4/6), Table 5.2.2.6.1-1 (for TM4/6) AssertFatal(tmode==4 || tmode==6 || tmode==8|| tmode==9 || tmode==10,"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm12\n",tmode); if (tmode <= 6) { //Table 5.2.2.6.1-1 36.213 if ((ri==1) && (cc->p_eNB==2)) { sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t)(p&0x0F); p>>=4; for (i=0;i<N;i++) { sched_ctl->aperiodic_subband_pmi[CC_idP][i] = (uint8_t)(p&0x03); p>>=2; } } if ((ri==2) && (cc->p_eNB==2)) { sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t)(p&0x0F); p>>=4; sched_ctl->aperiodic_wideband_cqi1[CC_idP] = (uint8_t)(p&0x0F); p>>=4; for (i=0;i<N;i++) { sched_ctl->aperiodic_subband_pmi[CC_idP][i] = (uint8_t)(p&0x01); p>>=1; } } if ((ri==1) && (cc->p_eNB==4)) { sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t)(p&0x0F); p>>=4; for (i=0;i<N;i++) { sched_ctl->aperiodic_subband_pmi[CC_idP][i] = (uint8_t)(p&0x03); p>>=4; } } if ((ri==2) && (cc->p_eNB==4)) { sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t)(p&0x0F); p>>=4; sched_ctl->aperiodic_wideband_cqi1[CC_idP] = (uint8_t)(p&0x0F); p>>=4; for (i=0;i<N;i++) { sched_ctl->aperiodic_subband_pmi[CC_idP][i] = (uint8_t)(p&0x01); p>>=4; } } } // if (tmode <= 6) { //Table 5.2.2.6.1-1 36.213 else { AssertFatal(1==0,"support for TM 8-10 to be done\n"); } break; case CQI_ReportModeAperiodic_rm20: AssertFatal(0==1, "to be fixed, don't use p but pdu directly\n"); // UE-selected subband CQI no PMI (TM1/2/3/7) , Table 5.2.2.6.3-1 from 36.213 AssertFatal(tmode==1 || tmode==2 || tmode==3 || tmode==7,"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm20\n",tmode); sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t)(p&0x0F); p>>=4; diffcqi0 = (uint8_t)(p&0x03); p>>=2; r = (uint8_t)(p&((1>>Ltab_uesel[bw])-1)); reverse_index(Ntab_uesel[bw],Mtab_uesel[bw],r,v); for (m=0;m<Mtab_uesel[bw];m++) sched_ctl->aperiodic_subband_diffcqi0[CC_idP][v[m]] = diffcqi0; break; case CQI_ReportModeAperiodic_rm22: AssertFatal(0==1, "to be fixed, don't use p but pdu directly\n"); // UE-selected subband CQI multiple PMI (TM4/6) Table 5.2.2.6.3-2 from 36.213 AssertFatal(tmode==4 || tmode==6 || tmode==8|| tmode==9 || tmode==10,"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm22\n",tmode); sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t)(p&0x0F); p>>=4; diffcqi0 = (uint8_t)(p&0x03); p>>=2; if (ri>1) { sched_ctl->aperiodic_wideband_cqi1[CC_idP] = (uint8_t)(p&0x0F); p>>=4; diffcqi1 = (uint8_t)(p&0x03); p>>=2; } r = (uint8_t)(p&((1>>Ltab_uesel[bw])-1)); p>>=Ltab_uesel[bw]; reverse_index(Ntab_uesel[bw],Mtab_uesel[bw],r,v); if ((ri==1)&&(cc->p_eNB==2)) { pmi_uesel = p&0x3; p>>=2; sched_ctl->aperiodic_wideband_pmi[CC_idP] = p&0x3; } else if ((ri==2)&&(cc->p_eNB==2)) { pmi_uesel = p&0x1; p>>=1; sched_ctl->aperiodic_wideband_pmi[CC_idP] = p&0x1; } else if (cc->p_eNB==4) { pmi_uesel = p&0x0F; p>>=4; sched_ctl->aperiodic_wideband_pmi[CC_idP] = p&0x0F; } for (m=0;m<Mtab_uesel[bw];m++) { sched_ctl->aperiodic_subband_diffcqi0[CC_idP][v[m]] = diffcqi0; if (ri>1) sched_ctl->aperiodic_subband_diffcqi1[CC_idP][v[m]] = diffcqi1; sched_ctl->aperiodic_subband_pmi[CC_idP][v[m]] = pmi_uesel; } break; case CQI_ReportModeAperiodic_rm30: //subband CQI no PMI (TM1/2/3/7) AssertFatal(tmode==1 || tmode==2 || tmode==3 || tmode==7,"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm30\n",tmode); sched_ctl->aperiodic_wideband_cqi0[CC_idP] = pdu[0]>>4; curbyte = 0; curbit = 3; for (i=0;i<N;i++) { sched_ctl->aperiodic_subband_diffcqi0[CC_idP][i] = (pdu[curbyte] >> (curbit-1)) & 0x03; curbit -= 2; if (curbit < 0) { curbit = 7; curbyte++; } } sched_ctl->dl_cqi[CC_idP] = sched_ctl->aperiodic_wideband_cqi0[CC_idP]; break; case CQI_ReportModeAperiodic_rm31: AssertFatal(0==1, "to be fixed, don't use p but pdu directly\n"); //subband CQI single PMI (TM4/5/6) AssertFatal(tmode==4 || tmode==5 || tmode==6 || tmode==8|| tmode==9|| tmode==10,"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm31\n",tmode); if ((ri==1) && (cc->p_eNB==2)) { sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t)(p&0x0F); p>>=4; for (i=0;i<N;i++) { sched_ctl->aperiodic_subband_diffcqi0[CC_idP][i] = (uint8_t)(p&0x03); p>>=2; } sched_ctl->aperiodic_wideband_pmi[CC_idP] = p&0x03; } if ((ri==2) && (cc->p_eNB==2)) { sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t)(p&0x0F); p>>=4; for (i=0;i<N;i++) { sched_ctl->aperiodic_subband_pmi[CC_idP][i] = (uint8_t)(p&0x01); p>>=1; } sched_ctl->aperiodic_wideband_cqi1[CC_idP] = (uint8_t)(p&0x0F); p>>=4; for (i=0;i<N;i++) { sched_ctl->aperiodic_subband_pmi[CC_idP][i] = (uint8_t)(p&0x01); p>>=1; } sched_ctl->aperiodic_wideband_pmi[CC_idP] = p&0x01; } if ((ri==1) && (cc->p_eNB==4)) { sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t)(p&0x0F); p>>=4; for (i=0;i<N;i++) { sched_ctl->aperiodic_subband_diffcqi0[CC_idP][i] = (uint8_t)(p&0x03); p>>=2; } sched_ctl->aperiodic_wideband_pmi[CC_idP] = p&0x0F; } if ((ri>1) && (cc->p_eNB==4)) { // Note : 64 bits for 20 MHz sched_ctl->aperiodic_wideband_cqi0[CC_idP] = (uint8_t)(p&0x0F); p>>=4; for (i=0;i<N;i++) { sched_ctl->aperiodic_subband_pmi[CC_idP][i] = (uint8_t)(p&0x01); p>>=1; } sched_ctl->aperiodic_wideband_cqi1[CC_idP] = (uint8_t)(p&0x0F); p>>=4; for (i=0;i<N;i++) { sched_ctl->aperiodic_subband_pmi[CC_idP][i] = (uint8_t)(p&0x01); p>>=2; } sched_ctl->aperiodic_wideband_pmi[CC_idP] = p&0x0F; } break; case CQI_ReportModeAperiodic_rm32_v1250: AssertFatal(tmode==4 || tmode==5 || tmode==6 || tmode==8|| tmode==9|| tmode==10,"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm32\n",tmode); AssertFatal(1==0,"CQI_ReportModeAperiodic_rm32 to be done\n"); break; case CQI_ReportModeAperiodic_rm10_v1310: AssertFatal(tmode==1 || tmode==2 || tmode==3 || tmode==7,"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm10\n",tmode); AssertFatal(1==0,"CQI_ReportModeAperiodic_rm10 to be done\n"); break; case CQI_ReportModeAperiodic_rm11_v1310: AssertFatal(tmode==4 || tmode==5 || tmode==6 || tmode==8|| tmode==9|| tmode==10,"Illegal transmission mode %d for CQI_ReportModeAperiodic_rm11\n",tmode); AssertFatal(1==0,"CQI_ReportModeAperiodic_rm11 to be done\n"); break; } } void cqi_indication(module_id_t mod_idP, int CC_idP, frame_t frameP, sub_frame_t subframeP, rnti_t rntiP, nfapi_cqi_indication_rel9_t *rel9,uint8_t *pdu, nfapi_ul_cqi_information_t *ul_cqi_information) { int UE_id = find_UE_id(mod_idP, rntiP); UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; if (UE_id >= 0) { if (ul_cqi_information->channel == 0) { // PUCCH // extract pucch csi information before changing RI information extract_pucch_csi(mod_idP,CC_idP,UE_id,frameP,subframeP,pdu,rel9->length); memcpy((void*)sched_ctl->periodic_ri_received, (void*)rel9->ri, rel9->number_of_cc_reported); // SNR for PUCCH2 sched_ctl->pucch2_snr[CC_idP] = ul_cqi_information->ul_cqi; } else { //PUSCH memcpy((void*)sched_ctl->aperiodic_ri_received, (void*)rel9->ri, rel9->number_of_cc_reported); extract_pusch_csi(mod_idP,CC_idP,UE_id,frameP,subframeP,pdu,rel9->length); } // timing advance sched_ctl->timing_advance = rel9->timing_advance; sched_ctl->timing_advance_r9 = rel9->timing_advance_r9; } } void SR_indication(module_id_t mod_idP, int cc_idP, frame_t frameP, sub_frame_t subframeP, rnti_t rntiP, uint8_t ul_cqi) { T(T_ENB_MAC_SCHEDULING_REQUEST, T_INT(mod_idP), T_INT(cc_idP), T_INT(frameP), T_INT(subframeP), T_INT(rntiP)); int UE_id = find_UE_id(mod_idP, rntiP); UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; if (UE_id != -1) { if (mac_eNB_get_rrc_status(mod_idP,UE_RNTI(mod_idP,UE_id)) < RRC_CONNECTED) LOG_D(MAC,"[eNB %d][SR %x] Frame %d subframeP %d Signaling SR for UE %d on CC_id %d\n",mod_idP,rntiP,frameP,subframeP, UE_id,cc_idP); UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; sched_ctl->pucch1_snr[cc_idP] = ul_cqi; sched_ctl->pucch1_cqi_update[cc_idP] = 1; UE_list->UE_template[cc_idP][UE_id].ul_SR = 1; UE_list->UE_template[cc_idP][UE_id].ul_active = TRUE; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SR_INDICATION,1); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SR_INDICATION,0); } else { // AssertFatal(0, "find_UE_id(%u,rnti %d) not found", enb_mod_idP, rntiP); // AssertError(0, 0, "Frame %d: find_UE_id(%u,rnti %d) not found\n", frameP, enb_mod_idP, rntiP); LOG_D(MAC,"[eNB %d][SR %x] Frame %d subframeP %d Signaling SR for UE %d (unknown UEid) on CC_id %d\n",mod_idP,rntiP,frameP,subframeP, UE_id,cc_idP); } } void UL_failure_indication(module_id_t mod_idP, int cc_idP, frame_t frameP, rnti_t rntiP, sub_frame_t subframeP) { int UE_id = find_UE_id(mod_idP, rntiP); UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; if (UE_id != -1) { LOG_D(MAC,"[eNB %d][UE %d/%x] Frame %d subframeP %d Signaling UL Failure for UE %d on CC_id %d (timer %d)\n", mod_idP,UE_id,rntiP,frameP,subframeP, UE_id,cc_idP, UE_list->UE_sched_ctrl[UE_id].ul_failure_timer); if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer == 0) UE_list->UE_sched_ctrl[UE_id].ul_failure_timer=1; } else { // AssertFatal(0, "find_UE_id(%u,rnti %d) not found", enb_mod_idP, rntiP); // AssertError(0, 0, "Frame %d: find_UE_id(%u,rnti %d) not found\n", frameP, enb_mod_idP, rntiP); LOG_W(MAC,"[eNB %d][SR %x] Frame %d subframeP %d Signaling UL Failure for UE %d (unknown UEid) on CC_id %d\n",mod_idP,rntiP,frameP,subframeP, UE_id,cc_idP); } } void harq_indication(module_id_t mod_idP, int CC_idP, frame_t frameP, sub_frame_t subframeP, nfapi_harq_indication_pdu_t *harq_pdu) { rnti_t rnti = harq_pdu->rx_ue_information.rnti; uint8_t ul_cqi = harq_pdu->ul_cqi_information.ul_cqi; uint8_t channel = harq_pdu->ul_cqi_information.channel; int UE_id = find_UE_id(mod_idP, rnti); UE_list_t *UE_list = &RC.mac[mod_idP]->UE_list; UE_sched_ctrl *sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; COMMON_channels_t *cc = &RC.mac[mod_idP]->common_channels[CC_idP]; // extract HARQ Information LOG_D(MAC,"Frame %d, subframe %d: Received harq indication (%d) from UE %d/%x, ul_cqi %d\n",frameP,subframeP,channel,UE_id,rnti,ul_cqi); if (cc->tdd_Config) extract_harq(mod_idP,CC_idP,UE_id,frameP,subframeP,(void*)&harq_pdu->harq_indication_tdd_rel13,channel); else extract_harq(mod_idP,CC_idP,UE_id,frameP,subframeP,(void*)&harq_pdu->harq_indication_fdd_rel13,channel); if (channel == 0) { sched_ctl->pucch1_snr[CC_idP] = ul_cqi; sched_ctl->pucch1_cqi_update[CC_idP] = 1; } }