diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index a6a723d58a3e28939ed00f8b8e76b5fd9baa018b..9d68d42ed3c90f79c9c29e49047ec5fafa6433cf 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -921,6 +921,9 @@ schedule_ue_spec(module_id_t module_idP, // add the length for all the control elements (timing adv, drx, etc) : header + payload + if (ue_sched_ctrl->ta_timer) + ue_sched_ctrl->ta_timer--; + if (ue_sched_ctrl->ta_timer == 0) { ta_update = ue_sched_ctrl->ta_update; diff --git a/openair2/LAYER2/MAC/mac_proto.h b/openair2/LAYER2/MAC/mac_proto.h index a785bfb6e928ce1fcb73c4607f4c7a0116291a14..b8834007e0edc7f631938e8dd64043ff80145c5f 100644 --- a/openair2/LAYER2/MAC/mac_proto.h +++ b/openair2/LAYER2/MAC/mac_proto.h @@ -237,30 +237,6 @@ void dlsch_scheduler_pre_processor(module_id_t module_idP, frame_t frameP, sub_frame_t subframe); -void dlsch_scheduler_pre_processor_reset(module_id_t module_idP, - int CC_id, - uint8_t rballoc_sub[N_RBG_MAX]); - -void dlsch_scheduler_pre_processor_accounting(module_id_t Mod_id, - int CC_id, - frame_t frameP, - sub_frame_t subframeP, - uint16_t nb_rbs_required[MAX_MOBILES_PER_ENB], - uint16_t nb_rbs_accounted[MAX_MOBILES_PER_ENB]); - -void dlsch_scheduler_pre_processor_positioning(module_id_t Mod_id, - int CC_id, - uint16_t nb_rbs_required[MAX_MOBILES_PER_ENB], - uint16_t nb_rbs_accounted[MAX_MOBILES_PER_ENB], - uint8_t rballoc_sub[N_RBG_MAX]); - -void dlsch_scheduler_pre_processor_allocate(module_id_t Mod_id, - int UE_id, - uint8_t CC_id, - uint16_t nb_rbs_required, - uint16_t *nb_rbs_remaining, - uint8_t rballoc_sub[N_RBG_MAX]); - /* \brief Function to trigger the eNB scheduling procedure. It is called by PHY at the beginning of each subframe, \f$n$\f and generates all DLSCH allocations for subframe \f$n\f$ and ULSCH allocations for subframe \f$n+k$\f. @param Mod_id Instance ID of eNB @@ -684,7 +660,6 @@ int add_new_ue(module_id_t Mod_id, int CC_id, rnti_t rnti, int harq_pid, uint8_t int rrc_mac_remove_ue(module_id_t Mod_id, rnti_t rntiP); void store_dlsch_buffer(module_id_t Mod_id, int CC_id, frame_t frameP, sub_frame_t subframeP); -void assign_rbs_required(module_id_t Mod_id, int CC_id, uint16_t nb_rbs_required[MAX_MOBILES_PER_ENB]); int prev(UE_list_t *listP, int nodeP); void add_ue_list(UE_list_t *listP, int UE_id); diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index fed69a82b15491c1155768412abb8e3da5b5d508..6c810fea0dc56bb6a13fe9981720159168fcadad 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -50,9 +50,152 @@ extern RAN_CONTEXT_t RC; -#define DEBUG_eNB_SCHEDULER 1 +#define DEBUG_eNB_SCHEDULER #define DEBUG_HEADER_PARSING 1 +int next_ue_list_looped(UE_list_t* list, int UE_id) { + if (UE_id < 0) + return list->head; + return list->next[UE_id] < 0 ? list->head : list->next[UE_id]; +} + +int g_start_ue_dl = -1; +int round_robin_dl(module_id_t Mod_id, + int CC_id, + int frame, + int subframe, + UE_list_t *UE_list, + int max_num_ue, + int n_rbg_sched, + uint8_t *rbgalloc_mask) { + DevAssert(UE_list->head >= 0); + DevAssert(n_rbg_sched > 0); + const int RBGsize = get_min_rb_unit(Mod_id, CC_id); + int num_ue_req = 0; + UE_info_t *UE_info = &RC.mac[Mod_id]->UE_info; + + int rb_required[MAX_MOBILES_PER_ENB]; // how much UEs request + memset(rb_required, 0, sizeof(rb_required)); + + int rbg = 0; + for (; !rbgalloc_mask[rbg]; rbg++) + ; /* fast-forward to first allowed RBG */ + + // Calculate the amount of RBs every UE wants to send. + for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) { + // check whether there are HARQ retransmissions + const COMMON_channels_t *cc = &RC.mac[Mod_id]->common_channels[CC_id]; + const uint8_t harq_pid = frame_subframe2_dl_harq_pid(cc->tdd_Config, frame, subframe); + UE_sched_ctrl_t *ue_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + const uint8_t round = ue_ctrl->round[CC_id][harq_pid]; + if (round != 8) { // retransmission: allocate + int nb_rb = UE_info->UE_template[CC_id][UE_id].nb_rb[harq_pid]; + if (nb_rb % RBGsize != 0) { + nb_rb += nb_rb % RBGsize; // should now divide evenly + } + int nb_rbg = nb_rb / RBGsize; + if (nb_rbg > n_rbg_sched) // needs more RBGs than we can allocate + continue; + // retransmissions: directly allocate + n_rbg_sched -= nb_rbg; + ue_ctrl->pre_nb_available_rbs[CC_id] += nb_rb; + for (; nb_rbg > 0; rbg++) { + if (!rbgalloc_mask[rbg]) + continue; + ue_ctrl->rballoc_sub_UE[CC_id][rbg] = 1; + nb_rbg--; + } + LOG_D(MAC, + "%4d.%d n_rbg_sched %d after retransmission reservation for UE %d " + "round %d retx nb_rb %d pre_nb_available_rbs %d\n", + frame, subframe, n_rbg_sched, UE_id, round, + UE_info->UE_template[CC_id][UE_id].nb_rb[harq_pid], + ue_ctrl->pre_nb_available_rbs[CC_id]); + /* if there are no more RBG to give, return */ + if (n_rbg_sched <= 0) + return 0; + max_num_ue--; + /* if there are no UEs that can be allocated anymore, return */ + if (max_num_ue == 0) + return n_rbg_sched; + for (; !rbgalloc_mask[rbg]; rbg++) /* fast-forward */ ; + } else { + const int dlsch_mcs1 = cqi_to_mcs[UE_info->UE_sched_ctrl[UE_id].dl_cqi[CC_id]]; + UE_info->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 = dlsch_mcs1; + rb_required[UE_id] = + find_nb_rb_DL(dlsch_mcs1, + UE_info->UE_template[CC_id][UE_id].dl_buffer_total, + n_rbg_sched * RBGsize, + RBGsize); + if (rb_required[UE_id] > 0) + num_ue_req++; + LOG_D(MAC, + "%d/%d UE_id %d rb_required %d n_rbg_sched %d\n", + frame, + subframe, + UE_id, + rb_required[UE_id], + n_rbg_sched); + } + } + + if (num_ue_req == 0) + return n_rbg_sched; // no UE has a transmission + + // after allocating retransmissions: build list of UE to allocate. + // if start_UE does not exist anymore (detach etc), start at first UE + if (g_start_ue_dl == -1) + g_start_ue_dl = UE_list->head; + int UE_id = g_start_ue_dl; + UE_list_t UE_sched; + int rb_required_total = 0; + int num_ue_sched = 0; + max_num_ue = min(min(max_num_ue, num_ue_req), n_rbg_sched); + int *cur_UE = &UE_sched.head; + while (num_ue_sched < max_num_ue) { + while (rb_required[UE_id] == 0) + UE_id = next_ue_list_looped(UE_list, UE_id); + /* TODO: check that CCE allocation is feasible. If it is not, reduce + * num_ue_req anyway because this would have been one opportunity */ + *cur_UE = UE_id; + cur_UE = &UE_sched.next[UE_id]; + rb_required_total += rb_required[UE_id]; + num_ue_sched++; + UE_id = next_ue_list_looped(UE_list, UE_id); // next candidate + } + *cur_UE = -1; + + /* for one UE after the next: allocate resources */ + for (int UE_id = UE_sched.head; UE_id >= 0; + UE_id = next_ue_list_looped(&UE_sched, UE_id)) { + if (rb_required[UE_id] <= 0) + continue; + UE_sched_ctrl_t *ue_ctrl = &UE_info->UE_sched_ctrl[UE_id]; + ue_ctrl->rballoc_sub_UE[CC_id][rbg] = 1; + ue_ctrl->pre_nb_available_rbs[CC_id] += RBGsize; + rb_required[UE_id] -= RBGsize; + rb_required_total -= RBGsize; + if (rb_required_total <= 0) + break; + n_rbg_sched--; + if (n_rbg_sched <= 0) + break; + for (rbg++; !rbgalloc_mask[rbg]; rbg++) /* fast-forward */ ; + } + + /* if not all UEs could be allocated in this round */ + if (num_ue_req > max_num_ue) { + /* go to the first one we missed */ + for (int i = 0; i < max_num_ue; ++i) + g_start_ue_dl = next_ue_list_looped(UE_list, g_start_ue_dl); + } else { + /* else, just start with the next UE next time */ + g_start_ue_dl = next_ue_list_looped(UE_list, g_start_ue_dl); + } + + return n_rbg_sched; +} + void sort_ue_ul(module_id_t module_idP, int slice_idx, @@ -129,41 +272,6 @@ store_dlsch_buffer(module_id_t Mod_id, } } -// This function returns the estimated number of RBs required to send the full -// buffer -int get_rbs_required(module_id_t Mod_id, - int CC_id, - int UE_id) { - const UE_info_t *UE_info = &RC.mac[Mod_id]->UE_info; - - if (UE_info->UE_template[CC_id][UE_id].dl_buffer_total == 0) - return 0; - - const int dlsch_mcs1 = cqi_to_mcs[UE_info->UE_sched_ctrl[UE_id].dl_cqi[CC_id]]; - const int min_rb_unit = get_min_rb_unit(Mod_id, CC_id); - int nb_rbs_required = min_rb_unit; - /* calculating required number of RBs for each UE */ - int TBS = get_TBS_DL(dlsch_mcs1, nb_rbs_required); - while (TBS < UE_info->UE_template[CC_id][UE_id].dl_buffer_total) { - nb_rbs_required += min_rb_unit; - TBS = get_TBS_DL(dlsch_mcs1, nb_rbs_required); - } - return nb_rbs_required; -} - -void -assign_rbs_required(module_id_t Mod_id, - int CC_id, - uint16_t nb_rbs_required[MAX_MOBILES_PER_ENB]) { - UE_info_t *UE_info = &RC.mac[Mod_id]->UE_info; - for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) { - nb_rbs_required[UE_id] = get_rbs_required(Mod_id, CC_id, UE_id); - // TODO: the following should not be here - UE_info->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 = cqi_to_mcs[UE_info->UE_sched_ctrl[UE_id].dl_cqi[CC_id]]; - } -} - - int maxround_ul(module_id_t Mod_id, uint16_t rnti, int sched_frame, sub_frame_t sched_subframe) { @@ -190,241 +298,124 @@ maxround_ul(module_id_t Mod_id, uint16_t rnti, int sched_frame, return round_max; } -void dlsch_scheduler_pre_processor_accounting(module_id_t Mod_id, - int CC_id, - frame_t frameP, - sub_frame_t subframeP, - uint16_t nb_rbs_required[MAX_MOBILES_PER_ENB], - uint16_t nb_rbs_accounted[MAX_MOBILES_PER_ENB]) { - uint16_t available_rbs = to_prb(RC.mac[Mod_id]->common_channels[CC_id].mib->message.dl_Bandwidth); - uint8_t rbs_retx = 0; - uint16_t average_rbs_per_user = 0; - int ue_count_newtx = 0; - int ue_count_retx = 0; - +// This function assigns pre-available RBS to each UE in specified sub-bands before scheduling is done +void +dlsch_scheduler_pre_processor(module_id_t Mod_id, + int CC_id, + frame_t frameP, + sub_frame_t subframeP) { UE_info_t *UE_info = &RC.mac[Mod_id]->UE_info; + const int N_RBG = to_rbg(RC.mac[Mod_id]->common_channels[CC_id].mib->message.dl_Bandwidth); + const int RBGsize = get_min_rb_unit(Mod_id, CC_id); - // Find total UE count, and account the RBs required for retransmissions - for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) { - const rnti_t rnti = UE_RNTI(Mod_id, UE_id); - if (rnti == NOT_A_RNTI) continue; - if (UE_info->UE_sched_ctrl[UE_id].ul_out_of_sync == 1) continue; + store_dlsch_buffer(Mod_id, CC_id, frameP, subframeP); - const COMMON_channels_t *cc = &RC.mac[Mod_id]->common_channels[CC_id]; - const uint8_t harq_pid = frame_subframe2_dl_harq_pid(cc->tdd_Config,frameP,subframeP); - const uint8_t round = UE_info->UE_sched_ctrl[UE_id].round[CC_id][harq_pid]; - - // retransmission - if (round != 8) { - nb_rbs_required[UE_id] = UE_info->UE_template[CC_id][UE_id].nb_rb[harq_pid]; - rbs_retx += nb_rbs_required[UE_id]; - ue_count_retx++; - } else { - ue_count_newtx++; - } - } + UE_list_t UE_to_sched; + UE_to_sched.head = -1; + for (int i = 0; i < MAX_MOBILES_PER_ENB; ++i) + UE_to_sched.next[i] = -1; - available_rbs = available_rbs - rbs_retx; - const int min_rb_unit = get_min_rb_unit(Mod_id, CC_id); + int first = 1; + int last_UE_id = -1; + for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) { + UE_sched_ctrl_t *ue_sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; - if (ue_count_newtx == 0) { - average_rbs_per_user = 0; - } else if (min_rb_unit*ue_count_newtx <= available_rbs) { - average_rbs_per_user = (uint16_t)floor(available_rbs/ue_count_newtx); - } else { - // consider the total number of use that can be scheduled UE - average_rbs_per_user = (uint16_t)min_rb_unit; - } + /* initialize per-UE scheduling information */ + ue_sched_ctrl->pre_nb_available_rbs[CC_id] = 0; + ue_sched_ctrl->dl_pow_off[CC_id] = 2; + memset(ue_sched_ctrl->rballoc_sub_UE[CC_id], 0, sizeof(ue_sched_ctrl->rballoc_sub_UE[CC_id])); - for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) { const rnti_t rnti = UE_RNTI(Mod_id, UE_id); - if (rnti == NOT_A_RNTI) continue; - if (UE_info->UE_sched_ctrl[UE_id].ul_out_of_sync == 1) continue; + if (rnti == NOT_A_RNTI) { + LOG_E(MAC, "UE %d has RNTI NOT_A_RNTI!\n", UE_id); + continue; + } + if (UE_info->active[UE_id] != TRUE) { + LOG_E(MAC, "UE %d RNTI %x is NOT active!\n", UE_id, rnti); + continue; + } - const COMMON_channels_t *cc = &RC.mac[Mod_id]->common_channels[CC_id]; - const uint8_t harq_pid = frame_subframe2_dl_harq_pid(cc->tdd_Config,frameP,subframeP); - const uint8_t round = UE_info->UE_sched_ctrl[UE_id].round[CC_id][harq_pid]; - - /* TODO the first seems unnecessary, remove it */ - if (mac_eNB_get_rrc_status(Mod_id, rnti) < RRC_RECONFIGURED || round != 8) - nb_rbs_accounted[UE_id] = nb_rbs_required[UE_id]; - else - nb_rbs_accounted[UE_id] = cmin(average_rbs_per_user, nb_rbs_required[UE_id]); + /* define UEs to schedule */ + if (first) { + first = 0; + UE_to_sched.head = UE_id; + } else { + UE_to_sched.next[last_UE_id] = UE_id; + } + UE_to_sched.next[UE_id] = -1; + last_UE_id = UE_id; } -} - -void dlsch_scheduler_pre_processor_positioning(module_id_t Mod_id, - int CC_id, - uint16_t nb_rbs_required[MAX_MOBILES_PER_ENB], - uint16_t nb_rbs_accounted[MAX_MOBILES_PER_ENB], - uint8_t rballoc_sub[N_RBG_MAX]) { - UE_info_t *UE_info = &RC.mac[Mod_id]->UE_info; - for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) { - if (UE_RNTI(Mod_id, UE_id) == NOT_A_RNTI) continue; - if (UE_info->UE_sched_ctrl[UE_id].ul_out_of_sync == 1) continue; - - dlsch_scheduler_pre_processor_allocate(Mod_id, - UE_id, - CC_id, - nb_rbs_required[UE_id], - &nb_rbs_accounted[UE_id], - rballoc_sub); + if (UE_to_sched.head < 0) + return; + uint8_t *vrb_map = RC.mac[Mod_id]->common_channels[CC_id].vrb_map; + uint8_t rbgalloc_mask[N_RBG_MAX]; + int n_rbg_sched = 0; + for (int i = 0; i < N_RBG; i++) { + // calculate mask: init to one + "AND" with vrb_map: + // if any RB in vrb_map is blocked (1), the current RBG will be 0 + rbgalloc_mask[i] = 1; + for (int j = 0; j < RBGsize; j++) + rbgalloc_mask[i] &= !vrb_map[RBGsize * i + j]; + n_rbg_sched += rbgalloc_mask[i]; } -} -// This function assigns pre-available RBS to each UE in specified sub-bands before scheduling is done -void -dlsch_scheduler_pre_processor(module_id_t Mod_id, - int CC_id, - frame_t frameP, - sub_frame_t subframeP) { - uint8_t rballoc_sub[N_RBG_MAX]; - memset(rballoc_sub, 0, sizeof(rballoc_sub)); - - // Initialize scheduling information for all active UEs - dlsch_scheduler_pre_processor_reset(Mod_id, - CC_id, - rballoc_sub); - - /* update all buffers. TODO move before CC scheduling */ - store_dlsch_buffer(Mod_id, CC_id, frameP, subframeP); - - // Calculate the number of RBs required by each UE on the basis of logical channel's buffer - uint16_t nb_rbs_required[MAX_MOBILES_PER_ENB]; - memset(nb_rbs_required, 0, sizeof(nb_rbs_required)); - assign_rbs_required(Mod_id, - CC_id, - nb_rbs_required); - - - // Decide the number of RBs to allocate - uint16_t nb_rbs_accounted[MAX_MOBILES_PER_ENB]; - memset(nb_rbs_accounted, 0, sizeof(nb_rbs_accounted)); - dlsch_scheduler_pre_processor_accounting(Mod_id, - CC_id, - frameP, - subframeP, - nb_rbs_required, - nb_rbs_accounted); - - // POSITIONING - // This procedure does the main allocation of the RBs - dlsch_scheduler_pre_processor_positioning(Mod_id, - CC_id, - nb_rbs_required, - nb_rbs_accounted, - rballoc_sub); - - const UE_info_t *UE_info = &RC.mac[Mod_id]->UE_info; - const COMMON_channels_t *cc = &RC.mac[Mod_id]->common_channels[CC_id]; - const int N_RBG = to_rbg(cc->mib->message.dl_Bandwidth); + round_robin_dl(Mod_id, + CC_id, + frameP, + subframeP, + &UE_to_sched, + 3, // max_num_ue + n_rbg_sched, + rbgalloc_mask); + + // the following block is meant for validation of the pre-processor to check + // whether all UE allocations are non-overlapping and is not necessary for + // scheduling functionality +#ifdef DEBUG_eNB_SCHEDULER + char t[26] = "_________________________"; + t[N_RBG] = 0; + for (int i = 0; i < N_RBG; i++) + for (int j = 0; j < RBGsize; j++) + if (vrb_map[RBGsize*i+j] != 0) + t[i] = 'x'; + int print = 0; for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) { const UE_sched_ctrl_t *ue_sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; if (ue_sched_ctrl->pre_nb_available_rbs[CC_id] == 0) continue; - char s[101]; - for (int i = 0; i < N_RBG; i++) - sprintf(&s[i*2], " %d", ue_sched_ctrl->rballoc_sub_UE[CC_id][i]); - LOG_D(MAC, - "%d/%d allocation UE %d RNTI %x:%s, total %d, MCS %d\n", + "%4d.%d UE%d %d RBs allocated, pre MCS %d\n", frameP, subframeP, UE_id, - UE_info->UE_template[CC_id][UE_id].rnti, - s, ue_sched_ctrl->pre_nb_available_rbs[CC_id], UE_info->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1); - } -} -void -dlsch_scheduler_pre_processor_reset(module_id_t module_idP, - int CC_id, - uint8_t rballoc_sub[N_RBG_MAX]) { - UE_info_t *UE_info = &RC.mac[module_idP]->UE_info; - - for (int UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; ++UE_id) { - UE_sched_ctrl_t *ue_sched_ctl = &UE_info->UE_sched_ctrl[UE_id]; - const rnti_t rnti = UE_RNTI(module_idP, UE_id); - - if (rnti == NOT_A_RNTI) - continue; - - if (UE_info->active[UE_id] != TRUE) - continue; - - // initialize harq_pid and round - if (ue_sched_ctl->ta_timer) - ue_sched_ctl->ta_timer--; - - ue_sched_ctl->pre_nb_available_rbs[CC_id] = 0; - ue_sched_ctl->dl_pow_off[CC_id] = 2; - - for (int i = 0; i < sizeof(ue_sched_ctl->rballoc_sub_UE[CC_id])/sizeof(unsigned char); i++) { - ue_sched_ctl->rballoc_sub_UE[CC_id][i] = 0; - } - } - - const int N_RB_DL = to_prb(RC.mac[module_idP]->common_channels[CC_id].mib->message.dl_Bandwidth); - const int RBGsize = get_min_rb_unit(module_idP, CC_id); - const uint8_t *vrb_map = RC.mac[module_idP]->common_channels[CC_id].vrb_map; - - // Check for SI-RNTI, RA-RNTI or P-RNTI allocations in VRB map and - // initialize subbands accordly - for (int i = 0; i < N_RB_DL; i++) { - if (vrb_map[i] != 0) - rballoc_sub[i/RBGsize] = 1; - } -} - - -void -dlsch_scheduler_pre_processor_allocate(module_id_t Mod_id, - int UE_id, - uint8_t CC_id, - uint16_t nb_rbs_required, - uint16_t *nb_rbs_remaining, - uint8_t rballoc_sub[N_RBG_MAX]) { - UE_sched_ctrl_t *ue_sched_ctl = &RC.mac[Mod_id]->UE_info.UE_sched_ctrl[UE_id]; - const int N_RBG = to_rbg(RC.mac[Mod_id]->common_channels[CC_id].mib->message.dl_Bandwidth); - const int N_RB_DL = to_prb(RC.mac[Mod_id]->common_channels[CC_id].mib->message.dl_Bandwidth); - const int min_rb_unit = get_min_rb_unit(Mod_id, CC_id); - - for (int i = 0; i < N_RBG; i++) { - if (rballoc_sub[i] != 0) continue; - if (ue_sched_ctl->rballoc_sub_UE[CC_id][i] != 0) continue; - if (*nb_rbs_remaining <= 0) continue; - if (ue_sched_ctl->pre_nb_available_rbs[CC_id] >= nb_rbs_required) continue; - if (ue_sched_ctl->dl_pow_off[CC_id] == 0) continue; - - if ((i == N_RBG - 1) && ((N_RB_DL == 25) || (N_RB_DL == 50))) { - // Allocating last, smaller RBG - if (*nb_rbs_remaining >= min_rb_unit - 1) { - rballoc_sub[i] = 1; - ue_sched_ctl->rballoc_sub_UE[CC_id][i] = 1; - - *nb_rbs_remaining -= min_rb_unit + 1; - ue_sched_ctl->pre_nb_available_rbs[CC_id] = ue_sched_ctl->pre_nb_available_rbs[CC_id] + min_rb_unit - 1; - } - } else { - // Allocating a standard-sized RBG - if (*nb_rbs_remaining >= min_rb_unit) { - rballoc_sub[i] = 1; - ue_sched_ctl->rballoc_sub_UE[CC_id][i] = 1; + print = 1; - *nb_rbs_remaining -= min_rb_unit; - ue_sched_ctl->pre_nb_available_rbs[CC_id] = ue_sched_ctl->pre_nb_available_rbs[CC_id] + min_rb_unit; + for (int i = 0; i < N_RBG; i++) { + if (!ue_sched_ctrl->rballoc_sub_UE[CC_id][i]) + continue; + for (int j = 0; j < RBGsize; j++) { + if (vrb_map[RBGsize*i+j] != 0) { + LOG_I(MAC, "%4d.%d DL scheduler allocation list: %s\n", frameP, subframeP, t); + LOG_E(MAC, "%4d.%d: UE %d allocated at locked RB %d/RBG %d\n", frameP, + subframeP, UE_id, RBGsize * i + j, i); + } + vrb_map[RBGsize*i+j] = 1; } + t[i] = '0' + UE_id; } } + if (print) + LOG_I(MAC, "%4d.%d DL scheduler allocation list: %s\n", frameP, subframeP, t); +#endif } - /// ULSCH PRE_PROCESSOR void ulsch_scheduler_pre_processor(module_id_t module_idP,