diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 2a847b30737f77922eb2a27dbc16df792de1d99e..01d0c8aabd707b0cadb698b50f1570aaf090fbe0 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1007,6 +1007,7 @@ set (MAC_SRC ${MAC_DIR}/eNB_scheduler_RA.c ${MAC_DIR}/pre_processor.c ${MAC_DIR}/config.c + ${MAC_DIR}/eNB_agent_scheduler_dlsch_ue.c ) set (ENB_APP_SRC diff --git a/openair2/ENB_APP/enb_agent.c b/openair2/ENB_APP/enb_agent.c index c48f8f67fb33c86da743ed1628f27e2bd1aada5d..c9c42a41d9c984b12bbb7c6003ea8149437c2180 100644 --- a/openair2/ENB_APP/enb_agent.c +++ b/openair2/ENB_APP/enb_agent.c @@ -256,6 +256,12 @@ int enb_agent_start(mid_t mod_id, const Enb_properties_array_t* enb_properties){ enb_agent_init_cont_mac_stats_update(mod_id); new_thread(receive_thread, &enb_agent[mod_id]); + + /*Initialize and register the mac xface. Must be modified later + *for more flexibility in agent management */ + + AGENT_MAC_xface *mac_agent_xface = (AGENT_MAC_xface *) malloc(sizeof(AGENT_MAC_xface)); + enb_agent_register_mac_xface(mod_id, mac_agent_xface); /* * initilize a timer diff --git a/openair2/ENB_APP/enb_agent_extern.h b/openair2/ENB_APP/enb_agent_extern.h index f191d86907441e6581437b34bb3d4fac3f4b5040..1ef22504830499ce2501becec554b733fd577246 100644 --- a/openair2/ENB_APP/enb_agent_extern.h +++ b/openair2/ENB_APP/enb_agent_extern.h @@ -44,7 +44,7 @@ //extern msg_context_t shared_ctxt[NUM_MAX_ENB][ENB_AGENT_MAX]; -extern AGENT_MAC_xface *agent_mac_xface[NUM_MAX_ENB][ENB_AGENT_MAX]; +extern AGENT_MAC_xface *agent_mac_xface[NUM_MAX_ENB]; extern unsigned int mac_agent_registered[NUM_MAX_ENB]; diff --git a/openair2/ENB_APP/enb_agent_mac.c b/openair2/ENB_APP/enb_agent_mac.c index 157b83581d30bc9d4bdf0faf2eee1b50d51c83f7..05b2a7a364ea6deca352c3387f40f57c37c4a603 100644 --- a/openair2/ENB_APP/enb_agent_mac.c +++ b/openair2/ENB_APP/enb_agent_mac.c @@ -39,6 +39,8 @@ #include "enb_agent_common.h" #include "enb_agent_mac_internal.h" +#include "LAYER2/MAC/proto.h" + #include "log.h" @@ -1158,6 +1160,7 @@ int enb_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->enb_agent_send_sr_info = enb_agent_send_sr_info; xface->enb_agent_send_sf_trigger = enb_agent_send_sf_trigger; xface->enb_agent_send_update_mac_stats = enb_agent_send_update_mac_stats; + xface->enb_agent_schedule_ue_spec = schedule_ue_spec_default; mac_agent_registered[mod_id] = 1; @@ -1172,6 +1175,7 @@ int enb_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { xface->enb_agent_send_sr_info = NULL; xface->enb_agent_send_sf_trigger = NULL; xface->enb_agent_send_update_mac_stats = NULL; + xface->enb_agent_schedule_ue_spec = NULL; mac_agent_registered[mod_id] = 0; agent_mac_xface[mod_id] = NULL; diff --git a/openair2/ENB_APP/enb_agent_mac_defs.h b/openair2/ENB_APP/enb_agent_mac_defs.h index f6dccb15704a0ac732ae00b3ab119293384217d2..67b89bf610fb0e42a19c764d90a13b593163f9eb 100644 --- a/openair2/ENB_APP/enb_agent_mac_defs.h +++ b/openair2/ENB_APP/enb_agent_mac_defs.h @@ -53,7 +53,14 @@ typedef struct { /// Send to the controller all the mac stat updates that occured during this subframe /// based on the stats request configuration void (*enb_agent_send_update_mac_stats)(mid_t mod_id); - + + /// Run the UE DL scheduler and fill the Protocol__ProgranMessage. Assumes that + /// dl_info is already initialized as prp_dl_mac_config and fills the + /// prp_dl_data part of it + void (*enb_agent_schedule_ue_spec)(mid_t mod_id, uint32_t frame, uint32_t subframe, + unsigned int *nb_rb_used, unsigned int *nCCE_used, + int *mbsfn_flag, Protocol__ProgranMessage *dl_info); + /*TODO: Fill in with the rest of the MAC layer technology specific callbacks (UL/DL scheduling, RACH info etc)*/ } AGENT_MAC_xface; diff --git a/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c new file mode 100644 index 0000000000000000000000000000000000000000..5adc4abc402130a0eacee8754267c5fdd3a2ddc4 --- /dev/null +++ b/openair2/LAYER2/MAC/eNB_agent_scheduler_dlsch_ue.c @@ -0,0 +1,944 @@ +/******************************************************************************* + OpenAirInterface + Copyright(c) 1999 - 2014 Eurecom + + OpenAirInterface is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + + OpenAirInterface is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OpenAirInterface.The full GNU General Public License is + included in this distribution in the file called "COPYING". If not, + see <http://www.gnu.org/licenses/>. + + Contact Information + OpenAirInterface Admin: openair_admin@eurecom.fr + OpenAirInterface Tech : openair_tech@eurecom.fr + OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr + + Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + +*******************************************************************************/ + +/*! \file eNB_agent_scheduler_dlsch_ue.c + * \brief procedures related to eNB for the DLSCH transport channel + * \author Xenofon Foukas + * \date 2016 + * \email: x.foukas@sms.ed.ac.uk + * \version 0.1 + * @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 "ENB_APP/enb_agent_defs.h" + +//#include "LAYER2/MAC/pre_processor.c" +#include "pdcp.h" + +#include "header.pb-c.h" +#include "progran.pb-c.h" + +#include "SIMULATION/TOOLS/defs.h" // for taus + +#if defined(ENABLE_ITTI) +# include "intertask_interface.h" +#endif + +#define ENABLE_MAC_PAYLOAD_DEBUG + +//------------------------------------------------------------------------------ +void +schedule_ue_spec_default( + mid_t mod_id, + uint32_t frame, + uint32_t subframe, + unsigned int *nb_rb_used, + unsigned int *nCCE_used, + int *mbsfn_flag, + Protocol__ProgranMessage *dl_info +) +//------------------------------------------------------------------------------ +{ + //TODO + uint8_t CC_id; + int UE_id; + uint16_t nCCE[MAX_NUM_CCs]; + int N_RBG[MAX_NUM_CCs]; + unsigned char aggregation; + mac_rlc_status_resp_t rlc_status; + unsigned char header_len_dcch=0, header_len_dcch_tmp=0,header_len_dtch=0,header_len_dtch_tmp=0, ta_len=0; + unsigned char sdu_lcids[11],offset,num_sdus=0; + uint16_t nb_rb,nb_rb_temp,total_nb_available_rb[MAX_NUM_CCs],nb_available_rb; + uint16_t TBS,j,sdu_lengths[11],rnti,padding=0,post_padding=0; + unsigned char dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES]; + unsigned char round = 0; + unsigned char harq_pid = 0; + void *DLSCH_dci = NULL; + LTE_eNB_UE_stats *eNB_UE_stats = NULL; + uint16_t sdu_length_total = 0; + // uint8_t dl_pow_off[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; + // unsigned char rballoc_sub_UE[MAX_NUM_CCs][NUMBER_OF_UE_MAX][N_RBG_MAX]; + // uint16_t pre_nb_available_rbs[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; + int mcs; + uint16_t min_rb_unit[MAX_NUM_CCs]; + short ta_update = 0; + eNB_MAC_INST *eNB = &eNB_mac_inst[mod_id]; + UE_list_t *UE_list = &eNB->UE_list; + LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]; + 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; + + Protocol__PrpDlData *dl_data[NUM_MAX_UE]; + int num_ues_added = 0; + + Protocol__PrpDlDci *dl_dci; + Protocol__PrpRlcPdu *rlc_pdus[11]; + uint32_t *ce_bitmap; + Protocol__PrpRlcPdu **rlc_pdu; + int num_tb; + uint32_t ce_flags = 0; + + uint8_t rballoc_sub[25]; + int i; + + + if (UE_list->head==-1) { + return; + } + + start_meas(&eNB->schedule_dlsch); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH,VCD_FUNCTION_IN); + + //weight = get_ue_weight(module_idP,UE_id); + aggregation = 1; // set to the maximum aggregation level + + for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + min_rb_unit[CC_id] = get_min_rb_unit(mod_id, CC_id); + frame_parms[CC_id] = mac_xface->get_lte_frame_parms(mod_id, CC_id); + total_nb_available_rb[CC_id] = frame_parms[CC_id]->N_RB_DL - nb_rb_used[CC_id]; + nCCE[CC_id] = mac_xface->get_nCCE_max(mod_id, CC_id) - nCCE_used[CC_id]; + N_RBG[CC_id] = frame_parms[CC_id]->N_RBG; + + // 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].available_ncces = nCCE[CC_id]; + eNB->eNB_stats[CC_id].dlsch_bytes_tx=0; + eNB->eNB_stats[CC_id].dlsch_pdus_tx=0; + } + + 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(mod_id, + frame, + subframe, + 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); + + 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(mod_id, UE_id); + eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); + 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); + // mac_xface->macphy_exit("Cannot find rnti for UE_id"); + continue_flag=1; + } + + if (eNB_UE_stats==NULL) { + LOG_D(MAC,"[eNB] Cannot find eNB_UE_stats\n"); + // mac_xface->macphy_exit("[MAC][eNB] Cannot find eNB_UE_stats\n"); + continue_flag=1; + } + + if ((ue_sched_ctl->pre_nb_available_rbs[CC_id] == 0) || (nCCE[CC_id] < (1<<aggregation))) { + LOG_D(MAC,"[eNB %d] Frame %d : no RB allocated for UE %d on CC_id %d: continue \n", + mod_id, frame, UE_id, CC_id, nb_rb_used[CC_id], ue_sched_ctl->pre_nb_available_rbs[CC_id], nCCE[CC_id], aggregation); + //if(mac_xface->get_transmission_mode(module_idP,rnti)==5) + continue_flag=1; //to next user (there might be rbs availiable for other UEs in TM5 + // else + // break; + } + + if (frame_parms[CC_id]->frame_type == TDD) { + set_ue_dai (subframe, + frame_parms[CC_id]->tdd_config, + UE_id, + CC_id, + UE_list); + // update UL DAI after DLSCH scheduling + set_ul_DAI(mod_id, UE_id, CC_id, frame, subframe,frame_parms); + } + + if (continue_flag == 1 ) { + add_ue_dlsch_info(mod_id, + CC_id, + UE_id, + subframe, + S_DL_NONE); + continue; + } + + // After this point all the UEs will be scheduled + // TODO create a Protocol__PrpDlData struct for the UE + dl_data[num_ues_added] = (Protocol__PrpDlData *) malloc(sizeof(Protocol__PrpDlData)); + protocol__prp_dl_data__init(dl_data[num_ues_added]); + dl_data[num_ues_added]->has_rnti = 1; + dl_data[num_ues_added]->rnti = rnti; + dl_data[num_ues_added]->n_rlc_pdu = 0; + dl_data[num_ues_added]->has_serv_cell_index = 1; + dl_data[num_ues_added]->serv_cell_index = CC_id; + + 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(mod_id, 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[0] < MIN_CQI_VALUE) || (eNB_UE_stats->DL_cqi[0] > MAX_CQI_VALUE)), + eNB_UE_stats->DL_cqi[0], MIN_CQI_VALUE, MAX_CQI_VALUE); + */ + eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]]; + eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs); + + +#ifdef EXMIMO + + if (mac_xface->get_transmission_mode(mod_id, CC_id, rnti)==5) { + eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1,16); + } + +#endif + + // store stats + UE_list->eNB_UE_stats[CC_id][UE_id].dl_cqi= eNB_UE_stats->DL_cqi[0]; + + // initializing the rb allocation indicator for each UE + for(j=0; j<frame_parms[CC_id]->N_RBG; 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, ncc %d, rrc %d)\n", + mod_id, frame, UE_id, CC_id, rnti, harq_pid, round, nb_available_rb, + eNB_UE_stats->DL_cqi[0], eNB_UE_stats->dlsch_mcs1, + nCCE[CC_id], + UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status); + + dl_dci = (Protocol__PrpDlDci*) malloc(sizeof(Protocol__PrpDlDci)); + protocol__prp_dl_dci__init(dl_dci); + dl_data[num_ues_added]->dl_dci = dl_dci; + + + dl_dci->has_rnti = 1; + dl_dci->rnti = rnti; + dl_dci->has_harq_process = 1; + dl_dci->harq_process = harq_pid; + + /* process retransmission */ + + if (round > 0) { + + if (frame_parms[CC_id]->frame_type == TDD) { + UE_list->UE_template[CC_id][UE_id].DAI++; + update_ul_dci(mod_id, 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, subframe,UE_id,UE_list->UE_template[CC_id][UE_id].DAI); + } + + // get freq_allocation + nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid]; + + if (nb_rb <= nb_available_rb) { + + if(nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) { + for(j=0; j<frame_parms[CC_id]->N_RBG; 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<frame_parms[CC_id]->N_RBG)) { + 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 == frame_parms[CC_id]->N_RBG-1) && + ((frame_parms[CC_id]->N_RB_DL == 25)|| + (frame_parms[CC_id]->N_RB_DL == 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; + aggregation = process_ue_cqi(mod_id, UE_id); + nCCE[CC_id]-=(1<<aggregation); // adjust the remaining nCCE + nCCE_used[CC_id] += (1<<aggregation); + + PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; + PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id]; + + for(j=0; j<frame_parms[CC_id]->N_RBG; j++) { + PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j]; + } + + switch (mac_xface->get_transmission_mode(mod_id,CC_id,rnti)) { + case 1: + case 2: + default: + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1; + dl_dci->n_ndi = 1; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = 0; + dl_dci->n_rv = 1; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = round&3; + if (frame_parms[CC_id]->frame_type == TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = (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\n", + mod_id, CC_id, harq_pid, round,(UE_list->UE_template[CC_id][UE_id].DAI-1)); + } else { + LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d\n", + mod_id, CC_id, harq_pid, round); + } + break; + case 4: + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A; + dl_dci->n_ndi = 2; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = 0; + dl_dci->ndi[1] = 0; + dl_dci->has_dai = 1; + dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + dl_dci->n_rv = 2; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = round&3; + dl_dci->rv[1] = round&3; + + break; + case 5: + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D; + dl_dci->n_ndi = 1; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = 0; + dl_dci->has_dai = 1; + dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + dl_dci->n_rv = 1; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = round&3; + + if(ue_sched_ctl->dl_pow_off[CC_id] == 2) { + ue_sched_ctl->dl_pow_off[CC_id] = 1; + } + + dl_dci->has_dl_power_offset = 1; + dl_dci->dl_power_offset = ue_sched_ctl->dl_pow_off[CC_id]; + + break; + case 6: + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D; + dl_dci->n_ndi = 1; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = 0; + dl_dci->has_dai = 1; + dl_dci->dai = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3; + dl_dci->n_rv = 1; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = round&3; + dl_dci->has_dl_power_offset = 1; + dl_dci->dl_power_offset = ue_sched_ctl->dl_pow_off[CC_id]; + + break; + } + + add_ue_dlsch_info(mod_id, + CC_id, + UE_id, + subframe, + 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].ncce_used_retx=nCCE[CC_id]; + 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", + mod_id, frame, CC_id, UE_id); + } + + num_ues_added += 1; + + } 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 = mac_xface->get_TBS(eNB_UE_stats->DL_cqi[0]<<1,nb_available_rb); + TBS = mac_xface->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 + + //#ifndef EXMIMO_IOT + // to be checked by RK, NN, FK + uint8_t update_TA=4; + + switch (frame_parms[CC_id]->N_RB_DL) { + case 6: + update_TA = 1; + break; + + case 25: + update_TA = 4; + break; + + case 50: + update_TA = 8; + break; + + case 100: + update_TA = 16; + break; + } + + ta_len = ((eNB_UE_stats->timing_advance_update/update_TA)!=0) ? 2 : 0; + + dl_data[num_ues_added]->n_ce_bitmap = 2; + dl_data[num_ues_added]->ce_bitmap = (uint32_t *) malloc(sizeof(uint32_t) * 2); + + if (ta_len > 0) { + ce_flags |= PROTOCOL__PRP_CE_TYPE__PRPCET_TA; + } + + + header_len_dcch = 2; // 2 bytes DCCH SDU subheader + + if ( TBS-ta_len-header_len_dcch > 0 ) { + + + rlc_status = mac_rlc_status_ind( + mod_id, + rnti, + mod_id, + frame, + ENB_FLAG_YES, + MBMS_FLAG_NO, + DCCH, + (TBS-ta_len-header_len_dcch)); // transport block set size + + if (rlc_status.bytes_in_buffer > 0) { + sdu_length_total = cmin(rlc_status.bytes_in_buffer, TBS-ta_len-header_len_dcch); + // TODO: This should be replaced with the proper description of the CE + ce_flags |= PROTOCOL__PRP_CE_TYPE__PRPCET_CR; + } 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( + mod_id, + rnti, + mod_id, + frame, + 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 + + if (rlc_status.bytes_in_buffer > 0) { + // TODO: Again hypothetical flag. Need to check how to find the actual type of CE + ce_flags |= PROTOCOL__PRP_CE_TYPE__PRPCET_CA; + sdu_length_total += cmin(rlc_status.bytes_in_buffer, TBS-ta_len-header_len_dcch-sdu_length_total); + header_len_dcch += 2; + } + } + + // Add the control element flags to the progran message + dl_data[num_ues_added]->ce_bitmap = ce_flags; + + // check for DTCH and update header information + // here we should loop over all possible DTCH + + header_len_dtch = 3; // 3 bytes DTCH SDU subheader + + LOG_D(MAC,"[eNB %d], Frame %d, DTCH->DLSCH, CC_id %d, Checking RLC status (rab %d, tbs %d, len %d)\n", + mod_id, frame, CC_id, DTCH, 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 ) { + rlc_status = mac_rlc_status_ind( + mod_id, + rnti, + mod_id, + frame, + ENB_FLAG_YES, + MBMS_FLAG_NO, + DTCH, + TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch); + + if (rlc_status.bytes_in_buffer > 0) { + + //TODO: Set rlc pdu info. Hardcoded for the moment + + dl_data[num_ues_added]->n_rlc_pdu++; + rlc_pdus[0] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu)); + protocol__prp_rlc_pdu__init(rlc_pdus[0]); + rlc_pdus[0]->n_rlc_pdu_tb = 2; + rlc_pdus[0]->rlc_pdu_tb = (Protocol__PrpRlcPduTb **) malloc(sizeof(Protocol__PrpRlcPduTb *) * 2); + rlc_pdus[0]->rlc_pdu_tb[0] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); + rlc_pdus[0]->rlc_pdu_tb[0]->has_logical_channel_id = 1; + rlc_pdus[0]->rlc_pdu_tb[0]->logical_channel_id = DTCH; + rlc_pdus[0]->rlc_pdu_tb[0]->has_size = 1; + rlc_pdus[0]->rlc_pdu_tb[0]->size = TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch; + rlc_pdus[0]->rlc_pdu_tb[1] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb)); + rlc_pdus[0]->rlc_pdu_tb[1]->has_logical_channel_id = 1; + rlc_pdus[0]->rlc_pdu_tb[1]->logical_channel_id = DTCH; + rlc_pdus[0]->rlc_pdu_tb[1]->has_size = 1; + rlc_pdus[0]->rlc_pdu_tb[1]->size = TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch; + + // Add rlc_pdus to the dl_data message + dl_data[num_ues_added]->rlc_pdu = (Protocol__PrpRlcPdu **) malloc(sizeof(Protocol__PrpRlcPdu *) * + dl_data[num_ues_added]->n_rlc_pdu); + for (i = 0; i< dl_data[num_ues_added]->n_rlc_pdu; i++) { + dl_data[num_ues_added]->rlc_pdu[i] = rlc_pdus[i]; + } + + sdu_length_total += cmin(rlc_status.bytes_in_buffer, TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch); + + if(cmin(rlc_status.bytes_in_buffer, TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch) < 128) { + header_len_dtch = 2; + } + + } else { + header_len_dtch = 0; + } + } + + // there is a payload + 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 : header_len_dcch; // remove length field + } else { + header_len_dtch = (header_len_dtch > 0) ? 1 :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 = mac_xface->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 = mac_xface->get_TBS_DL(eNB_UE_stats->dlsch_mcs1,nb_available_rb); + nb_rb = nb_available_rb; + break; + } + + TBS = mac_xface->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<frame_parms[CC_id]->N_RBG; 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<frame_parms[CC_id]->N_RBG)) { + 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 == frame_parms[CC_id]->N_RBG-1) && + ((frame_parms[CC_id]->N_RB_DL == 25)|| + (frame_parms[CC_id]->N_RB_DL == 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; + } + } + + PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb; + PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id]; + + for(j=0; j<frame_parms[CC_id]->N_RBG; j++) { + PHY_vars_eNB_g[mod_id][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 = mac_xface->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 = mac_xface->get_TBS_DL(mcs,nb_rb); + } + + dl_dci->n_tbs_size = 2; + dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * 2); + dl_dci->tbs_size[0] = TBS; + dl_dci->tbs_size[1] = TBS; + + LOG_D(MAC,"dlsch_mcs before and after the rate matching = (%d, %d)\n",eNB_UE_stats->dlsch_mcs1, mcs); + + aggregation = process_ue_cqi(mod_id,UE_id); + dl_dci->has_aggr_level = 1; + dl_dci->aggr_level = aggregation; + dl_dci->has_cce_index = 1; + dl_dci->cce_index = nCCE_used[CC_id]; + nCCE[CC_id]-=(1<<aggregation); // adjust the remaining nCCE + nCCE_used[CC_id]+=(1<<aggregation); // adjust the remaining nCCE + UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid] = nb_rb; + + add_ue_dlsch_info(mod_id, + CC_id, + UE_id, + subframe, + S_DL_SCHEDULED); + + if (frame_parms[CC_id]->frame_type == TDD) { + UE_list->UE_template[CC_id][UE_id].DAI++; + // printf("DAI update: subframeP %d: UE %d, DAI %d\n",subframeP,UE_id,UE_list->UE_template[CC_id][UE_id].DAI); +#warning only for 5MHz channel + update_ul_dci(mod_id, 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 = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti); + normalized_rx_power = eNB_UE_stats->Po_PUCCH_dBm; + target_rx_power = mac_xface->get_target_pucch_rx_power(mod_id, CC_id) + 10; + + // 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)<=(frame*10+subframe)) || //normal case + ((framex10psubframe>(frame*10+subframe)) && (((10240-framex10psubframe+frame*10+subframe)>=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=frame; + UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe=subframe; + 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_D(MAC,"[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n", + mod_id, frame, subframe, 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 + } + + for(i=0; i<PHY_vars_eNB_g[mod_id][CC_id]->lte_frame_parms.N_RBG; i++) { + rballoc_sub[i] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][i]; + } + + switch (mac_xface->get_transmission_mode(mod_id, CC_id, rnti)) { + case 1: + case 2: + default: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; + dl_dci->n_ndi = 1; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + dl_dci->n_rv = 1; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = 0; + dl_dci->has_tpc = 1; + dl_dci->tpc = tpc; + dl_dci->n_mcs = 1; + dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + if (frame_parms[CC_id]->frame_type == TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = (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\n", + mod_id, CC_id, harq_pid, round,(UE_list->UE_template[CC_id][UE_id].DAI-1)); + } else { + LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d\n", + mod_id, CC_id, harq_pid, round); + } + break; + case 3: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; + dl_dci->n_ndi = 2; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + dl_dci->ndi[1] = 0; + dl_dci->n_rv = 2; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = 0; + dl_dci->rv[1] = 1; + dl_dci->has_tpc = 1; + dl_dci->tpc = tpc; + dl_dci->n_mcs = 2; + dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + dl_dci->mcs[1] = 0; + if (frame_parms[CC_id]->frame_type == TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = (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\n", + mod_id, CC_id, harq_pid, round,(UE_list->UE_template[CC_id][UE_id].DAI-1)); + } else { + LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d\n", + mod_id, CC_id, harq_pid, round); + } + break; + case 4: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; + dl_dci->n_ndi = 2; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = 1-UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]; + dl_dci->ndi[1] = 0; + dl_dci->n_rv = 2; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = 0; + dl_dci->rv[1] = round&3; + dl_dci->has_tpc = 1; + dl_dci->tpc = tpc; + dl_dci->n_mcs = 2; + dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + dl_dci->mcs[1] = 0; + if (frame_parms[CC_id]->frame_type == TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = (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\n", + mod_id, CC_id, harq_pid, round,(UE_list->UE_template[CC_id][UE_id].DAI-1)); + } else { + LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d\n", + mod_id, CC_id, harq_pid, round); + } + break; + case 5: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; + dl_dci->n_ndi = 1; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = 1; + dl_dci->n_rv = 1; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = round&3; + dl_dci->has_tpc = 1; + dl_dci->tpc = tpc; + dl_dci->n_mcs = 1; + dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + if (frame_parms[CC_id]->frame_type == TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = (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\n", + mod_id, CC_id, harq_pid, round,(UE_list->UE_template[CC_id][UE_id].DAI-1)); + } else { + LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d\n", + mod_id, CC_id, harq_pid, round); + } + + if(ue_sched_ctl->dl_pow_off[CC_id] == 2) { + ue_sched_ctl->dl_pow_off[CC_id] = 1; + } + + dl_dci->has_dl_power_offset = 1; + dl_dci->dl_power_offset = ue_sched_ctl->dl_pow_off[CC_id]; + dl_dci->has_precoding_info = 1; + dl_dci->precoding_info = 5; // Is this right?? + + break; + case 6: + dl_dci->has_res_alloc = 1; + dl_dci->res_alloc = 0; + dl_dci->has_vrb_format = 1; + dl_dci->vrb_format = PROTOCOL__PRP_VRB_FORMAT__PRVRBF_LOCALIZED; + dl_dci->has_format = 1; + dl_dci->format = PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D; + dl_dci->has_rb_bitmap = 1; + dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, rballoc_sub); + dl_dci->has_rb_shift = 1; + dl_dci->rb_shift = 0; + dl_dci->n_ndi = 1; + dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi); + dl_dci->ndi[0] = 1; + dl_dci->n_rv = 1; + dl_dci->rv = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_rv); + dl_dci->rv[0] = round&3; + dl_dci->has_tpc = 1; + dl_dci->tpc = tpc; + dl_dci->n_mcs = 1; + dl_dci->mcs = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_mcs); + dl_dci->mcs[0] = mcs; + if (frame_parms[CC_id]->frame_type == TDD) { + dl_dci->has_dai = 1; + dl_dci->dai = (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\n", + mod_id, CC_id, harq_pid, round,(UE_list->UE_template[CC_id][UE_id].DAI-1)); + } else { + LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d\n", + mod_id, CC_id, harq_pid, round); + } + + dl_dci->has_dl_power_offset = 1; + dl_dci->dl_power_offset = ue_sched_ctl->dl_pow_off[CC_id]; + dl_dci->has_precoding_info = 1; + dl_dci->precoding_info = 5; // Is this right?? + break; + } + // 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, frame, subframe, 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]; + + // Increase the pointer for the number of scheduled UEs + num_ues_added++; + } else { // There is no data from RLC or MAC header, so don't schedule + + } + } + if (frame_parms[CC_id]->frame_type == TDD) { + set_ul_DAI(mod_id, UE_id, CC_id, frame, subframe, frame_parms); + } + } + } + + // Add all the dl_data elements to the progran message + dl_info->dl_mac_config_msg->n_dl_ue_data = num_ues_added; + dl_info->dl_mac_config_msg->dl_ue_data = (Protocol__PrpDlData **) malloc(sizeof(Protocol__PrpDlData *) * num_ues_added); + for (i = 0; i < num_ues_added; i++) { + dl_info->dl_mac_config_msg->dl_ue_data[i] = dl_data[i]; + } + + stop_meas(&eNB->schedule_dlsch); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH,VCD_FUNCTION_OUT); +} diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index 329c40be05e51ae85e005995f016c0a0294336ea..0de9253fef496715429dc69746fe3d44ea6df86a 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -59,6 +59,10 @@ //#include "LAYER2/MAC/pre_processor.c" #include "pdcp.h" +//Agent-related headers +#include "ENB_APP/enb_agent_extern.h" +#include "ENB_APP/enb_agent_mac.h" + #if defined(ENABLE_ITTI) # include "intertask_interface.h" #endif @@ -85,6 +89,9 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, int mbsfn_status[MAX_NUM_CCs]; uint32_t RBalloc[MAX_NUM_CCs]; protocol_ctxt_t ctxt; + + Protocol__ProgranMessage *msg; + #ifdef EXMIMO int ret; #endif @@ -275,7 +282,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, break; } } else { //FDD - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); schedule_ulsch(module_idP,frameP,cooperation_flag,1,5,nCCE); } @@ -287,7 +306,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, // TDD, nothing // FDD, normal UL/DLSCH if (mac_xface->lte_frame_parms->frame_type == FDD) { //FDD - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); schedule_ulsch(module_idP,frameP,cooperation_flag,2,6,nCCE); } @@ -306,7 +337,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, // no break here! case 5: - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); break; @@ -314,7 +357,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, break; } } else { //FDD - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); schedule_ulsch(module_idP,frameP,cooperation_flag,3,7,nCCE); @@ -341,7 +396,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, // no break here! case 5: - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,1,mbsfn_status); break; @@ -352,7 +419,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, if (mac_xface->lte_frame_parms->frame_type == FDD) { //FDD // schedule_RA(module_idP,frameP, subframeP, 0, nprb, nCCE); // schedule_ulsch(module_idP, frameP, cooperation_flag, 4, 8, nCCE); - schedule_ue_spec(module_idP, frameP, subframeP, nprb, nCCE, mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP, frameP, subframeP, nprb, nCCE, mbsfn_status); fill_DLSCH_dci(module_idP, frameP, subframeP, RBalloc, 1, mbsfn_status); } @@ -408,13 +487,37 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, case 5: schedule_RA(module_idP,frameP,subframeP,2,nprb,nCCE); - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,1,mbsfn_status); break; case 3: case 4: - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); break; @@ -423,7 +526,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } } else { //FDD // schedule_ulsch(module_idP,frameP,cooperation_flag,6,0,nCCE); - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); } @@ -438,12 +553,36 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, case 3: case 4: schedule_RA(module_idP,frameP,subframeP,3,nprb,nCCE); // 3 = Msg3 subframeP, not - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,1,mbsfn_status); break; case 5: - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); break; @@ -452,7 +591,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } } else { //FDD //schedule_ulsch(module_idP,frameP,cooperation_flag,7,1,nCCE); - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); } @@ -472,7 +623,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, // schedule_RA(module_idP,subframeP,nprb,nCCE); schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,2,nCCE); - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); break; @@ -481,7 +644,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } } else { //FDD //schedule_ulsch(module_idP,frameP,cooperation_flag,8,2,nCCE); - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); } @@ -495,28 +670,76 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, case 1: schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,3,nCCE); schedule_RA(module_idP,frameP,subframeP,7,nprb,nCCE); // 7 = Msg3 subframeP, not - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,1,mbsfn_status); break; case 3: case 4: schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,3,nCCE); - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); break; case 6: schedule_ulsch(module_idP,frameP,cooperation_flag,subframeP,4,nCCE); //schedule_RA(module_idP,frameP,subframeP,nprb,nCCE); - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); break; case 2: case 5: //schedule_RA(module_idP,frameP,subframeP,nprb,nCCE); - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); break; @@ -525,7 +748,19 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag, } } else { //FDD // schedule_ulsch(module_idP,frameP,cooperation_flag,9,3,nCCE); - schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); + if (mac_agent_registered[module_idP]) { + enb_agent_mac_create_empty_dl_config(module_idP, &msg); + agent_mac_xface[module_idP]->enb_agent_schedule_ue_spec( + module_idP, + frameP, + subframeP, + nprb, + nCCE, + mbsfn_status, + msg); + enb_agent_mac_destroy_dl_config(msg); + } + //schedule_ue_spec(module_idP,frameP,subframeP,nprb,nCCE,mbsfn_status); fill_DLSCH_dci(module_idP,frameP,subframeP,RBalloc,0,mbsfn_status); } diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h index d02e42ee16407b8aff87ffbb3ce098ded65cacf7..28df04ef64517d427ab7d3fd336e91b4b6f244ba 100644 --- a/openair2/LAYER2/MAC/proto.h +++ b/openair2/LAYER2/MAC/proto.h @@ -35,6 +35,11 @@ */ #ifndef __LAYER2_MAC_PROTO_H__ #define __LAYER2_MAC_PROTO_H__ + +#include "enb_agent_defs.h" +#include "header.pb-c.h" +#include "progran.pb-c.h" + /** \addtogroup _mac * @{ */ @@ -139,6 +144,11 @@ void fill_DLSCH_dci(module_id_t module_idP,frame_t frameP,sub_frame_t subframe,u */ void schedule_ue_spec(module_id_t module_idP,frame_t frameP,sub_frame_t subframe,unsigned int *nb_rb_used0,unsigned int *nCCE_used,int *mbsfn_flag); +//To be used by the agent +void schedule_ue_spec_default(mid_t mod_id, uint32_t frame, uint32_t subframe, + unsigned int *nb_rb_used, unsigned int *nCCE_used, + int *mbsfn_flag, Protocol__ProgranMessage *dl_info); + /** \brief Function for UE/PHY to compute PUSCH transmit power in power-control procedure. @param Mod_id Module id of UE @returns Po_NOMINAL_PUSCH (PREAMBLE_RECEIVED_TARGET_POWER+DELTA_PREAMBLE