/*! \file eNB_scheduler_NB_IoT.c * \brief top level of the scheduler, it scheduled in pdcch period based. * \author NTUST BMW Lab./ * \date 2017 * \email: * \version 1.0 * */ #include "defs_NB_IoT.h" #include "proto_NB_IoT.h" #include "extern_NB_IoT.h" // scheduler #define flag_css_type1 0x1 #define flag_css_type2 0x2 #define flag_uss_v 0x4 // common #define flag_mib 0x1 #define flag_sib1 0x2 #define flag_npss 0x4 #define flag_nsss 0x8 unsigned char str22[] = "UL_Data"; unsigned char str23[] = "DCI_N0"; //extern BCCH_DL_SCH_Message_NB_IoT_t SIB; void eNB_scheduler_computing_flag_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t abs_subframe, uint32_t *scheduler_flags, uint32_t *common_flags, uint32_t *max_subframe){ uint32_t subframe = abs_subframe % 10; uint32_t frame = abs_subframe / 10; int i; uint32_t max = 0; //NPRACH_Parameters_NB_IoT_r13_t **type2_css_info = SIB.message.choice.c1.choice.systemInformation_r13.criticalExtensions.choice.systemInformation_r13.sib_TypeAndInfo_r13.choice.sib2_r13.radioResourceConfigCommon_r13.nprach_Config_r13.nprach_ParametersList_r13.list.array; // fixed scheduling part (e.g. MIB, NPSS, NSSS, SIB1) if(subframe == 0){ *common_flags |= flag_mib; }else if(subframe == 5){ *common_flags |= flag_npss; }else if(subframe == 9 && (frame&0x1)==0){ *common_flags |= flag_nsss; }else if(subframe == 4 && mac_inst->sib1_flag[frame%mac_inst->sib1_period]){ *common_flags |= flag_sib1; } uint32_t type2_css_pp[3] = { mac_inst->npdcch_config_common[0].R_max*mac_inst->npdcch_config_common[0].G, mac_inst->npdcch_config_common[1].R_max*mac_inst->npdcch_config_common[1].G, mac_inst->npdcch_config_common[2].R_max*mac_inst->npdcch_config_common[2].G }; uint32_t start_subframe; for(i=0; i<1; ++i){ // only CE0 if(mac_inst->npdcch_config_common[i].a_offset==0) { start_subframe = 0; } else if(mac_inst->npdcch_config_common[i].a_offset==1/8) { start_subframe = type2_css_pp[i]>>3; } else if(mac_inst->npdcch_config_common[i].a_offset==1/4) { start_subframe = type2_css_pp[i]>>2; } else if(mac_inst->npdcch_config_common[i].a_offset==3/8) { start_subframe = (type2_css_pp[i]>>3)+(type2_css_pp[i]>>2); } if(((abs_subframe+1)%type2_css_pp[i])==start_subframe){ *scheduler_flags |= flag_css_type2; max = MAX(max, extend_space[i]); LOG_D(MAC,"[%d][computing flags] common searching space: %d, num subframe: %d\n", mac_inst->current_subframe, i, extend_space[i]); } } //USS trigger flag for(i=0;i<mac_inst->num_uss_list;++i) { if(((abs_subframe+1)%mac_inst->UE_list_spec[i].NPDCCH_config_dedicated.T)==mac_inst->UE_list_spec[i].NPDCCH_config_dedicated.ss_start_uss) { *scheduler_flags |= (flag_uss_v<<i); max = MAX(max, mac_inst->UE_list_spec[i].NPDCCH_config_dedicated.T); LOG_D(MAC,"[%d][computing flags] UE-spec searching space: %d, num subframe: %d\n", mac_inst->current_subframe, i, mac_inst->UE_list_spec[i].NPDCCH_config_dedicated.T); } } *max_subframe = max; // the maximum subframe to be extend } /*function description: * top level of the scheduler, this will trigger in every subframe, * and determined if do the schedule by checking this current subframe is the start of the NPDCCH period or not */ void eNB_dlsch_ulsch_scheduler_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t abs_subframe){ int i; uint8_t MIB_flag = 0, SIB1_flag = 0; uint32_t scheduler_flags, max_subframe, common_flags; /*Check this subframe should schedule something, set the flag*/ scheduler_flags = 0; common_flags = 0; uint32_t h,f,sf,a; mac_inst->current_subframe = abs_subframe; protocol_ctxt_t ctxt; convert_system_number(abs_subframe, &h, &f, &sf); //*************************RUN PDCP**************************** PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, 0, ENB_FLAG_YES, NOT_A_RNTI, f, sf, 0); pdcp_run(&ctxt); //************************************************************* eNB_scheduler_computing_flag_NB_IoT(mac_inst, abs_subframe, &scheduler_flags, &common_flags, &max_subframe); if(scheduler_flags > 0){ extend_available_resource_DL(mac_inst, mac_inst->current_subframe +1 + max_subframe); } maintain_available_resource(mac_inst); if((abs_subframe % nprach_list->nprach_Periodicity) == rachstart[0]){ //TODO, configuration should be pass by configuration module add_UL_Resource(); } //Check if type2 searching space scheduling if((scheduler_flags&flag_css_type2)>0){ schedule_RA_NB_IoT(mac_inst); scheduler_flags &= ~(flag_css_type2); } //Check if type1 searching space scheduling if((scheduler_flags&flag_css_type1)>0){ // paging, direct indication scheduler_flags &= ~(flag_css_type1); } //The scheduling time is current subframe + 1 convert_system_number(abs_subframe+1, &h, &f, &sf); // loop all USS period for(i=0;i<mac_inst->num_uss_list;++i) { if((scheduler_flags&(flag_uss_v<<i))>0){ LOG_D(MAC,"--------------[%04d][SchedulerUSS] Schedule USS list %d------------\n", mac_inst->current_subframe, (scheduler_flags&(flag_uss_v<<i))>>3); schedule_uss_NB_IoT(0, mac_inst,sf, f, h, i); LOG_D(MAC,"--------------[%04d][SchedulerUSS] Schedule USS list %d end------------\n", mac_inst->current_subframe, (scheduler_flags&(flag_uss_v<<i))>>3); scheduler_flags &= ~(flag_uss_v<<i); } } if(common_flags == flag_mib) MIB_flag = 1; if(common_flags == flag_sib1) SIB1_flag = 1; convert_system_number(abs_subframe, &h, &f, &sf); a = output_handler(mac_inst, 0,0,h,f,sf,MIB_flag,SIB1_flag, abs_subframe); if(a==-1) LOG_I(MAC,"[%04d][SchedulerUSS] schedule result is empty------------\n", mac_inst->current_subframe); } void USS_scheduling_module(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t abs_subframe, uint8_t total_num_UE_list) { int i, max_subframe,MIB_flag,SIB1_flag; /*Check this subframe should schedule something, set the flag*/ MIB_flag = 0; SIB1_flag = 0; max_subframe=0; uint32_t h,f,sf; int a; int UE_list_index; // how many scheduling is triggered this sunframe uint8_t num_sched_UE_list=0; uint8_t *UE_list_flag=(uint8_t*)malloc(total_num_UE_list*sizeof(uint8_t)); //DEBUG("[%04d][USS_scheduling_module] check scheduling trigger\n", mac_inst->current_subframe); //eNB_scheduler_computing_flag_NB_IoT(mac_inst, abs_subframe, &scheduler_flags, &common_flags, &max_subframe); // Check which scheduling period of UE_list is triggered for(i=0;i<total_num_UE_list;++i) { if(((abs_subframe+1)%mac_inst->UE_list_spec[i].NPDCCH_config_dedicated.T)==mac_inst->UE_list_spec[i].NPDCCH_config_dedicated.ss_start_uss) //if((abs_subframe+1)%16==0) { if(mac_inst->UE_list_spec[i].NPDCCH_config_dedicated.T>max_subframe) { max_subframe=mac_inst->UE_list_spec[i].NPDCCH_config_dedicated.T; } UE_list_flag[i]=1; num_sched_UE_list++; //*scheduler_flags |= (flag_uss_v<<i); //max = MAX(max, mac_inst->UE_list_spec[i].NPDCCH_config_dedicated.T); LOG_D(MAC,"[%d][USS_scheduling_module] UE_list num: %d, num subframe: %d\n", mac_inst->current_subframe, i, mac_inst->UE_list_spec[i].NPDCCH_config_dedicated.T); } else { UE_list_flag[i]=0; } } // Update available resource if(num_sched_UE_list > 0) { LOG_D(MAC,"[%d][USS_scheduling_module] extend resource\n", mac_inst->current_subframe); //DEBUG("[%04d][USS_scheduling_module] In extend_available_resource_DL\n", mac_inst->current_subframe); extend_available_resource_DL(mac_inst, mac_inst->current_subframe +1 + max_subframe); } maintain_available_resource(mac_inst); // reserve resource for NPRACH if((abs_subframe % nprach_list->nprach_Periodicity) == rachstart[0]) { //DEBUG("[%04d][USS_scheduling_module] In add_UL_Resource\n", mac_inst->current_subframe); add_UL_Resource(); } //The scheduling time is current subframe + 1 convert_system_number(abs_subframe+1, &h, &f, &sf); // loop all USS period for(UE_list_index=0;UE_list_index<total_num_UE_list;++UE_list_index) { //if((scheduler_flags&(flag_uss_v<<i))>0){ if(UE_list_flag[UE_list_index]==1) { LOG_D(MAC,"--------------[%04d][USS_scheduling_module] Schedule USS list %d------------\n", mac_inst->current_subframe, UE_list_index); //USS Scheduling for corresponding index schedule_uss_NB_IoT(0, mac_inst,sf, f, h, UE_list_index); LOG_D(MAC,"--------------[%04d][USS_scheduling_module] Schedule USS list %d end------------\n", mac_inst->current_subframe, UE_list_index); //scheduler_flags &= ~(flag_uss_v<<i); } } // flag for generating SIB1 and MIB message if(abs_subframe%10 == 0) MIB_flag = 1; if(abs_subframe%10 == 4 && mac_inst->sib1_flag[abs_subframe/10%mac_inst->sib1_period]) SIB1_flag = 1; // handling output to L1 a = output_handler(mac_inst, 0,0,h,f,sf,MIB_flag,SIB1_flag, abs_subframe); if(a==-1) LOG_D(MAC,"[%04d][USS_scheduling_module] schedule result is empty------------\n", mac_inst->current_subframe); } void schedule_uss_NB_IoT(module_id_t module_id, eNB_MAC_INST_NB_IoT *mac_inst, uint32_t subframe, uint32_t frame, uint32_t hypersfn, int UE_list_index) { UE_SCHED_CTRL_NB_IoT_t *UE_sched_ctrl_info; UE_TEMPLATE_NB_IoT *UE_template_temp; DCIFormatN1_t *DCI_N1; DCIFormatN0_t *DCI_N0; //SCHEDULE_NB_IoT_t *scheduler = &eNB->scheduler; mac_inst->scheduling_flag.flag_uss[0]=1; mac_inst->scheduling_flag.flag_uss[1]=0; mac_inst->scheduling_flag.flag_uss[2]=0; mac_inst->scheduling_flag.num_uss_run = 0; int UE_ID; //search space index //int index_ss=0; LOG_D(MAC,"[%04d][schedule_uss_NB_IoT] Start processing preprocessor\n", mac_inst->current_subframe); /***algorithm for USS scheduling***/ preprocessor_uss_NB_IoT(module_id, mac_inst, subframe, frame, hypersfn, UE_list_index); LOG_D(MAC,"[%04d][schedule_uss_NB_IoT] Finish processing preprocessor\n", mac_inst->current_subframe); LOG_D(MAC,"[%04d][schedule_uss_NB_IoT] Do USS Final Scheduling\n", mac_inst->current_subframe); UE_ID = mac_inst->UE_list_spec[UE_list_index].head; while(UE_ID>-1) { UE_template_temp = &(mac_inst->UE_list_spec[UE_list_index].UE_template_NB_IoT[UE_ID]); UE_sched_ctrl_info = &(mac_inst->UE_list_spec[UE_list_index].UE_sched_ctrl_NB_IoT[UE_ID]); LOG_D(MAC,"------Start Scheduling USS UE RNTI %d------\n", UE_template_temp->rnti); if((UE_template_temp->RRC_connected==1)&&(UE_sched_ctrl_info->flag_schedule_success==1)) { switch(UE_template_temp->direction) { case 1: // Downlink Scheduling LOG_D(MAC,"[%04d][schedule_uss_NB_IoT][UE%d] USS DL Final scheduling\n", mac_inst->current_subframe, UE_template_temp->rnti); LOG_D(MAC,"[%04d][schedule_uss_NB_IoT][UE%d] UE_sched_ctrl NPDCCH information:sf_start %d sf end %d\n", mac_inst->current_subframe, UE_template_temp->rnti, UE_sched_ctrl_info->NPDCCH_sf_start, UE_sched_ctrl_info->NPDCCH_sf_end); LOG_D(MAC,"[%04d][schedule_uss_NB_IoT][UE%d] UE_sched_ctrl NPDSCH information:sf_start %d sf end %d\n", mac_inst->current_subframe, UE_template_temp->rnti, UE_sched_ctrl_info->NPDSCH_sf_start, UE_sched_ctrl_info->NPDSCH_sf_end); LOG_D(MAC,"[%04d][schedule_uss_NB_IoT][UE%d] UE_sched_ctrl HARQ information:sf_start %d sf end %d\n", mac_inst->current_subframe, UE_template_temp->rnti, UE_sched_ctrl_info->HARQ_sf_start, UE_sched_ctrl_info->HARQ_sf_end); DCI_N1 = (DCIFormatN1_t*)malloc(sizeof(DCIFormatN1_t)); fill_DCI_N1(DCI_N1, UE_template_temp, UE_sched_ctrl_info); generate_scheduling_result_DL(UE_sched_ctrl_info->NPDCCH_sf_end, UE_sched_ctrl_info->NPDCCH_sf_start, UE_sched_ctrl_info->NPDSCH_sf_end, UE_sched_ctrl_info->NPDSCH_sf_start, UE_sched_ctrl_info->HARQ_sf_end, UE_sched_ctrl_info->HARQ_sf_start, DCI_N1, UE_template_temp->rnti, UE_sched_ctrl_info->TBS, UE_template_temp->DLSCH_pdu.payload); UE_template_temp->R_dci=UE_sched_ctrl_info->R_dci; UE_template_temp->R_dl=UE_sched_ctrl_info->R_dl_data; UE_template_temp->I_mcs_dl=UE_sched_ctrl_info->dci_n1_index_mcs; UE_template_temp->DLSCH_pdu_size=UE_sched_ctrl_info->TBS; if(UE_template_temp->HARQ_round==0) UE_template_temp->oldNDI_DL=(UE_template_temp->oldNDI_DL+1)%2; break; case 0: // Uplink LOG_D(MAC,"[%04d][schedule_uss_NB_IoT][UE%d] USS UL Final scheduling\n", mac_inst->current_subframe, UE_template_temp->rnti); LOG_D(MAC,"[%04d][schedule_uss_NB_IoT][UE%d] UE_sched_ctrl NPDCCH information:sf_start %d sf end %d\n", mac_inst->current_subframe, UE_template_temp->rnti, UE_sched_ctrl_info->NPDCCH_sf_start, UE_sched_ctrl_info->NPDCCH_sf_end); LOG_D(MAC,"[%04d][schedule_uss_NB_IoT][UE%d] UE_sched_ctrl NPUSCH information:sf_start %d sf end %d\n", mac_inst->current_subframe, UE_template_temp->rnti, UE_sched_ctrl_info->NPUSCH_sf_start, UE_sched_ctrl_info->NPUSCH_sf_end); DCI_N0 = (DCIFormatN0_t*)malloc(sizeof(DCIFormatN0_t)); //generate DCI-N0 content fill_DCI_N0(DCI_N0, UE_template_temp, UE_sched_ctrl_info); generate_scheduling_result_UL(UE_sched_ctrl_info->NPDCCH_sf_start, UE_sched_ctrl_info->NPDCCH_sf_end,UE_sched_ctrl_info->NPUSCH_sf_start+3, UE_sched_ctrl_info->NPUSCH_sf_end+3,DCI_N0, UE_template_temp->rnti, str22, str23, 0); //sotre UE_template UE_template_temp->R_dci=UE_sched_ctrl_info->R_dci; UE_template_temp->R_ul=UE_sched_ctrl_info->R_ul_data; if(UE_template_temp->HARQ_round == 0) { UE_template_temp->oldNDI_UL=1-UE_template_temp->oldNDI_UL; } UE_template_temp->direction = -1; break; case -1: // Idle //DEBUG("current idle.. \n"); break; default: break; } } UE_sched_ctrl_info -> flag_schedule_success = 0; UE_ID = UE_template_temp->next; } } void preprocessor_uss_NB_IoT(module_id_t module_id, eNB_MAC_INST_NB_IoT *mac_inst, uint32_t subframe, uint32_t frame, uint32_t hypersfn, int UE_list_index) { int ue_id; UE_TEMPLATE_NB_IoT *UE_template_temp; UE_SCHED_CTRL_NB_IoT_t *UE_sched_ctrl_info; ue_id = mac_inst->UE_list_spec[UE_list_index].head; while(ue_id>-1) { UE_template_temp = &(mac_inst->UE_list_spec[UE_list_index].UE_template_NB_IoT[ue_id]); UE_sched_ctrl_info = &(mac_inst->UE_list_spec[UE_list_index].UE_sched_ctrl_NB_IoT[ue_id]); //determine index of MCS, TBS, R, R_max, R_dci, R_harq UE_sched_ctrl_info->R_dci=UE_template_temp->R_dci; //Set repetition number of downlink transmission if(UE_template_temp->direction==1) { //UE_sched_ctrl_info->R_dci=UE_template_temp->R_dci; UE_sched_ctrl_info->R_dl_data=UE_template_temp->R_dl; UE_sched_ctrl_info->R_dl_harq=UE_template_temp->R_harq; UE_sched_ctrl_info->dci_n1_index_mcs=UE_template_temp->I_mcs_dl; LOG_N(MAC,"[%04d][preprocessor_uss_NB_IoT][UE%d] Initialze R_dci %d R_data_dl %d R_harq %d \n", mac_inst->current_subframe, UE_template_temp->rnti, UE_sched_ctrl_info->R_dci=UE_template_temp->R_dci, UE_sched_ctrl_info->R_dl_data, UE_sched_ctrl_info->R_dl_harq=UE_template_temp->R_harq); //determine how many SF for data transmission //store_rlc_logical_channel_info_dl(); } //Set repetition number of UL transmission else { UE_sched_ctrl_info->R_ul_data=UE_template_temp->R_ul; } ue_id = UE_template_temp->next; } //sort all UE regardless DL or UL UEs sort_UEs_uss(); ue_id = mac_inst->UE_list_spec[UE_list_index].head; //Resource scheduling algorithm while(ue_id>-1) { UE_template_temp = &(mac_inst->UE_list_spec[UE_list_index].UE_template_NB_IoT[ue_id]); UE_sched_ctrl_info = &(mac_inst->UE_list_spec[UE_list_index].UE_sched_ctrl_NB_IoT[ue_id]); // UE not finish RA or finish transmission if(UE_template_temp->RRC_connected!=1) { LOG_D(MAC,"[%04d][preprocessor_uss_NB_IoT][UE%d] rrc not connected\n", mac_inst->current_subframe, UE_template_temp->rnti); } // Finish RA else { //DEBUG("[%04d][preprocessor_uss_NB_IoT][UE%d] ", mac_inst->current_subframe, UE_template_temp->rnti); //DEBUG("[%04d][preprocessor_uss_NB_IoT][UE%d] Start scheduling\n", mac_inst->current_subframe, UE_template_temp->rnti); switch(UE_template_temp->direction) { case 1: // Downlink resource allocation algorithm LOG_D(MAC,"uss downlink scheduling.. \n"); //schedule_DL_NB_IoT(0, mac_inst, UE_template_temp, hypersfn, frame, subframe); if(0==schedule_DL_NB_IoT(0, mac_inst, UE_template_temp, hypersfn, frame, subframe, UE_sched_ctrl_info)) { LOG_N(MAC,"[%04d][preprocessor_uss_NB_IoT][UE%d] DL scheduling USS is successful\n", mac_inst->current_subframe, UE_template_temp->rnti); UE_sched_ctrl_info->flag_schedule_success=1; } else { LOG_D(MAC,"[%04d][preprocessor_uss_NB_IoT][UE%d] DL scheduling USS is failed\n", mac_inst->current_subframe, UE_template_temp->rnti); } break; case 0: // Uplink resource allocation algorithm LOG_D(MAC,"uss uplink scheduling.. \n"); if(0==schedule_UL_NB_IoT(mac_inst, UE_template_temp, subframe, frame, hypersfn, UE_sched_ctrl_info)) { LOG_D(MAC,"[%04d][preprocessor_uss_NB_IoT][UE%d] UL scheduling USS is successful\n", mac_inst->current_subframe, UE_template_temp->rnti); UE_sched_ctrl_info->flag_schedule_success=1; } else { LOG_D(MAC,"[%04d][preprocessor_uss_NB_IoT][UE%d] UL scheduling USS is failed\n", mac_inst->current_subframe, UE_template_temp->rnti); } break; //schedule_UL_NB_IoT(mac_inst, UE_template_temp, subframe, frame, hypersfn); break; case -1: // Idle state, no data wait to send //sDEBUG("current idle.. \n"); default: break; } } ue_id = UE_template_temp->next; } } void sort_UEs_uss() { //loop all UE }