/* * 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_dlsch.c * \brief procedures related to eNB for the DLSCH transport channel * \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/proto.h" #include "LAYER2/MAC/extern.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" #include "SIMULATION/TOOLS/defs.h" // for taus #if defined(ENABLE_ITTI) # include "intertask_interface.h" #endif #include "T.h" #define ENABLE_MAC_PAYLOAD_DEBUG //#define DEBUG_eNB_SCHEDULER 1 extern RAN_CONTEXT_t RC; //------------------------------------------------------------------------------ void add_ue_dlsch_info( module_id_t module_idP, int CC_id, int UE_id, sub_frame_t subframeP, UE_DLSCH_STATUS status ) //------------------------------------------------------------------------------ { eNB_dlsch_info[module_idP][CC_id][UE_id].rnti = UE_RNTI(module_idP,UE_id); // eNB_dlsch_info[module_idP][CC_id][ue_mod_idP].weight = weight; eNB_dlsch_info[module_idP][CC_id][UE_id].subframe = subframeP; eNB_dlsch_info[module_idP][CC_id][UE_id].status = status; eNB_dlsch_info[module_idP][CC_id][UE_id].serving_num++; } //------------------------------------------------------------------------------ int schedule_next_dlue( module_id_t module_idP, int CC_id, sub_frame_t subframeP ) //------------------------------------------------------------------------------ { int next_ue; UE_list_t *UE_list=&RC.mac[module_idP]->UE_list; for (next_ue=UE_list->head; next_ue>=0; next_ue=UE_list->next[next_ue] ) { if (eNB_dlsch_info[module_idP][CC_id][next_ue].status == S_DL_WAITING) { return next_ue; } } for (next_ue=UE_list->head; next_ue>=0; next_ue=UE_list->next[next_ue] ) { if (eNB_dlsch_info[module_idP][CC_id][next_ue].status == S_DL_BUFFERED) { eNB_dlsch_info[module_idP][CC_id][next_ue].status = S_DL_WAITING; } } return(-1);//next_ue; } //------------------------------------------------------------------------------ unsigned char generate_dlsch_header( unsigned char* mac_header, unsigned char num_sdus, unsigned short *sdu_lengths, unsigned char *sdu_lcids, unsigned char drx_cmd, unsigned short timing_advance_cmd, unsigned char *ue_cont_res_id, 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[16],*ce_ptr; ce_ptr = &mac_header_control_elements[0]; // compute header components 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; } if (drx_cmd != 255) { if (first_element>0) { mac_header_ptr->E = 1; mac_header_ptr++; } else { first_element=1; } mac_header_ptr->R = 0; mac_header_ptr->E = 0; mac_header_ptr->LCID = DRX_CMD; last_size=1; } if (timing_advance_cmd != 0) { if (first_element>0) { mac_header_ptr->E = 1; mac_header_ptr++; } else { first_element=1; } mac_header_ptr->R = 0; mac_header_ptr->E = 0; mac_header_ptr->LCID = TIMING_ADV_CMD; last_size=1; // msg("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); ((TIMING_ADVANCE_CMD *)ce_ptr)->R=0; AssertFatal(timing_advance_cmd < 64,"timing_advance_cmd %d > 63\n",timing_advance_cmd); ((TIMING_ADVANCE_CMD *)ce_ptr)->TA=timing_advance_cmd;//(timing_advance_cmd+31)&0x3f; LOG_D(MAC,"timing advance =%d (%d)\n",timing_advance_cmd,((TIMING_ADVANCE_CMD *)ce_ptr)->TA); ce_ptr+=sizeof(TIMING_ADVANCE_CMD); //msg("offset %d\n",ce_ptr-mac_header_control_elements); } if (ue_cont_res_id) { if (first_element>0) { mac_header_ptr->E = 1; /* printf("[eNB][MAC] last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); */ mac_header_ptr++; } else { first_element=1; } mac_header_ptr->R = 0; mac_header_ptr->E = 0; mac_header_ptr->LCID = UE_CONT_RES; last_size=1; LOG_T(MAC,"[eNB ][RAPROC] Generate contention resolution msg: %x.%x.%x.%x.%x.%x\n", ue_cont_res_id[0], ue_cont_res_id[1], ue_cont_res_id[2], ue_cont_res_id[3], ue_cont_res_id[4], ue_cont_res_id[5]); memcpy(ce_ptr,ue_cont_res_id,6); ce_ptr+=6; // msg("(cont_res) : offset %d\n",ce_ptr-mac_header_control_elements); } //msg("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); for (i=0; i<num_sdus; i++) { LOG_T(MAC,"[eNB] Generate DLSCH header num sdu %d len sdu %d\n",num_sdus, sdu_lengths[i]); if (first_element>0) { mac_header_ptr->E = 1; /*msg("last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); */ mac_header_ptr+=last_size; //msg("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); } 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_MSB = ((unsigned short) sdu_lengths[i]>>8)&0x7f; ((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_LSB = (unsigned short) sdu_lengths[i]&0xff; ((SCH_SUBHEADER_LONG *)mac_header_ptr)->padding = 0x00; last_size=3; #ifdef DEBUG_HEADER_PARSING LOG_D(MAC,"[eNB] generate long sdu, size %x (MSB %x, LSB %x)\n", sdu_lengths[i], ((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_MSB, ((SCH_SUBHEADER_LONG *)mac_header_ptr)->L_LSB); #endif } } /* printf("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr); printf("last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr, ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R, ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E, ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID); if (((SCH_SUBHEADER_FIXED*)mac_header_ptr)->LCID < UE_CONT_RES) { if (((SCH_SUBHEADER_SHORT*)mac_header_ptr)->F == 0) printf("F = 0, sdu len (L field) %d\n",(((SCH_SUBHEADER_SHORT*)mac_header_ptr)->L)); else printf("F = 1, sdu len (L field) %d\n",(((SCH_SUBHEADER_LONG*)mac_header_ptr)->L)); } */ 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++; } //msg("After subheaders %d\n",(uint8_t*)mac_header_ptr - mac_header); 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); } //msg("After CEs %d\n",(uint8_t*)mac_header_ptr - mac_header); return((unsigned char*)mac_header_ptr - mac_header); } //------------------------------------------------------------------------------ void set_ul_DAI( int module_idP, int UE_idP, int CC_idP, int frameP, int subframeP ) //------------------------------------------------------------------------------ { eNB_MAC_INST *eNB = RC.mac[module_idP]; UE_list_t *UE_list = &eNB->UE_list; unsigned char DAI; COMMON_channels_t *cc = &eNB->common_channels[CC_idP]; if (cc->tdd_Config != NULL) { //TDD DAI = (UE_list->UE_template[CC_idP][UE_idP].DAI-1)&3; LOG_D(MAC,"[eNB %d] CC_id %d Frame %d, subframe %d: DAI %d for UE %d\n",module_idP,CC_idP,frameP,subframeP,DAI,UE_idP); // Save DAI for Format 0 DCI switch (cc->tdd_Config->subframeAssignment) { case 0: // if ((subframeP==0)||(subframeP==1)||(subframeP==5)||(subframeP==6)) break; case 1: switch (subframeP) { case 1: UE_list->UE_template[CC_idP][UE_idP].DAI_ul[7] = DAI; break; case 4: UE_list->UE_template[CC_idP][UE_idP].DAI_ul[8] = DAI; break; case 6: UE_list->UE_template[CC_idP][UE_idP].DAI_ul[2] = DAI; break; case 9: UE_list->UE_template[CC_idP][UE_idP].DAI_ul[3] = DAI; break; } case 2: // if ((subframeP==3)||(subframeP==8)) // UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI; break; case 3: //if ((subframeP==6)||(subframeP==8)||(subframeP==0)) { // LOG_D(MAC,"schedule_ue_spec: setting UL DAI to %d for subframeP %d => %d\n",DAI,subframeP, ((subframeP+8)%10)>>1); // UE_list->UE_template[CC_idP][UE_idP].DAI_ul[((subframeP+8)%10)>>1] = DAI; //} switch (subframeP) { case 5: case 6: case 1: UE_list->UE_template[CC_idP][UE_idP].DAI_ul[2] = DAI; break; case 7: case 8: UE_list->UE_template[CC_idP][UE_idP].DAI_ul[3] = DAI; break; case 9: case 0: UE_list->UE_template[CC_idP][UE_idP].DAI_ul[4] = DAI; break; default: break; } break; case 4: // if ((subframeP==8)||(subframeP==9)) // UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI; break; case 5: // if (subframeP==8) // UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI; break; case 6: // if ((subframeP==1)||(subframeP==4)||(subframeP==6)||(subframeP==9)) // UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI; break; default: break; } } } // changes to pre-processor for eMTC //------------------------------------------------------------------------------ /*unsigned int getRepetition(UE_TEMPLATE * pue_template){ EPDCCH_SetConfig_r11_t *epdcch_setconfig_r11; AssertFatal(pue_template->physicalConfigDedicated, "no RRC physical configuration for this UE ") ; AssertFatal(pue_template->physicalConfigDedicated->ext4, "no RRC physical configuration for this UE ") ; epdcch_setconfig_r11->setConfigId_r11 = 0; epdcch_setconfig_r11->transmissionType_r11 = EPDCCH_SetConfig_r11__transmissionType_r11_localised; epdcch_setconfig_r11->resourceBlockAssignment_r11.numberPRB_Pairs_r11 = EPDCCH_SetConfig_r11__resourceBlockAssignment_r11__numberPRB_Pairs_r11_n2; //epdcch_setconfig_r11->resourceBlockAssignment_r11.resourceBlockAssignment_r11 = calloc(0, sizeof(BIT_STRING_t)); epdcch_setconfig_r11->resourceBlockAssignment_r11.resourceBlockAssignment_r11.buf = calloc(0, 2 * sizeof(uint8_t)); epdcch_setconfig_r11->resourceBlockAssignment_r11.resourceBlockAssignment_r11.size = 2; epdcch_setconfig_r11->resourceBlockAssignment_r11.resourceBlockAssignment_r11.bits_unused = 6; epdcch_setconfig_r11->resourceBlockAssignment_r11.resourceBlockAssignment_r11.buf[0] = 0x0E; epdcch_setconfig_r11->dmrs_ScramblingSequenceInt_r11 = 0; epdcch_setconfig_r11->pucch_ResourceStartOffset_r11 = 0; epdcch_setconfig_r11->re_MappingQCL_ConfigId_r11 = NULL; epdcch_setconfig_r11->ext2 = calloc(1, sizeof(struct EPDCCH_SetConfig_r11__ext2)); epdcch_setconfig_r11->ext2->numberPRB_Pairs_v1310 = NULL; epdcch_setconfig_r11->ext2->mpdcch_config_r13 = calloc(1, sizeof(struct EPDCCH_SetConfig_r11__ext2__mpdcch_config_r13)); epdcch_setconfig_r11->ext2->mpdcch_config_r13->present = EPDCCH_SetConfig_r11__ext2__mpdcch_config_r13_PR_setup; epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.csi_NumRepetitionCE_r13 = EPDCCH_SetConfig_r11__ext2__mpdcch_config_r13__setup__csi_NumRepetitionCE_r13_sf1; epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.mpdcch_pdsch_HoppingConfig_r13 = EPDCCH_SetConfig_r11__ext2__mpdcch_config_r13__setup__mpdcch_pdsch_HoppingConfig_r13_off; epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.mpdcch_StartSF_UESS_r13.present = EPDCCH_SetConfig_r11__ext2__mpdcch_config_r13__setup__mpdcch_StartSF_UESS_r13_PR_fdd_r13; epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.mpdcch_StartSF_UESS_r13.choice.fdd_r13 = EPDCCH_SetConfig_r11__ext2__mpdcch_config_r13__setup__mpdcch_StartSF_UESS_r13__fdd_r13_v1; epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.mpdcch_NumRepetition_r13 = EPDCCH_SetConfig_r11__ext2__mpdcch_config_r13__setup__mpdcch_NumRepetition_r13_r1; epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.mpdcch_Narrowband_r13 = 3; ASN_SEQUENCE_ADD(physicalConfigDedicated2->ext4->epdcch_Config_r11->config_r11.choice.setup.setConfigToAddModList_r11, epdcch_setconfig_r11); }*/ /* void schedule_ue_spec_br( module_id_t module_idP, frame_t frameP, sub_frame_t subframeP, int* mbsfn_flag ) //------------------------------------------------------------------------------ { uint8_t CC_id; int UE_id; unsigned char aggregation; mac_rlc_status_resp_t rlc_status; unsigned char header_len_dcch = 0, header_len_dcch_tmp = 0; unsigned char header_len_dtch = 0, header_len_dtch_tmp = 0, header_len_dtch_last = 0; unsigned char ta_len = 0; unsigned char sdu_lcids[NB_RB_MAX], lcid, offset, num_sdus = 0; uint16_t nb_rb, nb_rb_temp, nb_available_rb; uint16_t TBS, j, sdu_lengths[NB_RB_MAX], rnti, padding = 0, post_padding = 0; unsigned char dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES]; unsigned char round = 0; unsigned char harq_pid = 0; eNB_UE_STATS *eNB_UE_stats = NULL; uint16_t sdu_length_total = 0; eNB_MAC_INST *eNB = RC.mac[module_idP]; COMMON_channels_t *cc = eNB->common_channels; UE_list_t *UE_list = &eNB->UE_list; int continue_flag = 0; int32_t normalized_rx_power, target_rx_power; int32_t tpc = 1; static int32_t tpc_accumulated = 0; UE_sched_ctrl *ue_sched_ctl; int mcs; int i; int min_rb_unit[MAX_NUM_CCs]; int N_RB_DL[MAX_NUM_CCs]; int total_nb_available_rb[MAX_NUM_CCs]; int N_RBG[MAX_NUM_CCs]; nfapi_dl_config_request_body_t *dl_req; nfapi_dl_config_request_pdu_t *dl_config_pdu; nfapi_tx_request_pdu_t *TX_req; int tdd_sfa; #if 0 if (UE_list->head == -1) { return; } #endif uint8_t *vrb_map; int first_rb; start_meas(&eNB->schedule_dlsch); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, VCD_FUNCTION_IN); // for TDD: check that we have to act here, otherwise return //if (cc[0].tdd_Config) { // tdd_sfa = cc[0].tdd_Config->subframeAssignment; // switch (subframeP) { // case 0: // // always continue // break; // case 1: // return; // break; // case 2: // return; // break; // case 3: // if ((tdd_sfa != 2) && (tdd_sfa != 5)) return; // break; // case 4: // if ((tdd_sfa != 1) && (tdd_sfa != 2) && (tdd_sfa != 4) && (tdd_sfa != 5)) return; // break; // case 5: // break; // case 6: // case 7: // if ((tdd_sfa != 1) && (tdd_sfa != 2) && (tdd_sfa != 4) && (tdd_sfa != 5)) return; // break; // case 8: // if ((tdd_sfa != 2) && (tdd_sfa != 3) && (tdd_sfa != 4) && (tdd_sfa != 5)) return; // break; // case 9: // if ((tdd_sfa != 1) && (tdd_sfa != 3) && (tdd_sfa != 4) && (tdd_sfa != 6)) return; // break; // } //} //weight = get_ue_weight(module_idP,UE_id); aggregation = 2; for (CC_id = 0; CC_id<MAX_NUM_CCs; CC_id++) { N_RB_DL[CC_id] = to_prb(cc[CC_id].mib->message.dl_Bandwidth); min_rb_unit[CC_id] = get_min_rb_unit(module_idP, CC_id); // get number of PRBs less those used by common channels total_nb_available_rb[CC_id] = N_RB_DL[CC_id]; for (i = 0; i<N_RB_DL[CC_id]; i++) if (cc[CC_id].vrb_map[i] != 0) total_nb_available_rb[CC_id]--; N_RBG[CC_id] = to_rbg(cc[CC_id].mib->message.dl_Bandwidth); // store the global enb stats: eNB->eNB_stats[CC_id].num_dlactive_UEs = UE_list->num_UEs; eNB->eNB_stats[CC_id].available_prbs = total_nb_available_rb[CC_id]; eNB->eNB_stats[CC_id].total_available_prbs += total_nb_available_rb[CC_id]; eNB->eNB_stats[CC_id].dlsch_bytes_tx = 0; eNB->eNB_stats[CC_id].dlsch_pdus_tx = 0; } /// CALLING Pre_Processor for downlink scheduling (Returns estimation of RBs required by each UE and the allocation on sub-band) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR, VCD_FUNCTION_IN); //start_meas(&eNB->schedule_dlsch_preprocessor); //dlsch_scheduler_pre_processor(module_idP, // frameP, // subframeP, // N_RBG, // mbsfn_flag); //stop_meas(&eNB->schedule_dlsch_preprocessor); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR, VCD_FUNCTION_OUT); for (CC_id = 0; CC_id<MAX_NUM_CCs; CC_id++) { vrb_map = cc[CC_id].vrb_map; LOG_D(MAC, "doing schedule_ue_spec for CC_id %d\n", CC_id); dl_req = &eNB->DL_req[CC_id].dl_config_request_body; if (mbsfn_flag[CC_id]>0) continue; for (UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { first_rb = 0; vrb_map[first_rb] = 1; vrb_map[first_rb + 1] = 1; vrb_map[first_rb + 2] = 1; vrb_map[first_rb + 3] = 1; vrb_map[first_rb + 4] = 1; vrb_map[first_rb + 5] = 1; continue_flag = 0; // reset the flag to allow allocation for the remaining UEs rnti = UE_RNTI(module_idP, UE_id); eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id]; ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; if (rnti == NOT_A_RNTI) { LOG_D(MAC, "Cannot find rnti for UE_id %d (num_UEs %d)\n", UE_id, UE_list->num_UEs); continue_flag = 1; } if (eNB_UE_stats == NULL) { LOG_D(MAC, "[eNB] Cannot find eNB_UE_stats\n"); continue_flag = 1; } //if (continue_flag != 1) { // switch (get_tmode(module_idP, CC_id, UE_id)) { // case 1: // case 2: // case 7: // aggregation = get_aggregation(get_bw_index(module_idP, CC_id), // eNB_UE_stats->dl_cqi, // format1); // break; // case 3: // aggregation = get_aggregation(get_bw_index(module_idP, CC_id), // eNB_UE_stats->dl_cqi, // format2A); // break; // default: // LOG_W(MAC, "Unsupported transmission mode %d\n", get_tmode(module_idP, CC_id, UE_id)); // aggregation = 2; // } //} if ((ue_sched_ctl->pre_nb_available_rbs[CC_id] == 0) || // no RBs allocated CCE_allocation_infeasible(module_idP, CC_id, 0, subframeP, aggregation, rnti) ) { LOG_D(MAC, "[eNB %d] Frame %d : no RB allocated for UE %d on CC_id %d: continue \n", module_idP, frameP, UE_id, CC_id); continue_flag = 1; //to next user (there might be rbs availiable for other UEs in TM5 } //if (cc[CC_id].tdd_Config != NULL) { //TDD // set_ue_dai(subframeP, // UE_id, // CC_id, // cc[CC_id].tdd_Config->subframeAssignment, // UE_list); // // update UL DAI after DLSCH scheduling // set_ul_DAI(module_idP, UE_id, CC_id, frameP, subframeP); //} //if (continue_flag == 1) { // add_ue_dlsch_info(module_idP, // CC_id, // UE_id, // subframeP, // S_DL_NONE); // continue; // } nb_available_rb = 6; // to be checked harq_pid = ue_sched_ctl->harq_pid[CC_id]; round = ue_sched_ctl->round[CC_id]; UE_list->eNB_UE_stats[CC_id][UE_id].crnti = rnti; UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status = mac_eNB_get_rrc_status(module_idP, rnti); UE_list->eNB_UE_stats[CC_id][UE_id].harq_pid = harq_pid; UE_list->eNB_UE_stats[CC_id][UE_id].harq_round = round; sdu_length_total = 0; num_sdus = 0; //DevCheck(((eNB_UE_stats->dl_cqi < MIN_CQI_VALUE) || (eNB_UE_stats->dl_cqi > MAX_CQI_VALUE)), //eNB_UE_stats->dl_cqi, MIN_CQI_VALUE, MAX_CQI_VALUE); eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[eNB_UE_stats->dl_cqi]; //to be checked eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1, 15); // store stats UE_list->eNB_UE_stats[CC_id][UE_id].dl_cqi = eNB_UE_stats->dl_cqi; // initializing the rb allocation indicator for each UE //to be checked for (j = 0; j<N_RBG[CC_id]; j++) { UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = 0; } LOG_D(MAC, "[eNB %d] Frame %d: Scheduling UE %d on CC_id %d (rnti %x, harq_pid %d, round %d, rb %d, cqi %d, mcs %d, rrc %d)\n", module_idP, frameP, UE_id, CC_id, rnti, harq_pid, round, nb_available_rb, eNB_UE_stats->dl_cqi, eNB_UE_stats->dlsch_mcs1, UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status); // process retransmission if (round > 0) { // get freq_allocation nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; if (nb_rb <= nb_available_rb) { if (cc[CC_id].tdd_Config != NULL) { UE_list->UE_template[CC_id][UE_id].DAI++; update_ul_dci(module_idP, CC_id, rnti, UE_list->UE_template[CC_id][UE_id].DAI); LOG_D(MAC, "DAI update: CC_id %d subframeP %d: UE %d, DAI %d\n", CC_id, subframeP, UE_id, UE_list->UE_template[CC_id][UE_id].DAI); } if (nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { for (j = 0; j<N_RBG[CC_id]; j++) { // for indicating the rballoc for each sub-band UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; } } else { nb_rb_temp = nb_rb; j = 0; while ((nb_rb_temp > 0) && (j<N_RBG[CC_id])) { if (ue_sched_ctl->rballoc_sub_UE[CC_id][j] == 1) { UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; if ((j == N_RBG[CC_id] - 1) && ((N_RB_DL[CC_id] == 25) || (N_RB_DL[CC_id] == 50))) { nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id] + 1; } else { nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]; } } j = j + 1; } } nb_available_rb -= nb_rb; //eNB->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; //eNB->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id]; //for(j=0; j<N_RBG[CC_id]; j++) { //eNB->mu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; //} switch (get_tmode(module_idP, CC_id, UE_id)) { case 1: case 2: case 7: default: { // rmax from SIB2 information rmax = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->mpdcch_NumRepetition_RA_r13; // choose r3 by default for RAR (Table 9.1.5-5) rep = 2; // get actual repetition count from Table 9.1.5-3 reps = (rmax <= 8) ? (1 << rep) : (rmax >> (3 - rep)); // get narrowband according to higher-layer config num_nb = p[RA_template->rach_resource_type - 1]->mpdcch_NarrowbandsToMonitor_r13.list.count; RA_template->msg2_narrowband = *p[RA_template->rach_resource_type - 1]->mpdcch_NarrowbandsToMonitor_r13.list.array[RA_template->preamble_index%num_nb]; first_rb = RA_template->msg2_narrowband * 6; if ((RA_template->msg2_mpdcch_repetition_cnt == 0) && (mpdcch_sf_condition(eNB, CC_idP, frameP, subframeP, rmax, TYPE2)>0)) { // MPDCCH configuration for RAR memset((void*)dl_config_pdu, 0, sizeof(nfapi_dl_config_request_pdu_t)); dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_MPDCCH_PDU_TYPE; dl_config_pdu->pdu_size = (uint8_t)(2 + sizeof(nfapi_dl_config_mpdcch_pdu)); dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_format = (RA_template->rach_resource_type > 1) ? 11 : 10; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_narrow_band = RA_template->msg2_narrowband; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.number_of_prb_pairs = 6; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_assignment = 0; // Note: this can be dynamic dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_tansmission_type = 1; // imposed (9.1.5 in 213) for Type 2 Common search space AssertFatal(cc[CC_idP].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13 != NULL, "cc[CC_id].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13 is null\n"); dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.start_symbol = cc[CC_idP].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->startSymbolBR_r13; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ecce_index = 0; // Note: this should be dynamic dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.aggregation_level = 16; // OK for CEModeA r1-3 (9.1.5-1b) or CEModeB r1-4 dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti_type = 2; // RA-RNTI dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti = RA_template->RA_rnti; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ce_mode = (RA_template->rach_resource_type < 3) ? 1 : 2; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.drms_scrambling_init = cc[CC_idP].physCellId; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.initial_transmission_sf_io = (frameP * 10) + subframeP; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.transmission_power = 6000; // 0dB dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_coding = getRIV(6, 0, 6); // Note: still to be checked if it should not be (getRIV(N_RB_DL,first_rb,6)) : Check nFAPI specifications and what is done L1 with this parameter dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mcs = 4; // adjust according to size of RAR, 208 bits with N1A_PRB=3 dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pdsch_reptition_levels = 4; // fix to 4 for now dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.redundancy_version = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.new_data_indicator = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_process = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi_length = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi_flag = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_resource_offset = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_subframe_repetition_number = rep; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpc = 1;// N1A_PRB=3 (36.212); => 208 bits for mcs=4, choose mcs according t message size TBD dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.downlink_assignment_index_length = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.downlink_assignment_index = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.allocate_prach_flag = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.preamble_index = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.prach_mask_index = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.starting_ce_level = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.srs_request = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity_flag = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.frequency_hopping_enabled_flag = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.paging_direct_indication_differentiation_flag = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.direct_indication = 0; dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.total_dci_length_including_padding = 0; // this is not needed by OAI L1, but should be filled in dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.number_of_tx_antenna_ports = 1; RA_template->msg2_mpdcch_repetition_cnt++; dl_req->number_pdu++; } //repetition_count==0 && SF condition met else if (RA_template->msg2_mpdcch_repetition_cnt>0) { // we're in a stream of repetitions RA_template->msg2_mpdcch_repetition_cnt++; if (RA_template->msg2_mpdcch_repetition_cnt == reps) { // this is the last mpdcch repetition if (cc[CC_idP].tdd_Config == NULL) { // FDD case // wait 2 subframes for PDSCH transmission if (subframeP>7) RA_template->Msg2_frame = (frameP + 1) & 1023; else RA_template->Msg2_frame = frameP; RA_template->Msg2_subframe = (subframeP + 2) % 10; // +2 is the "n+x" from Section 7.1.11 in 36.213 } else { AssertFatal(1 == 0, "TDD case not done yet\n"); } } // mpdcch_repetition_count == reps if ((RA_template->Msg2_frame == frameP) && (RA_template->Msg2_subframe == subframeP)) { // Program PDSCH RA_template->generate_rar = 0; 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.pdu_index = eNB->pdu_index[CC_idP]; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = RA_template->RA_rnti; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2; // format 1A/1B/1D dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0; // localized dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = getRIV(N_RB_DL, first_rb, 6); dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = 0; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1;// first block dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = 0; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = (cc->p_eNB == 1) ? 0 : 1; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = 1; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = 1; // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index = ; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = 1; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = 0; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = (cc->p_eNB == 1) ? 1 : 2; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = 1; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1; // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector = ; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = (RA_template->rach_resource_type < 3) ? 1 : 2;; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 2; // not SI message dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = (10 * frameP) + subframeP; dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.drms_table_flag = 0; dl_req->number_pdu++; // Program UL processing for Msg3, same as regular LTE get_Msg3alloc(&cc[CC_idP], subframeP, frameP, &RA_template->Msg3_frame, &RA_template->Msg3_subframe); fill_rar_br(eNB, CC_idP, RA_template, frameP, subframeP, cc[CC_idP].RAR_pdu.payload, RA_template->rach_resource_type - 1); // DL request eNB->TX_req[CC_idP].sfn_sf = (frameP << 3) + subframeP; TX_req = &eNB->TX_req[CC_idP].tx_request_body.tx_pdu_list[eNB->TX_req[CC_idP].tx_request_body.number_of_pdus]; TX_req->pdu_length = 7; // This should be changed if we have more than 1 preamble TX_req->pdu_index = eNB->pdu_index[CC_idP]++; TX_req->num_segments = 1; TX_req->segments[0].segment_length = 7; TX_req->segments[0].segment_data = cc[CC_idP].RAR_pdu.payload; eNB->TX_req[CC_idP].tx_request_body.number_of_pdus++; } } } //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_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_1; //dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = get_aggregation(get_bw_index(module_idP, CC_id), eNB_UE_stats->dl_cqi, format1); // dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; //dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1; // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications //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_pid; //dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = 1; // dont adjust power when retransmitting // dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; // dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid]; // dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = round & 3; if (!CCE_allocation_infeasible(module_idP, CC_id, 0, subframeP, dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, rnti)) { dl_req->number_dci++; dl_req->number_pdu++; } else { // No TX request for retransmission (check if null request for FAPI) } } add_ue_dlsch_info(module_idP, CC_id, UE_id, subframeP, S_DL_SCHEDULED); //eNB_UE_stats->dlsch_trials[round]++; UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission += 1; UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx = nb_rb; UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_retx += nb_rb; UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 = eNB_UE_stats->dlsch_mcs1; UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2 = eNB_UE_stats->dlsch_mcs1; } else { LOG_D(MAC, "[eNB %d] Frame %d CC_id %d : don't schedule UE %d, its retransmission takes more resources than we have\n", module_idP, frameP, CC_id, UE_id); } } else { // This is a potentially new SDU opportunity rlc_status.bytes_in_buffer = 0; // Now check RLC information to compute number of required RBs // get maximum TBS size for RLC request //to be checked TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1, nb_available_rb); // check first for RLC data on DCCH // add the length for all the control elements (timing adv, drx, etc) : header + payload ta_len = (ue_sched_ctl->ta_update != 0) ? 2 : 0; header_len_dcch = 2; // 2 bytes DCCH SDU subheader if (TBS - ta_len - header_len_dcch > 0) { rlc_status = mac_rlc_status_ind( module_idP, rnti, module_idP, frameP, subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH, (TBS - ta_len - header_len_dcch)); // transport block set size sdu_lengths[0] = 0; if (rlc_status.bytes_in_buffer > 0) { // There is DCCH to transmit LOG_D(MAC, "[eNB %d] Frame %d, DL-DCCH->DLSCH CC_id %d, Requesting %d bytes from RLC (RRC message)\n", module_idP, frameP, CC_id, TBS - header_len_dcch); sdu_lengths[0] = mac_rlc_data_req( module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH, TBS, //not used (char *)&dlsch_buffer[0]); T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP), T_INT(harq_pid), T_INT(DCCH), T_INT(sdu_lengths[0])); LOG_D(MAC, "[eNB %d][DCCH] CC_id %d Got %d bytes from RLC\n", module_idP, CC_id, sdu_lengths[0]); sdu_length_total = sdu_lengths[0]; sdu_lcids[0] = DCCH; UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[DCCH] += 1; UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH] += sdu_lengths[0]; num_sdus = 1; #ifdef DEBUG_eNB_SCHEDULER LOG_T(MAC, "[eNB %d][DCCH] CC_id %d Got %d bytes :", module_idP, CC_id, sdu_lengths[0]); for (j = 0; j<sdu_lengths[0]; j++) { LOG_T(MAC, "%x ", dlsch_buffer[j]); } LOG_T(MAC, "\n"); #endif } else { header_len_dcch = 0; sdu_length_total = 0; } } // check for DCCH1 and update header information (assume 2 byte sub-header) if (TBS - ta_len - header_len_dcch - sdu_length_total > 0) { rlc_status = mac_rlc_status_ind( module_idP, rnti, module_idP, frameP, subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH + 1, (TBS - ta_len - header_len_dcch - sdu_length_total)); // transport block set size less allocations for timing advance and // DCCH SDU sdu_lengths[num_sdus] = 0; if (rlc_status.bytes_in_buffer > 0) { LOG_I(MAC, "[eNB %d], Frame %d, DCCH1->DLSCH, CC_id %d, Requesting %d bytes from RLC (RRC message)\n", module_idP, frameP, CC_id, TBS - header_len_dcch - sdu_length_total); sdu_lengths[num_sdus] += mac_rlc_data_req( module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH + 1, TBS, //not used (char *)&dlsch_buffer[sdu_length_total]); T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP), T_INT(harq_pid), T_INT(DCCH + 1), T_INT(sdu_lengths[num_sdus])); sdu_lcids[num_sdus] = DCCH1; sdu_length_total += sdu_lengths[num_sdus]; header_len_dcch += 2; UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[DCCH1] += 1; UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH1] += sdu_lengths[num_sdus]; num_sdus++; #ifdef DEBUG_eNB_SCHEDULER LOG_T(MAC, "[eNB %d][DCCH1] CC_id %d Got %d bytes :", module_idP, CC_id, sdu_lengths[num_sdus]); for (j = 0; j<sdu_lengths[num_sdus]; j++) { LOG_T(MAC, "%x ", dlsch_buffer[j]); } LOG_T(MAC, "\n"); #endif } } // assume the max dtch header size, and adjust it later header_len_dtch = 0; header_len_dtch_last = 0; // the header length of the last mac sdu // lcid has to be sorted before the actual allocation (similar struct as ue_list). for (lcid = NB_RB_MAX - 1; lcid >= DTCH; lcid--) { // TBD: check if the lcid is active header_len_dtch += 3; header_len_dtch_last = 3; LOG_D(MAC, "[eNB %d], Frame %d, DTCH%d->DLSCH, Checking RLC status (tbs %d, len %d)\n", module_idP, frameP, lcid, TBS, TBS - ta_len - header_len_dcch - sdu_length_total - header_len_dtch); if (TBS - ta_len - header_len_dcch - sdu_length_total - header_len_dtch > 0) { // NN: > 2 ? rlc_status = mac_rlc_status_ind(module_idP, rnti, module_idP, frameP, subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, TBS - ta_len - header_len_dcch - sdu_length_total - header_len_dtch); if (rlc_status.bytes_in_buffer > 0) { LOG_D(MAC, "[eNB %d][USER-PLANE DEFAULT DRB] Frame %d : DTCH->DLSCH, Requesting %d bytes from RLC (lcid %d total hdr len %d)\n", module_idP, frameP, TBS - header_len_dcch - sdu_length_total - header_len_dtch, lcid, header_len_dtch); sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, TBS, //not used (char*)&dlsch_buffer[sdu_length_total]); T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP), T_INT(harq_pid), T_INT(lcid), T_INT(sdu_lengths[num_sdus])); LOG_D(MAC, "[eNB %d][USER-PLANE DEFAULT DRB] Got %d bytes for DTCH %d \n", module_idP, sdu_lengths[num_sdus], lcid); sdu_lcids[num_sdus] = lcid; sdu_length_total += sdu_lengths[num_sdus]; UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[lcid] += 1; UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[lcid] += sdu_lengths[num_sdus]; if (sdu_lengths[num_sdus] < 128) { header_len_dtch--; header_len_dtch_last--; } num_sdus++; } // no data for this LCID else { header_len_dtch -= 3; } } // no TBS left else { header_len_dtch -= 3; break; } } if (header_len_dtch == 0) header_len_dtch_last = 0; // there is at least one SDU // if (num_sdus > 0 ){ if ((sdu_length_total + header_len_dcch + header_len_dtch)> 0) { // Now compute number of required RBs for total sdu length // Assume RAH format 2 // adjust header lengths header_len_dcch_tmp = header_len_dcch; header_len_dtch_tmp = header_len_dtch; if (header_len_dtch == 0) { header_len_dcch = (header_len_dcch >0) ? 1 : 0;//header_len_dcch; // remove length field } else { header_len_dtch_last -= 1; // now use it to find how many bytes has to be removed for the last MAC SDU header_len_dtch = (header_len_dtch > 0) ? header_len_dtch - header_len_dtch_last : header_len_dtch; // remove length field for the last SDU } mcs = eNB_UE_stats->dlsch_mcs1; if (mcs == 0) { nb_rb = 4; // don't let the TBS get too small } else { nb_rb = min_rb_unit[CC_id]; } TBS = get_TBS_DL(mcs, nb_rb); while (TBS < (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) { nb_rb += min_rb_unit[CC_id]; // if (nb_rb>nb_available_rb) { // if we've gone beyond the maximum number of RBs // (can happen if N_RB_DL is odd) TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1, nb_available_rb); nb_rb = nb_available_rb; break; } TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1, nb_rb); } ///////////////////////////////////////////////////////////// // alter the allocation of the emtc UE here ////////////////////////////////////////////////////////////// if (nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { for (j = 0; j<N_RBG[CC_id]; j++) { // for indicating the rballoc for each sub-band UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; } } else { nb_rb_temp = nb_rb; j = 0; while ((nb_rb_temp > 0) && (j<N_RBG[CC_id])) { if (ue_sched_ctl->rballoc_sub_UE[CC_id][j] == 1) { UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; if ((j == N_RBG[CC_id] - 1) && ((N_RB_DL[CC_id] == 25) || (N_RB_DL[CC_id] == 50))) { nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id] + 1; } else { nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]; } } j = j + 1; } } /////////////////////////////////// // decrease mcs until TBS falls below required length while ((TBS > (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && (mcs>0)) { mcs--; TBS = get_TBS_DL(mcs, nb_rb); } // if we have decreased too much or we don't have enough RBs, increase MCS while ((TBS < (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && (((ue_sched_ctl->dl_pow_off[CC_id]>0) && (mcs<28)) || ((ue_sched_ctl->dl_pow_off[CC_id] == 0) && (mcs <= 15)))) { mcs++; TBS = get_TBS_DL(mcs, nb_rb); } LOG_D(MAC, "dlsch_mcs before and after the rate matching = (%d, %d)\n", eNB_UE_stats->dlsch_mcs1, mcs); #ifdef DEBUG_eNB_SCHEDULER LOG_D(MAC, "[eNB %d] CC_id %d Generated DLSCH header (mcs %d, TBS %d, nb_rb %d)\n", module_idP, CC_id, mcs, TBS, nb_rb); // msg("[MAC][eNB ] Reminder of DLSCH with random data %d %d %d %d \n", // TBS, sdu_length_total, offset, TBS-sdu_length_total-offset); #endif if ((TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len) <= 2) { padding = (TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len); post_padding = 0; } else { padding = 0; // adjust the header len if (header_len_dtch == 0) { header_len_dcch = header_len_dcch_tmp; } else { //if (( header_len_dcch==0)&&((header_len_dtch==1)||(header_len_dtch==2))) header_len_dtch = header_len_dtch_tmp; } post_padding = TBS - sdu_length_total - header_len_dcch - header_len_dtch - ta_len; // 1 is for the postpadding header } offset = generate_dlsch_header((unsigned char*)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], num_sdus, //num_sdus sdu_lengths, // sdu_lcids, 255, // no drx ue_sched_ctl->ta_update, // timing advance NULL, // contention res id padding, post_padding); //#ifdef DEBUG_eNB_SCHEDULER if (ue_sched_ctl->ta_update) { LOG_I(MAC, "[eNB %d][DLSCH] Frame %d Generate header for UE_id %d on CC_id %d: sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d,timing advance value : %d, padding %d,post_padding %d,(mcs %d, TBS %d, nb_rb %d),header_dcch %d, header_dtch %d\n", module_idP, frameP, UE_id, CC_id, sdu_length_total, num_sdus, sdu_lengths[0], sdu_lcids[0], offset, ue_sched_ctl->ta_update, padding, post_padding, mcs, TBS, nb_rb, header_len_dcch, header_len_dtch); } //#endif #ifdef DEBUG_eNB_SCHEDULER LOG_T(MAC, "[eNB %d] First 16 bytes of DLSCH : \n"); for (i = 0; i<16; i++) { LOG_T(MAC, "%x.", dlsch_buffer[i]); } LOG_T(MAC, "\n"); #endif // cycle through SDUs and place in dlsch_buffer memcpy(&UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset], dlsch_buffer, sdu_length_total); // memcpy(RC.mac[0].DLSCH_pdu[0][0].payload[0][offset],dcch_buffer,sdu_lengths[0]); // fill remainder of DLSCH with random data UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb; for (j = 0; j<(TBS - sdu_length_total - offset); j++) { UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset + sdu_length_total + j] = (char)(taus() & 0xff); } if (opt_enabled == 1) { trace_pdu(1, (uint8_t *)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], TBS, module_idP, 3, UE_RNTI(module_idP, UE_id), eNB->frame, eNB->subframe, 0, 0); LOG_D(OPT, "[eNB %d][DLSCH] CC_id %d Frame %d rnti %x with size %d\n", module_idP, CC_id, frameP, UE_RNTI(module_idP, UE_id), TBS); } T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP), T_INT(harq_pid), T_BUFFER(UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], TBS)); UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid] = nb_rb; add_ue_dlsch_info(module_idP, CC_id, UE_id, subframeP, S_DL_SCHEDULED); // store stats eNB->eNB_stats[CC_id].dlsch_bytes_tx += sdu_length_total; eNB->eNB_stats[CC_id].dlsch_pdus_tx += 1; UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb; UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used += nb_rb; UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 = eNB_UE_stats->dlsch_mcs1; UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2 = mcs; UE_list->eNB_UE_stats[CC_id][UE_id].TBS = TBS; UE_list->eNB_UE_stats[CC_id][UE_id].overhead_bytes = TBS - sdu_length_total; UE_list->eNB_UE_stats[CC_id][UE_id].total_sdu_bytes += sdu_length_total; UE_list->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes += TBS; UE_list->eNB_UE_stats[CC_id][UE_id].total_num_pdus += 1; // do PUCCH power control // this is the normalized RX power eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id]; normalized_rx_power = eNB_UE_stats->Po_PUCCH_dBm; target_rx_power = get_target_pucch_rx_power(module_idP, CC_id) + 20; // this assumes accumulated tpc // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out int32_t framex10psubframe = UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame * 10 + UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe; if (((framex10psubframe + 10) <= (frameP * 10 + subframeP)) || //normal case ((framex10psubframe>(frameP * 10 + subframeP)) && (((10240 - framex10psubframe + frameP * 10 + subframeP) >= 10)))) //frame wrap-around if (eNB_UE_stats->Po_PUCCH_update == 1) { eNB_UE_stats->Po_PUCCH_update = 0; UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame = frameP; UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe = subframeP; if (normalized_rx_power>(target_rx_power + 1)) { tpc = 0; //-1 tpc_accumulated--; } else if (normalized_rx_power<(target_rx_power - 1)) { tpc = 2; //+1 tpc_accumulated++; } else { tpc = 1; //0 } } // Po_PUCCH has been updated else { tpc = 1; //0 } // time to do TPC update else { tpc = 1; //0 } //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_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_1; //dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = get_aggregation(get_bw_index(module_idP, CC_id), eNB_UE_stats->dl_cqi, format1); //dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; //dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1; // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications //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_pid; //dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = tpc; // dont adjust power when retransmitting //dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; //dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs; //dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = 0; ////deactivate second codeword //dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_2 = 0; //dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_2 = 1; // dl_req->number_dci++; dl_req->number_pdu++; // Toggle NDI for next time LOG_D(MAC, "CC_id %d Frame %d, subframeP %d: Toggling Format1 NDI for UE %d (rnti %x/%d) oldNDI %d\n", CC_id, frameP, subframeP, UE_id, UE_list->UE_template[CC_id][UE_id].rnti, harq_pid, UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]); UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid] = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid] = mcs; UE_list->UE_template[CC_id][UE_id].oldmcs2[harq_pid] = 0; eNB->TX_req[CC_id].sfn_sf = (frameP << 3) + subframeP; TX_req = &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB->TX_req[CC_id].tx_request_body.number_of_pdus]; TX_req->pdu_length = TBS; TX_req->pdu_index = eNB->pdu_index[CC_id]++; TX_req->num_segments = 1; TX_req->segments[0].segment_length = TBS; TX_req->segments[0].segment_data = eNB->UE_list.DLSCH_pdu[CC_id][0][(unsigned char)UE_id].payload[harq_pid]; eNB->TX_req[CC_id].tx_request_body.number_of_pdus++; } else { // There is no data from RLC or MAC header, so don't schedule } } } // UE_id loop } // CC_id loop fill_DLSCH_dci(module_idP, frameP, subframeP, mbsfn_flag); stop_meas(&eNB->schedule_dlsch); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, VCD_FUNCTION_OUT); }*/ //------------------------------------------------------------------------------ void schedule_ue_spec( module_id_t module_idP, frame_t frameP, sub_frame_t subframeP, int* mbsfn_flag ) //------------------------------------------------------------------------------ { uint8_t CC_id; int UE_id; unsigned char aggregation; mac_rlc_status_resp_t rlc_status; unsigned char header_len_dcch=0, header_len_dcch_tmp=0; unsigned char header_len_dtch=0, header_len_dtch_tmp=0, header_len_dtch_last=0; unsigned char ta_len=0; unsigned char sdu_lcids[NB_RB_MAX],lcid,offset,num_sdus=0; uint16_t nb_rb,nb_rb_temp,nb_available_rb; uint16_t TBS,j,sdu_lengths[NB_RB_MAX],rnti,padding=0,post_padding=0; unsigned char dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES]; unsigned char round = 0; unsigned char harq_pid = 0; eNB_UE_STATS *eNB_UE_stats = NULL; uint16_t sdu_length_total = 0; eNB_MAC_INST *eNB = RC.mac[module_idP]; COMMON_channels_t *cc = eNB->common_channels; UE_list_t *UE_list = &eNB->UE_list; int continue_flag=0; int32_t normalized_rx_power, target_rx_power; int32_t tpc=1; static int32_t tpc_accumulated=0; UE_sched_ctrl *ue_sched_ctl; int mcs; int i; int min_rb_unit[MAX_NUM_CCs]; int N_RB_DL[MAX_NUM_CCs]; int total_nb_available_rb[MAX_NUM_CCs]; int N_RBG[MAX_NUM_CCs]; nfapi_dl_config_request_body_t *dl_req; nfapi_dl_config_request_pdu_t *dl_config_pdu; nfapi_tx_request_pdu_t *TX_req; int tdd_sfa; #if 0 if (UE_list->head==-1) { return; } #endif start_meas(&eNB->schedule_dlsch); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH,VCD_FUNCTION_IN); // for TDD: check that we have to act here, otherwise return if (cc[0].tdd_Config) { tdd_sfa = cc[0].tdd_Config->subframeAssignment; switch (subframeP) { case 0: // always continue break; case 1: return; break; case 2: return; break; case 3: if ((tdd_sfa!=2) && (tdd_sfa!=5)) return; break; case 4: if ((tdd_sfa!=1)&&(tdd_sfa!=2)&&(tdd_sfa!=4)&&(tdd_sfa!=5)) return; break; case 5: break; case 6: case 7: if ((tdd_sfa!=1)&&(tdd_sfa!=2)&&(tdd_sfa!=4)&&(tdd_sfa!=5)) return; break; case 8: if ((tdd_sfa!=2)&&(tdd_sfa!=3)&&(tdd_sfa!=4)&&(tdd_sfa!=5)) return; break; case 9: if ((tdd_sfa!=1)&&(tdd_sfa!=3)&&(tdd_sfa!=4)&&(tdd_sfa!=6)) return; break; } } //weight = get_ue_weight(module_idP,UE_id); aggregation = 2; for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { N_RB_DL[CC_id] = to_prb(cc[CC_id].mib->message.dl_Bandwidth); min_rb_unit[CC_id]=get_min_rb_unit(module_idP,CC_id); // get number of PRBs less those used by common channels total_nb_available_rb[CC_id] = N_RB_DL[CC_id]; for (i=0;i<N_RB_DL[CC_id];i++) if (cc[CC_id].vrb_map[i]!=0) total_nb_available_rb[CC_id]--; N_RBG[CC_id] = to_rbg(cc[CC_id].mib->message.dl_Bandwidth); // store the global enb stats: eNB->eNB_stats[CC_id].num_dlactive_UEs = UE_list->num_UEs; eNB->eNB_stats[CC_id].available_prbs = total_nb_available_rb[CC_id]; eNB->eNB_stats[CC_id].total_available_prbs += total_nb_available_rb[CC_id]; eNB->eNB_stats[CC_id].dlsch_bytes_tx = 0; eNB->eNB_stats[CC_id].dlsch_pdus_tx = 0; } /// CALLING Pre_Processor for downlink scheduling (Returns estimation of RBs required by each UE and the allocation on sub-band) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR,VCD_FUNCTION_IN); start_meas(&eNB->schedule_dlsch_preprocessor); dlsch_scheduler_pre_processor(module_idP, frameP, subframeP, N_RBG, mbsfn_flag); stop_meas(&eNB->schedule_dlsch_preprocessor); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR,VCD_FUNCTION_OUT); for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { LOG_D(MAC, "doing schedule_ue_spec for CC_id %d\n",CC_id); dl_req = &eNB->DL_req[CC_id].dl_config_request_body; if (mbsfn_flag[CC_id]>0) continue; for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) { continue_flag=0; // reset the flag to allow allocation for the remaining UEs rnti = UE_RNTI(module_idP,UE_id); eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id]; ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id]; if (rnti==NOT_A_RNTI) { LOG_D(MAC,"Cannot find rnti for UE_id %d (num_UEs %d)\n",UE_id,UE_list->num_UEs); continue_flag=1; } if (eNB_UE_stats==NULL) { LOG_D(MAC,"[eNB] Cannot find eNB_UE_stats\n"); continue_flag=1; } if (continue_flag != 1){ switch(get_tmode(module_idP,CC_id,UE_id)){ case 1: case 2: case 7: aggregation = get_aggregation(get_bw_index(module_idP,CC_id), eNB_UE_stats->dl_cqi, format1); break; case 3: aggregation = get_aggregation(get_bw_index(module_idP,CC_id), eNB_UE_stats->dl_cqi, format2A); break; default: LOG_W(MAC,"Unsupported transmission mode %d\n", get_tmode(module_idP,CC_id,UE_id)); aggregation = 2; } } /* if (continue_flag != 1 */ if ((ue_sched_ctl->pre_nb_available_rbs[CC_id] == 0) || // no RBs allocated CCE_allocation_infeasible(module_idP,CC_id,0,subframeP,aggregation,rnti) ) { LOG_D(MAC,"[eNB %d] Frame %d : no RB allocated for UE %d on CC_id %d: continue \n", module_idP, frameP, UE_id, CC_id); continue_flag=1; //to next user (there might be rbs availiable for other UEs in TM5 } if (cc[CC_id].tdd_Config != NULL) { //TDD set_ue_dai (subframeP, UE_id, CC_id, cc[CC_id].tdd_Config->subframeAssignment, UE_list); // update UL DAI after DLSCH scheduling set_ul_DAI(module_idP,UE_id,CC_id,frameP,subframeP); } if (continue_flag == 1 ) { add_ue_dlsch_info(module_idP, CC_id, UE_id, subframeP, S_DL_NONE); continue; } nb_available_rb = ue_sched_ctl->pre_nb_available_rbs[CC_id]; harq_pid = ue_sched_ctl->harq_pid[CC_id]; round = ue_sched_ctl->round[CC_id]; UE_list->eNB_UE_stats[CC_id][UE_id].crnti= rnti; UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status=mac_eNB_get_rrc_status(module_idP,rnti); UE_list->eNB_UE_stats[CC_id][UE_id].harq_pid = harq_pid; UE_list->eNB_UE_stats[CC_id][UE_id].harq_round = round; sdu_length_total=0; num_sdus=0; /* DevCheck(((eNB_UE_stats->dl_cqi < MIN_CQI_VALUE) || (eNB_UE_stats->dl_cqi > MAX_CQI_VALUE)), eNB_UE_stats->dl_cqi, MIN_CQI_VALUE, MAX_CQI_VALUE); */ eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[eNB_UE_stats->dl_cqi]; eNB_UE_stats->dlsch_mcs1 = eNB_UE_stats->dlsch_mcs1;//cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs); // store stats UE_list->eNB_UE_stats[CC_id][UE_id].dl_cqi= eNB_UE_stats->dl_cqi; // initializing the rb allocation indicator for each UE for(j=0; j<N_RBG[CC_id]; j++) { UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = 0; } LOG_D(MAC,"[eNB %d] Frame %d: Scheduling UE %d on CC_id %d (rnti %x, harq_pid %d, round %d, rb %d, cqi %d, mcs %d, rrc %d)\n", module_idP, frameP, UE_id,CC_id,rnti,harq_pid, round,nb_available_rb, eNB_UE_stats->dl_cqi, eNB_UE_stats->dlsch_mcs1, UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status); /* process retransmission */ if (round > 0) { // get freq_allocation nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; if (nb_rb <= nb_available_rb) { if (cc[CC_id].tdd_Config != NULL) { UE_list->UE_template[CC_id][UE_id].DAI++; update_ul_dci(module_idP,CC_id,rnti,UE_list->UE_template[CC_id][UE_id].DAI); LOG_D(MAC,"DAI update: CC_id %d subframeP %d: UE %d, DAI %d\n", CC_id,subframeP,UE_id,UE_list->UE_template[CC_id][UE_id].DAI); } if(nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { for(j=0; j<N_RBG[CC_id]; j++) { // for indicating the rballoc for each sub-band UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; } } else { nb_rb_temp = nb_rb; j = 0; while((nb_rb_temp > 0) && (j<N_RBG[CC_id])) { if(ue_sched_ctl->rballoc_sub_UE[CC_id][j] == 1) { UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; if((j == N_RBG[CC_id]-1) && ((N_RB_DL[CC_id] == 25)|| (N_RB_DL[CC_id] == 50))) { nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]+1; } else { nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]; } } j = j+1; } } nb_available_rb -= nb_rb; /* eNB->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; eNB->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id]; for(j=0; j<N_RBG[CC_id]; j++) { eNB->mu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; } */ switch (get_tmode(module_idP,CC_id,UE_id)) { case 1: case 2: case 7: default: 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_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_1; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = get_aggregation(get_bw_index(module_idP,CC_id),eNB_UE_stats->dl_cqi,format1); dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1; // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications 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_pid; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = 1; // dont adjust power when retransmitting dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid]; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = round&3; if (cc[CC_id].tdd_Config != NULL) { //TDD dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.downlink_assignment_index = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, dai %d, mcs %d\n", module_idP,CC_id,harq_pid,round, (UE_list->UE_template[CC_id][UE_id].DAI-1), UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid]); } else { LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, mcs %d\n", module_idP,CC_id,harq_pid,round, UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid]); } if (!CCE_allocation_infeasible(module_idP,CC_id,0,subframeP, dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, rnti)) { dl_req->number_dci++; dl_req->number_pdu++; } else { // No TX request for retransmission (check if null request for FAPI) } } add_ue_dlsch_info(module_idP, CC_id, UE_id, subframeP, S_DL_SCHEDULED); //eNB_UE_stats->dlsch_trials[round]++; UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission+=1; UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx=nb_rb; UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_retx+=nb_rb; UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1=eNB_UE_stats->dlsch_mcs1; UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2=eNB_UE_stats->dlsch_mcs1; } else { LOG_D(MAC,"[eNB %d] Frame %d CC_id %d : don't schedule UE %d, its retransmission takes more resources than we have\n", module_idP, frameP, CC_id, UE_id); } } else { /* This is a potentially new SDU opportunity */ rlc_status.bytes_in_buffer = 0; // Now check RLC information to compute number of required RBs // get maximum TBS size for RLC request TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1,nb_available_rb); // check first for RLC data on DCCH // add the length for all the control elements (timing adv, drx, etc) : header + payload ta_len = (ue_sched_ctl->ta_update!=0) ? 2 : 0; header_len_dcch = 2; // 2 bytes DCCH SDU subheader if ( TBS-ta_len-header_len_dcch > 0 ) { rlc_status = mac_rlc_status_ind( module_idP, rnti, module_idP, frameP, subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH, (TBS-ta_len-header_len_dcch)); // transport block set size sdu_lengths[0]=0; if (rlc_status.bytes_in_buffer > 0) { // There is DCCH to transmit LOG_D(MAC,"[eNB %d] Frame %d, DL-DCCH->DLSCH CC_id %d, Requesting %d bytes from RLC (RRC message)\n", module_idP,frameP,CC_id,TBS-header_len_dcch); sdu_lengths[0] = mac_rlc_data_req( module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH, TBS, //not used (char *)&dlsch_buffer[0]); T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP), T_INT(harq_pid), T_INT(DCCH), T_INT(sdu_lengths[0])); LOG_D(MAC,"[eNB %d][DCCH] CC_id %d Got %d bytes from RLC\n",module_idP,CC_id,sdu_lengths[0]); sdu_length_total = sdu_lengths[0]; sdu_lcids[0] = DCCH; UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[DCCH]+=1; UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH]+=sdu_lengths[0]; num_sdus = 1; #ifdef DEBUG_eNB_SCHEDULER LOG_T(MAC,"[eNB %d][DCCH] CC_id %d Got %d bytes :",module_idP,CC_id,sdu_lengths[0]); for (j=0; j<sdu_lengths[0]; j++) { LOG_T(MAC,"%x ",dlsch_buffer[j]); } LOG_T(MAC,"\n"); #endif } else { header_len_dcch = 0; sdu_length_total = 0; } } // check for DCCH1 and update header information (assume 2 byte sub-header) if (TBS-ta_len-header_len_dcch-sdu_length_total > 0 ) { rlc_status = mac_rlc_status_ind( module_idP, rnti, module_idP, frameP, subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH+1, (TBS-ta_len-header_len_dcch-sdu_length_total)); // transport block set size less allocations for timing advance and // DCCH SDU sdu_lengths[num_sdus] = 0; if (rlc_status.bytes_in_buffer > 0) { LOG_I(MAC,"[eNB %d], Frame %d, DCCH1->DLSCH, CC_id %d, Requesting %d bytes from RLC (RRC message)\n", module_idP,frameP,CC_id,TBS-header_len_dcch-sdu_length_total); sdu_lengths[num_sdus] += mac_rlc_data_req( module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH+1, TBS, //not used (char *)&dlsch_buffer[sdu_length_total]); T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP), T_INT(harq_pid), T_INT(DCCH+1), T_INT(sdu_lengths[num_sdus])); sdu_lcids[num_sdus] = DCCH1; sdu_length_total += sdu_lengths[num_sdus]; header_len_dcch += 2; UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[DCCH1]+=1; UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH1]+=sdu_lengths[num_sdus]; num_sdus++; #ifdef DEBUG_eNB_SCHEDULER LOG_T(MAC,"[eNB %d][DCCH1] CC_id %d Got %d bytes :",module_idP,CC_id,sdu_lengths[num_sdus]); for (j=0; j<sdu_lengths[num_sdus]; j++) { LOG_T(MAC,"%x ",dlsch_buffer[j]); } LOG_T(MAC,"\n"); #endif } } // assume the max dtch header size, and adjust it later header_len_dtch=0; header_len_dtch_last=0; // the header length of the last mac sdu // lcid has to be sorted before the actual allocation (similar struct as ue_list). for (lcid=NB_RB_MAX-1; lcid>=DTCH ; lcid--){ // TBD: check if the lcid is active header_len_dtch+=3; header_len_dtch_last=3; LOG_D(MAC,"[eNB %d], Frame %d, DTCH%d->DLSCH, Checking RLC status (tbs %d, len %d)\n", module_idP,frameP,lcid,TBS, TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch); if (TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch > 0 ) { // NN: > 2 ? rlc_status = mac_rlc_status_ind(module_idP, rnti, module_idP, frameP, subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch); if (rlc_status.bytes_in_buffer > 0) { LOG_D(MAC,"[eNB %d][USER-PLANE DEFAULT DRB] Frame %d : DTCH->DLSCH, Requesting %d bytes from RLC (lcid %d total hdr len %d)\n", module_idP,frameP,TBS-header_len_dcch-sdu_length_total-header_len_dtch,lcid, header_len_dtch); sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, rnti, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, TBS, //not used (char*)&dlsch_buffer[sdu_length_total]); T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP), T_INT(harq_pid), T_INT(lcid), T_INT(sdu_lengths[num_sdus])); LOG_D(MAC,"[eNB %d][USER-PLANE DEFAULT DRB] Got %d bytes for DTCH %d \n",module_idP,sdu_lengths[num_sdus],lcid); sdu_lcids[num_sdus] = lcid; sdu_length_total += sdu_lengths[num_sdus]; UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[lcid]+=1; UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[lcid]+=sdu_lengths[num_sdus]; if (sdu_lengths[num_sdus] < 128) { header_len_dtch--; header_len_dtch_last--; } num_sdus++; } // no data for this LCID else { header_len_dtch-=3; } } // no TBS left else { header_len_dtch-=3; break; } } if (header_len_dtch == 0 ) header_len_dtch_last= 0; // there is at least one SDU // if (num_sdus > 0 ){ if ((sdu_length_total + header_len_dcch + header_len_dtch )> 0) { // Now compute number of required RBs for total sdu length // Assume RAH format 2 // adjust header lengths header_len_dcch_tmp = header_len_dcch; header_len_dtch_tmp = header_len_dtch; if (header_len_dtch==0) { header_len_dcch = (header_len_dcch >0) ? 1 : 0;//header_len_dcch; // remove length field } else { header_len_dtch_last-=1; // now use it to find how many bytes has to be removed for the last MAC SDU header_len_dtch = (header_len_dtch > 0) ? header_len_dtch - header_len_dtch_last :header_len_dtch; // remove length field for the last SDU } mcs = eNB_UE_stats->dlsch_mcs1; if (mcs==0) { nb_rb = 4; // don't let the TBS get too small } else { nb_rb=min_rb_unit[CC_id]; } TBS = get_TBS_DL(mcs,nb_rb); while (TBS < (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) { nb_rb += min_rb_unit[CC_id]; // if (nb_rb>nb_available_rb) { // if we've gone beyond the maximum number of RBs // (can happen if N_RB_DL is odd) TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1,nb_available_rb); nb_rb = nb_available_rb; break; } TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1,nb_rb); } if(nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { for(j=0; j<N_RBG[CC_id]; j++) { // for indicating the rballoc for each sub-band UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; } } else { nb_rb_temp = nb_rb; j = 0; while((nb_rb_temp > 0) && (j<N_RBG[CC_id])) { if(ue_sched_ctl->rballoc_sub_UE[CC_id][j] == 1) { UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j]; if ((j == N_RBG[CC_id]-1) && ((N_RB_DL[CC_id] == 25)|| (N_RB_DL[CC_id] == 50))) { nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]+1; } else { nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id]; } } j = j+1; } } /* RC.eNB[module_idP][CC_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; RC.eNB[module_idP][CC_id]->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id]; for(j=0; j<N_RBG[CC_id]; j++) { RC.eNB[module_idP][CC_id]->mu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; } */ // decrease mcs until TBS falls below required length while ((TBS > (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && (mcs>0)) { mcs--; TBS = get_TBS_DL(mcs,nb_rb); } // if we have decreased too much or we don't have enough RBs, increase MCS while ((TBS < (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && ((( ue_sched_ctl->dl_pow_off[CC_id]>0) && (mcs<28)) || ( (ue_sched_ctl->dl_pow_off[CC_id]==0) && (mcs<=15)))) { mcs++; TBS = get_TBS_DL(mcs,nb_rb); } LOG_D(MAC,"dlsch_mcs before and after the rate matching = (%d, %d)\n",eNB_UE_stats->dlsch_mcs1, mcs); #ifdef DEBUG_eNB_SCHEDULER LOG_D(MAC,"[eNB %d] CC_id %d Generated DLSCH header (mcs %d, TBS %d, nb_rb %d)\n", module_idP,CC_id,mcs,TBS,nb_rb); // msg("[MAC][eNB ] Reminder of DLSCH with random data %d %d %d %d \n", // TBS, sdu_length_total, offset, TBS-sdu_length_total-offset); #endif if ((TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len) <= 2) { padding = (TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len); post_padding = 0; } else { padding = 0; // adjust the header len if (header_len_dtch==0) { header_len_dcch = header_len_dcch_tmp; } else { //if (( header_len_dcch==0)&&((header_len_dtch==1)||(header_len_dtch==2))) header_len_dtch = header_len_dtch_tmp; } post_padding = TBS - sdu_length_total - header_len_dcch - header_len_dtch - ta_len ; // 1 is for the postpadding header } offset = generate_dlsch_header((unsigned char*)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], num_sdus, //num_sdus sdu_lengths, // sdu_lcids, 255, // no drx ue_sched_ctl->ta_update, // timing advance NULL, // contention res id padding, post_padding); //#ifdef DEBUG_eNB_SCHEDULER if (ue_sched_ctl->ta_update) { LOG_I(MAC, "[eNB %d][DLSCH] Frame %d Generate header for UE_id %d on CC_id %d: sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d,timing advance value : %d, padding %d,post_padding %d,(mcs %d, TBS %d, nb_rb %d),header_dcch %d, header_dtch %d\n", module_idP,frameP, UE_id, CC_id, sdu_length_total,num_sdus,sdu_lengths[0],sdu_lcids[0],offset, ue_sched_ctl->ta_update,padding,post_padding,mcs,TBS,nb_rb,header_len_dcch,header_len_dtch); } //#endif #ifdef DEBUG_eNB_SCHEDULER LOG_T(MAC,"[eNB %d] First 16 bytes of DLSCH : \n"); for (i=0; i<16; i++) { LOG_T(MAC,"%x.",dlsch_buffer[i]); } LOG_T(MAC,"\n"); #endif // cycle through SDUs and place in dlsch_buffer memcpy(&UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset],dlsch_buffer,sdu_length_total); // memcpy(RC.mac[0].DLSCH_pdu[0][0].payload[0][offset],dcch_buffer,sdu_lengths[0]); // fill remainder of DLSCH with random data for (j=0; j<(TBS-sdu_length_total-offset); j++) { UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset+sdu_length_total+j] = (char)(taus()&0xff); } if (opt_enabled == 1) { trace_pdu(1, (uint8_t *)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], TBS, module_idP, 3, UE_RNTI(module_idP,UE_id), eNB->frame, eNB->subframe,0,0); LOG_D(OPT,"[eNB %d][DLSCH] CC_id %d Frame %d rnti %x with size %d\n", module_idP, CC_id, frameP, UE_RNTI(module_idP,UE_id), TBS); } T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP), T_INT(harq_pid), T_BUFFER(UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], TBS)); UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid] = nb_rb; add_ue_dlsch_info(module_idP, CC_id, UE_id, subframeP, S_DL_SCHEDULED); // store stats eNB->eNB_stats[CC_id].dlsch_bytes_tx+=sdu_length_total; eNB->eNB_stats[CC_id].dlsch_pdus_tx+=1; UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb; UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used += nb_rb; UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1=eNB_UE_stats->dlsch_mcs1; UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2=mcs; UE_list->eNB_UE_stats[CC_id][UE_id].TBS = TBS; UE_list->eNB_UE_stats[CC_id][UE_id].overhead_bytes= TBS- sdu_length_total; UE_list->eNB_UE_stats[CC_id][UE_id].total_sdu_bytes+= sdu_length_total; UE_list->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes+= TBS; UE_list->eNB_UE_stats[CC_id][UE_id].total_num_pdus+=1; if (cc[CC_id].tdd_Config != NULL) { // TDD UE_list->UE_template[CC_id][UE_id].DAI++; update_ul_dci(module_idP,CC_id,rnti,UE_list->UE_template[CC_id][UE_id].DAI); } // do PUCCH power control // this is the normalized RX power eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id]; normalized_rx_power = eNB_UE_stats->Po_PUCCH_dBm; target_rx_power = get_target_pucch_rx_power(module_idP,CC_id) + 20; // this assumes accumulated tpc // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out int32_t framex10psubframe = UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame*10+UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe; if (((framex10psubframe+10)<=(frameP*10+subframeP)) || //normal case ((framex10psubframe>(frameP*10+subframeP)) && (((10240-framex10psubframe+frameP*10+subframeP)>=10)))) //frame wrap-around if (eNB_UE_stats->Po_PUCCH_update == 1) { eNB_UE_stats->Po_PUCCH_update = 0; UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame=frameP; UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe=subframeP; if (normalized_rx_power>(target_rx_power+1)) { tpc = 0; //-1 tpc_accumulated--; } else if (normalized_rx_power<(target_rx_power-1)) { tpc = 2; //+1 tpc_accumulated++; } else { tpc = 1; //0 } /* LOG_I(MAC,"[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n", module_idP,frameP, subframeP,harq_pid,tpc, tpc_accumulated,normalized_rx_power,target_rx_power);*/ } // Po_PUCCH has been updated else { tpc = 1; //0 } // time to do TPC update else { tpc = 1; //0 } 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_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_1; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = get_aggregation(get_bw_index(module_idP,CC_id),eNB_UE_stats->dl_cqi,format1); dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1; // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications 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_pid; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = tpc; // dont adjust power when retransmitting dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = 0; //deactivate second codeword dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_2 = 0; dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_2 = 1; if (cc[CC_id].tdd_Config != NULL) { //TDD dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.downlink_assignment_index = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, dai %d, mcs %d\n", module_idP,CC_id,harq_pid,round, (UE_list->UE_template[CC_id][UE_id].DAI-1), mcs); } else { LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, mcs %d\n", module_idP,CC_id,harq_pid,round,mcs); } dl_req->number_dci++; dl_req->number_pdu++; // Toggle NDI for next time LOG_D(MAC,"CC_id %d Frame %d, subframeP %d: Toggling Format1 NDI for UE %d (rnti %x/%d) oldNDI %d\n", CC_id, frameP,subframeP,UE_id, UE_list->UE_template[CC_id][UE_id].rnti,harq_pid,UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]); UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]=1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid] = mcs; UE_list->UE_template[CC_id][UE_id].oldmcs2[harq_pid] = 0; eNB->TX_req[CC_id].sfn_sf = (frameP<<3)+subframeP; TX_req = &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB->TX_req[CC_id].tx_request_body.number_of_pdus]; TX_req->pdu_length = TBS; TX_req->pdu_index = eNB->pdu_index[CC_id]++; TX_req->num_segments = 1; TX_req->segments[0].segment_length = TBS; TX_req->segments[0].segment_data = eNB->UE_list.DLSCH_pdu[CC_id][0][(unsigned char)UE_id].payload[harq_pid]; eNB->TX_req[CC_id].tx_request_body.number_of_pdus++; } else { // There is no data from RLC or MAC header, so don't schedule } } if (cc[CC_id].tdd_Config != NULL){ // TDD set_ul_DAI(module_idP,UE_id,CC_id,frameP,subframeP); } } // UE_id loop } // CC_id loop fill_DLSCH_dci(module_idP,frameP,subframeP,mbsfn_flag); stop_meas(&eNB->schedule_dlsch); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH,VCD_FUNCTION_OUT); } //------------------------------------------------------------------------------ void fill_DLSCH_dci( module_id_t module_idP, frame_t frameP, sub_frame_t subframeP, int* mbsfn_flagP ) //------------------------------------------------------------------------------ { // loop over all allocated UEs and compute frequency allocations for PDSCH int UE_id = -1; uint8_t /* first_rb, */ nb_rb=3; rnti_t rnti; //unsigned char *vrb_map; uint8_t rballoc_sub[25]; //uint8_t number_of_subbands=13; //unsigned char round; unsigned char harq_pid; int i; int CC_id; eNB_MAC_INST *eNB =RC.mac[module_idP]; UE_list_t *UE_list = &eNB->UE_list; int N_RBG; int N_RB_DL; COMMON_channels_t *cc; eNB_UE_STATS *eNB_UE_stats; start_meas(&eNB->fill_DLSCH_dci); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_FILL_DLSCH_DCI,VCD_FUNCTION_IN); for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { LOG_D(MAC,"Doing fill DCI for CC_id %d\n",CC_id); if (mbsfn_flagP[CC_id]>0) continue; cc = &eNB->common_channels[CC_id]; N_RBG = to_rbg(cc->mib->message.dl_Bandwidth); N_RB_DL = to_prb(cc->mib->message.dl_Bandwidth); // UE specific DCIs for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) { LOG_T(MAC,"CC_id %d, UE_id: %d => status %d\n",CC_id,UE_id,eNB_dlsch_info[module_idP][CC_id][UE_id].status); if (eNB_dlsch_info[module_idP][CC_id][UE_id].status == S_DL_SCHEDULED) { // clear scheduling flag eNB_dlsch_info[module_idP][CC_id][UE_id].status = S_DL_WAITING; rnti = UE_RNTI(module_idP,UE_id); harq_pid = UE_list->UE_sched_ctrl[UE_id].harq_pid[CC_id]; nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id]; /// Synchronizing rballoc with rballoc_sub for(i=0; i<N_RBG; i++) { rballoc_sub[i] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][i]; } nfapi_dl_config_request_t *DL_req = &RC.mac[module_idP]->DL_req[0]; nfapi_dl_config_request_pdu_t* dl_config_pdu; for (i=0;i<DL_req[CC_id].dl_config_request_body.number_pdu;i++) { dl_config_pdu = &DL_req[CC_id].dl_config_request_body.dl_config_pdu_list[i]; if ((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.resource_block_coding = allocate_prbs_sub(nb_rb,N_RB_DL,N_RBG,rballoc_sub); dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_allocation_type = 0; break; } } } } } stop_meas(&eNB->fill_DLSCH_dci); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_FILL_DLSCH_DCI,VCD_FUNCTION_OUT); } //------------------------------------------------------------------------------ unsigned char* get_dlsch_sdu( module_id_t module_idP, int CC_id, frame_t frameP, rnti_t rntiP, uint8_t TBindex ) //------------------------------------------------------------------------------ { int UE_id; eNB_MAC_INST *eNB=RC.mac[module_idP]; if (rntiP==SI_RNTI) { LOG_D(MAC,"[eNB %d] CC_id %d Frame %d Get DLSCH sdu for BCCH \n", module_idP, CC_id, frameP); return((unsigned char *)&eNB->common_channels[CC_id].BCCH_pdu.payload[0]); } UE_id = find_UE_id(module_idP,rntiP); if (UE_id != -1) { LOG_D(MAC,"[eNB %d] Frame %d: CC_id %d Get DLSCH sdu for rnti %x => UE_id %d\n",module_idP,frameP,CC_id,rntiP,UE_id); return((unsigned char *)&eNB->UE_list.DLSCH_pdu[CC_id][TBindex][UE_id].payload[0]); } else { LOG_E(MAC,"[eNB %d] Frame %d: CC_id %d UE with RNTI %x does not exist\n", module_idP,frameP,CC_id,rntiP); return NULL; } } //------------------------------------------------------------------------------ void update_ul_dci(module_id_t module_idP, uint8_t CC_idP, rnti_t rntiP, uint8_t daiP) //------------------------------------------------------------------------------ { nfapi_hi_dci0_request_t *HI_DCI0_req = &RC.mac[module_idP]->HI_DCI0_req[CC_idP]; nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = &HI_DCI0_req->hi_dci0_request_body.hi_dci0_pdu_list[0]; COMMON_channels_t *cc = &RC.mac[module_idP]->common_channels[CC_idP]; int i; if (cc->tdd_Config != NULL) { // TDD for (i=0; i<HI_DCI0_req->hi_dci0_request_body.number_of_dci + HI_DCI0_req->hi_dci0_request_body.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)) hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.dl_assignment_index = (daiP-1)&3; } } } //------------------------------------------------------------------------------ void set_ue_dai( sub_frame_t subframeP, int UE_id, uint8_t CC_id, uint8_t tdd_config, UE_list_t* UE_list ) //------------------------------------------------------------------------------ { switch (tdd_config) { case 0: if ((subframeP==0)||(subframeP==1)||(subframeP==3)||(subframeP==5)||(subframeP==6)||(subframeP==8)) { UE_list->UE_template[CC_id][UE_id].DAI = 0; } break; case 1: if ((subframeP==0)||(subframeP==4)||(subframeP==5)||(subframeP==9)) { UE_list->UE_template[CC_id][UE_id].DAI = 0; } break; case 2: if ((subframeP==4)||(subframeP==5)) { UE_list->UE_template[CC_id][UE_id].DAI = 0; } break; case 3: if ((subframeP==5)||(subframeP==7)||(subframeP==9)) { UE_list->UE_template[CC_id][UE_id].DAI = 0; } break; case 4: if ((subframeP==0)||(subframeP==6)) { UE_list->UE_template[CC_id][UE_id].DAI = 0; } break; case 5: if (subframeP==9) { UE_list->UE_template[CC_id][UE_id].DAI = 0; } break; case 6: if ((subframeP==0)||(subframeP==1)||(subframeP==5)||(subframeP==6)||(subframeP==9)) { UE_list->UE_template[CC_id][UE_id].DAI = 0; } break; default: UE_list->UE_template[CC_id][UE_id].DAI = 0; LOG_N(MAC,"unknow TDD config %d\n",tdd_config); break; } }