/*******************************************************************************
    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,
  int           *mbsfn_flag,
  Protocol__ProgranMessage *dl_info
)
//------------------------------------------------------------------------------
{
  //TODO
  uint8_t               CC_id;
  int                   UE_id;
  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, mcs_tmp;
  uint16_t              min_rb_unit[MAX_NUM_CCs];
  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;
  int channels_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;
  uint32_t data_to_request;
  uint32_t dci_tbs;
  

  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);
    // get number of PRBs less those used by common channels
    total_nb_available_rb[CC_id] = frame_parms[CC_id]->N_RB_DL;
    for (i=0;i<frame_parms[CC_id]->N_RB_DL;i++)
      if (eNB->common_channels[CC_id].vrb_map[i]!=0)
	total_nb_available_rb[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].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) ||  // no RBs allocated 
	  CCE_allocation_infeasible(mod_id, CC_id, 0, subframe, aggregation, rnti)
	  ) {
        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);
        //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];


      
      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);
      */

      mcs = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]];

      /*TODO: Must also update these stats*/
      //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) {
	  mcs = cqi_to_mcs[eNB_UE_stats->DL_cqi[0]];
	 //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, rrc %d)\n",
            mod_id, frame, UE_id, CC_id, rnti, harq_pid, round, nb_available_rb,
            eNB_UE_stats->DL_cqi[0], mcs,
            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);
	  
	  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_res_alloc = 1;
	    dl_dci->res_alloc = 0;
	    dl_dci->n_mcs = 1;
	    dl_dci->mcs = (uint32_t *)malloc(sizeof(uint32_t));
	    dl_dci->mcs[0] = mcs;
	    //TODO:Need to fix tpc for retransmissions
	    dl_dci->has_tpc = 1;
	    dl_dci->tpc = 1;
	    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, UE_list->UE_template[CC_id][UE_id].rballoc_subband);
	    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+1) % 4;
	    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->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] = mcs;
	    //TODO:Need to fix tpc for retransmissions
	    dl_dci->has_tpc = 1;
	    dl_dci->tpc = 1;
	    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, UE_list->UE_template[CC_id][UE_id].rballoc_subband);
	    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] = 0;
	    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] = (round+1) % 4;
	    dl_dci->rv[1] = (round+1) % 4;
	    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->n_mcs = 1;
	    dl_dci->mcs = (uint32_t *)malloc(sizeof(uint32_t));
	    dl_dci->mcs[0] = mcs;
	    //TODO:Need to fix tpc for retransmissions
	    dl_dci->has_tpc = 1;
	    dl_dci->tpc = 1;
	    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->n_ndi = 1;
	    dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi);
	    dl_dci->ndi[0] = 0;
	    dl_dci->has_rb_bitmap = 1;
	    dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, UE_list->UE_template[CC_id][UE_id].rballoc_subband);
	    dl_dci->has_rb_shift = 1;
	    dl_dci->rb_shift = 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 + 1) % 4;

	    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_res_alloc = 1;
	    dl_dci->res_alloc = 0;
	    dl_dci->n_mcs = 1;
	    dl_dci->mcs = (uint32_t *)malloc(sizeof(uint32_t));
	    dl_dci->mcs[0] = mcs;
	    //TODO:Need to fix tpc for retransmissions
	    dl_dci->has_tpc = 1;
	    dl_dci->tpc = 1;
	    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->n_ndi = 1;
	    dl_dci->ndi = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_ndi);
	    dl_dci->ndi[0] = 0;
	    dl_dci->has_rb_bitmap = 1;
	    dl_dci->rb_bitmap = allocate_prbs_sub(nb_rb, UE_list->UE_template[CC_id][UE_id].rballoc_subband);
	    dl_dci->has_rb_shift = 1;
	    dl_dci->rb_shift = 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 + 1) % 4;
	    dl_dci->has_dl_power_offset = 1;
	    dl_dci->dl_power_offset = ue_sched_ctl->dl_pow_off[CC_id];

	    break;
	  }
	  num_ues_added += 1;
	} 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);
	}
	
      } 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(mcs, nb_available_rb);
	dci_tbs = TBS;
	
        // 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;
	
	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;
	}

	/*TODO: Add other flags if DRX and other CE are required*/
	
	// Add the control element flags to the progran message
	dl_data[num_ues_added]->ce_bitmap[0] = ce_flags;
	dl_data[num_ues_added]->ce_bitmap[1] = ce_flags;

	header_len_dcch = 2; // 2 bytes DCCH SDU subheader

	// Need to see if we have space for data from this channel
	
	if ( TBS-ta_len-header_len_dcch > 0 ) {

	  //If we have space, we need to see how much data we can request at most (if any available)
	  rlc_status = mac_rlc_status_ind(mod_id,
					  rnti,
					  mod_id,
					  frame,
					  ENB_FLAG_YES,
					  MBMS_FLAG_NO,
					  DCCH,
					  (dci_tbs-ta_len-header_len_dcch)); // transport block set size

	  //If data are available in the DCCH
	  if (rlc_status.bytes_in_buffer > 0) {
	    LOG_D(MAC, "[TEST]Have %d bytes in buffer during first call\n", rlc_status.bytes_in_buffer);
	    //Fill in as much as possible
	    data_to_request = cmin(dci_tbs-ta_len-header_len_dcch, rlc_status.bytes_in_buffer) + 1;
	    LOG_D(MAC, "[TEST]Will request %d \n", data_to_request);
	    rlc_pdus[channels_added] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu));
	    protocol__prp_rlc_pdu__init(rlc_pdus[channels_added]);
	    rlc_pdus[channels_added]->n_rlc_pdu_tb = 2;
	    rlc_pdus[channels_added]->rlc_pdu_tb = (Protocol__PrpRlcPduTb **) malloc(sizeof(Protocol__PrpRlcPduTb *) * 2);
	    rlc_pdus[channels_added]->rlc_pdu_tb[0] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb));
	    protocol__prp_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[0]);
	    rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_logical_channel_id = 1;
	    rlc_pdus[channels_added]->rlc_pdu_tb[0]->logical_channel_id = DCCH;
	    rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_size = 1;
	    rlc_pdus[channels_added]->rlc_pdu_tb[0]->size = data_to_request;
	    rlc_pdus[channels_added]->rlc_pdu_tb[1] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb));
	    protocol__prp_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[1]);
	    rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_logical_channel_id = 1;
	    rlc_pdus[channels_added]->rlc_pdu_tb[1]->logical_channel_id = DCCH;
	    rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_size = 1;
	    rlc_pdus[channels_added]->rlc_pdu_tb[1]->size = data_to_request;
	    dl_data[num_ues_added]->n_rlc_pdu++;
	    channels_added++;
	    //Set this to the max value that we might request
	    sdu_length_total = data_to_request;
	  } else {
	    header_len_dcch = 0;
            sdu_length_total = 0;
	  } 
	}

	// check for DCCH1 and update header information (assume 2 byte sub-header)
        if (dci_tbs-ta_len-header_len_dcch-sdu_length_total-2 > 0 ) {

	  //If we have space, we need to see how much data we can request at most (if any are available)
	  rlc_status = mac_rlc_status_ind(mod_id,
					  rnti,
					  mod_id,
					  frame,
					  ENB_FLAG_YES,
					  MBMS_FLAG_NO,
					  DCCH1,
					  (dci_tbs-ta_len-header_len_dcch-sdu_length_total-2)); // transport block set size less allocations for timing advance and
          // DCCH SDU

	  // If data are available in DCCH1
	  if (rlc_status.bytes_in_buffer > 0) {
	    //Add this subheader
	    header_len_dcch += 2;

	    //Fill in as much as possible
	    data_to_request = cmin(dci_tbs-ta_len-header_len_dcch-sdu_length_total, rlc_status.bytes_in_buffer) + 1;

	    rlc_pdus[channels_added] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu));
	    protocol__prp_rlc_pdu__init(rlc_pdus[channels_added]);
	    rlc_pdus[channels_added]->n_rlc_pdu_tb = 2;
	    rlc_pdus[channels_added]->rlc_pdu_tb = (Protocol__PrpRlcPduTb **) malloc(sizeof(Protocol__PrpRlcPduTb *) * 2);
	    rlc_pdus[channels_added]->rlc_pdu_tb[0] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb));
	    protocol__prp_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[0]);
	    rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_logical_channel_id = 1;
	    rlc_pdus[channels_added]->rlc_pdu_tb[0]->logical_channel_id = DCCH1;
	    rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_size = 1;
	    rlc_pdus[channels_added]->rlc_pdu_tb[0]->size = data_to_request;
	    rlc_pdus[channels_added]->rlc_pdu_tb[1] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb));
	    protocol__prp_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[1]);
	    rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_logical_channel_id = 1;
	    rlc_pdus[channels_added]->rlc_pdu_tb[1]->logical_channel_id = DCCH1;
	    rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_size = 1;
	    rlc_pdus[channels_added]->rlc_pdu_tb[1]->size = data_to_request;
	    dl_data[num_ues_added]->n_rlc_pdu++;
	    channels_added++;
	    sdu_length_total += data_to_request;
	  }
	}

	// check for DTCH and update header information
        // here we should loop over all possible DTCH

        header_len_dtch = 3; // Assume max 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,
              dci_tbs-ta_len-header_len_dcch-sdu_length_total-header_len_dtch);

	if (dci_tbs-ta_len-header_len_dcch-sdu_length_total-header_len_dtch > 0 ) {

	   LOG_D(MAC, "[TEST] This is how much we request at most during first call %d\n", dci_tbs-ta_len-header_len_dcch-sdu_length_total-header_len_dtch);
	  
	  //If we have space, we need to see how much data we can request at most (if any are available)
	  rlc_status = mac_rlc_status_ind(mod_id,
					  rnti,
					  mod_id,
					  frame,
					  ENB_FLAG_YES,
					  MBMS_FLAG_NO,
					  DTCH,
					  dci_tbs-ta_len-header_len_dcch-sdu_length_total-header_len_dtch);

	  // If data are available in DTCH
	  if (rlc_status.bytes_in_buffer > 0) {
	     LOG_D(MAC, "[TEST] Have %d bytes in buffer DTCH during first call\n", rlc_status.bytes_in_buffer);
	    //Fill what remains in the TB
	    data_to_request = cmin(dci_tbs-ta_len-header_len_dcch-sdu_length_total-header_len_dtch, rlc_status.bytes_in_buffer) + 1;
	    LOG_D(MAC, "[TEST]Will request %d \n", data_to_request);
	    rlc_pdus[channels_added] = (Protocol__PrpRlcPdu *) malloc(sizeof(Protocol__PrpRlcPdu));
	    protocol__prp_rlc_pdu__init(rlc_pdus[channels_added]);
	    rlc_pdus[channels_added]->n_rlc_pdu_tb = 2;
	    rlc_pdus[channels_added]->rlc_pdu_tb = (Protocol__PrpRlcPduTb **) malloc(sizeof(Protocol__PrpRlcPduTb *) * 2);
	    rlc_pdus[channels_added]->rlc_pdu_tb[0] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb));
	    protocol__prp_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[0]);
	    rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_logical_channel_id = 1;
	    rlc_pdus[channels_added]->rlc_pdu_tb[0]->logical_channel_id = DTCH;
	    rlc_pdus[channels_added]->rlc_pdu_tb[0]->has_size = 1;
	    rlc_pdus[channels_added]->rlc_pdu_tb[0]->size = data_to_request;
	    rlc_pdus[channels_added]->rlc_pdu_tb[1] = (Protocol__PrpRlcPduTb *) malloc(sizeof(Protocol__PrpRlcPduTb));
	    protocol__prp_rlc_pdu_tb__init(rlc_pdus[channels_added]->rlc_pdu_tb[1]);
	    rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_logical_channel_id = 1;
	    rlc_pdus[channels_added]->rlc_pdu_tb[1]->logical_channel_id = DTCH;
	    rlc_pdus[channels_added]->rlc_pdu_tb[1]->has_size = 1;
	    rlc_pdus[channels_added]->rlc_pdu_tb[1]->size = data_to_request;
	    dl_data[num_ues_added]->n_rlc_pdu++;
	    channels_added++;
	    sdu_length_total += data_to_request;

	    if(data_to_request < 128) {
	      header_len_dtch = 2;
	    }
	  } else {
	    header_len_dtch = 0;
	  }
	}
	
	// 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];
	}
	
	// there is a payload
        if (( dl_data[num_ues_added]->n_rlc_pdu > 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) ? (header_len_dcch - 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_tmp = mcs;

	  if (mcs_tmp == 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_tmp, 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(mcs_tmp, nb_available_rb);
              nb_rb = nb_available_rb;
              break;
            }

            TBS = mac_xface->get_TBS_DL(mcs_tmp, 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_tmp > 0)) {
            mcs_tmp--;
            TBS = mac_xface->get_TBS_DL(mcs_tmp, 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_tmp < 28))											     || ( (ue_sched_ctl->dl_pow_off[CC_id]==0) && (mcs_tmp <= 15)))) {
            mcs_tmp++;
            TBS = mac_xface->get_TBS_DL(mcs_tmp, nb_rb);
          }

	  LOG_D(MAC,"[TEST] dlsch_mcs and TBS before and after the rate matching = (%d, %d) (%d, %d)\n", mcs, mcs_tmp, dci_tbs, TBS);

	  dci_tbs = TBS;

	  mcs = mcs_tmp;

	  aggregation = process_ue_cqi(mod_id,UE_id);
	  dl_dci->has_aggr_level = 1;
	  dl_dci->aggr_level = aggregation;
	  
          UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid] = nb_rb;

	  /*Deactivate here as well*/
          /* 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;
	    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;
	    dl_dci->n_tbs_size = 1;
	    dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size);
	    dl_dci->tbs_size[0] = dci_tbs;
	    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;
	    }
	    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;
	    dl_dci->ndi[1] = 1;
	    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] = 0;
	    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] = mcs;
	    dl_dci->n_tbs_size = 2;
	    dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size);
	    dl_dci->tbs_size[0] = dci_tbs;
	    dl_dci->tbs_size[1] = dci_tbs;
	    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;
	    }
	    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_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;
	    dl_dci->ndi[1] = 1;
	    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] = 0;
	    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] = mcs;
	    dl_dci->n_tbs_size = 2;
	    dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size);
	    dl_dci->tbs_size[0] = dci_tbs;
	    dl_dci->tbs_size[1] = dci_tbs;
	    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;
	    }
	    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 = 1;
	    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] = 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;
	    dl_dci->n_tbs_size = 1;
	    dl_dci->tbs_size = (uint32_t *) malloc(sizeof(uint32_t) * dl_dci->n_tbs_size);
	    dl_dci->tbs_size[0] = dci_tbs;
	    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;
	    }

	    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;
	    }

	    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);
}

void apply_scheduling_decisions(mid_t mod_id,
				uint32_t frame,
				uint32_t subframe,
				int *mbsfn_flag,
				Protocol__ProgranMessage *dl_scheduling_info) {

  uint8_t               CC_id;
  int                   UE_id;
  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;
  DCI_PDU      *DCI_pdu;
  
  LTE_eNB_UE_stats     *eNB_UE_stats     = NULL;
  uint16_t              sdu_length_total = 0;
  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];
  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 i;
  int           size_bits,size_bytes;
  
  Protocol__PrpDlMacConfig *mac_config = dl_scheduling_info->dl_mac_config_msg;
  Protocol__PrpDlData *dl_data;
  Protocol__PrpDlDci *dl_dci;

  uint32_t rlc_size, n_lc, lcid;

  // Check if there is any scheduling command for UE data
  if (mac_config->n_dl_ue_data > 0) {
   
    // For each UE-related command
    for (i = 0; i < mac_config->n_dl_ue_data; i++) {
      
      dl_data = mac_config->dl_ue_data[i];
      dl_dci = dl_data->dl_dci;

      CC_id = dl_data->serv_cell_index;
      rnti = dl_data->rnti;
      UE_id = find_ue(rnti, PHY_vars_eNB_g[mod_id][CC_id]);

      //NOTICE: Maybe later will not be required, once scheduler fully restructured
      //eNB_dlsch_info[mod_id][CC_id][UE_id].status = S_DL_WAITING;

      ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
      eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id,CC_id,rnti);
      
      round = dl_dci->rv[0];
      harq_pid = dl_dci->harq_process;
      
      // Note this code is for a specific DCI format
      DLSCH_dci = (void *)UE_list->UE_template[CC_id][UE_id].DLSCH_DCI[harq_pid];
      DCI_pdu = &eNB->common_channels[CC_id].DCI_pdu;

      frame_parms[CC_id] = mac_xface->get_lte_frame_parms(mod_id, CC_id);

      switch (frame_parms[CC_id]->N_RB_DL) {
      case 6:
	if (frame_parms[CC_id]->frame_type == TDD) {
	  if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) {
	    ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->harq_pid = harq_pid;
	    ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->rv       = round;
	    ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->dai      = dl_dci->dai;
	    ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->rballoc  = dl_dci->rb_bitmap;
	    ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->rah      = dl_dci->res_alloc;
	    ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->mcs      = dl_dci->mcs[0];
	    ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->TPC      = dl_dci->tpc;
	    ((DCI1_1_5MHz_TDD_t*)DLSCH_dci)->ndi     = dl_dci->ndi[0];
	    size_bytes = sizeof(DCI1_1_5MHz_TDD_t);
	    size_bits  = sizeof_DCI1_1_5MHz_TDD_t;
	  } else if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) {
	    //TODO
	  } else if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) {
	    //TODO
	  }
	} else {
	  if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) {
	    ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->harq_pid = harq_pid;
	    ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->rv       = round;
	    ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->rballoc  = dl_dci->rb_bitmap;
	    ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->rah      = dl_dci->res_alloc;
	    ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->mcs      = dl_dci->mcs[0];
	    ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->TPC      = dl_dci->tpc;
	    ((DCI1_1_5MHz_FDD_t*)DLSCH_dci)->ndi      = dl_dci->ndi[0];
	    size_bytes = sizeof(DCI1_1_5MHz_FDD_t);
	    size_bits  = sizeof_DCI1_1_5MHz_FDD_t;
	  } else if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) {
	    //TODO
	  } else if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) {
	    //TODO
	  }
	}
	break;
      case 25:
	if (frame_parms[CC_id]->frame_type == TDD) {
	  if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) {
	    ((DCI1_5MHz_TDD_t*)DLSCH_dci)->harq_pid = harq_pid;
	    ((DCI1_5MHz_TDD_t*)DLSCH_dci)->rv       = round;
	    ((DCI1_5MHz_TDD_t*)DLSCH_dci)->dai      = dl_dci->dai;
	    ((DCI1_5MHz_TDD_t*)DLSCH_dci)->rballoc  = dl_dci->rb_bitmap;
	    ((DCI1_5MHz_TDD_t*)DLSCH_dci)->rah      = dl_dci->res_alloc;
	    ((DCI1_5MHz_TDD_t*)DLSCH_dci)->mcs      = dl_dci->mcs[0];
	    ((DCI1_5MHz_TDD_t*)DLSCH_dci)->TPC      = dl_dci->tpc;
	    ((DCI1_5MHz_TDD_t*)DLSCH_dci)->ndi      = dl_dci->ndi[0];
	    size_bytes = sizeof(DCI1_5MHz_TDD_t);
	    size_bits  = sizeof_DCI1_5MHz_TDD_t;
	  } else if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) {
	    //TODO
	  } else if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) {
	    //TODO
	  }
	} else {
	  if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) {
	    ((DCI1_5MHz_FDD_t*)DLSCH_dci)->harq_pid = harq_pid;
	    ((DCI1_5MHz_FDD_t*)DLSCH_dci)->rv       = round;
	    ((DCI1_5MHz_FDD_t*)DLSCH_dci)->rballoc  = dl_dci->rb_bitmap;
	    ((DCI1_5MHz_FDD_t*)DLSCH_dci)->rah      = dl_dci->res_alloc;
	    ((DCI1_5MHz_FDD_t*)DLSCH_dci)->mcs      = dl_dci->mcs[0];
	    ((DCI1_5MHz_FDD_t*)DLSCH_dci)->TPC      = dl_dci->tpc;
	    ((DCI1_5MHz_FDD_t*)DLSCH_dci)->ndi      = dl_dci->ndi[0];
	    size_bytes = sizeof(DCI1_5MHz_FDD_t);
	    size_bits  = sizeof_DCI1_5MHz_FDD_t;
	  } else if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) {
	    //TODO
	  } else if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) {
	    //TODO
	  }
	}
	break;
      case 50:
	if (frame_parms[CC_id]->frame_type == TDD) {
	  if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) {
	    ((DCI1_10MHz_TDD_t*)DLSCH_dci)->harq_pid = harq_pid;
	    ((DCI1_10MHz_TDD_t*)DLSCH_dci)->rv       = round;
	    ((DCI1_10MHz_TDD_t*)DLSCH_dci)->dai      = dl_dci->dai;
	    ((DCI1_10MHz_TDD_t*)DLSCH_dci)->rballoc  = dl_dci->rb_bitmap;
	    ((DCI1_10MHz_TDD_t*)DLSCH_dci)->rah      = dl_dci->res_alloc;
	    ((DCI1_10MHz_TDD_t*)DLSCH_dci)->mcs      = dl_dci->mcs[0];
	    ((DCI1_10MHz_TDD_t*)DLSCH_dci)->TPC      = dl_dci->tpc;
	    ((DCI1_10MHz_TDD_t*)DLSCH_dci)->ndi      = dl_dci->ndi[0];
	    size_bytes = sizeof(DCI1_10MHz_TDD_t);
	    size_bits  = sizeof_DCI1_10MHz_TDD_t;
	  } else if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) {
	    //TODO
	  } else if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) {
	    //TODO
	  }
	} else {
	  if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) {
	    ((DCI1_10MHz_FDD_t*)DLSCH_dci)->harq_pid = harq_pid;
	    ((DCI1_10MHz_FDD_t*)DLSCH_dci)->rv       = round;
	    ((DCI1_10MHz_FDD_t*)DLSCH_dci)->rballoc  = dl_dci->rb_bitmap;
	    ((DCI1_10MHz_FDD_t*)DLSCH_dci)->rah      = dl_dci->res_alloc;
	    ((DCI1_10MHz_FDD_t*)DLSCH_dci)->mcs      = dl_dci->mcs[0];
	    ((DCI1_10MHz_FDD_t*)DLSCH_dci)->TPC      = dl_dci->tpc;
	    ((DCI1_10MHz_TDD_t*)DLSCH_dci)->ndi      = dl_dci->ndi[0];
	    size_bytes = sizeof(DCI1_10MHz_FDD_t);
	    size_bits  = sizeof_DCI1_10MHz_FDD_t;
	  } else if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) {
	    //TODO
	  } else if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) {
	    //TODO
	  }
	}
	break;
      case 100:
	if (frame_parms[CC_id]->frame_type == TDD) {
	  if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) {
	    ((DCI1_20MHz_TDD_t*)DLSCH_dci)->harq_pid = harq_pid;
	    ((DCI1_20MHz_TDD_t*)DLSCH_dci)->rv       = round;
	    ((DCI1_20MHz_TDD_t*)DLSCH_dci)->dai      = dl_dci->dai;
	    ((DCI1_20MHz_TDD_t*)DLSCH_dci)->rballoc  = dl_dci->rb_bitmap;
	    ((DCI1_20MHz_TDD_t*)DLSCH_dci)->rah      = dl_dci->res_alloc;
	    ((DCI1_20MHz_TDD_t*)DLSCH_dci)->mcs      = dl_dci->mcs[0];
	    ((DCI1_20MHz_TDD_t*)DLSCH_dci)->TPC      = dl_dci->tpc;
	    ((DCI1_20MHz_TDD_t*)DLSCH_dci)->ndi      = dl_dci->ndi[0];
	    size_bytes = sizeof(DCI1_20MHz_TDD_t);
	    size_bits  = sizeof_DCI1_20MHz_TDD_t;
	  } else if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) {
	    //TODO
	  } else if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) {
	    //TODO
	  }
	} else {
	  if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) {
	    ((DCI1_20MHz_FDD_t*)DLSCH_dci)->harq_pid = harq_pid;
	    ((DCI1_20MHz_FDD_t*)DLSCH_dci)->rv       = round;
	    ((DCI1_20MHz_FDD_t*)DLSCH_dci)->rballoc  = dl_dci->rb_bitmap;
	    ((DCI1_20MHz_FDD_t*)DLSCH_dci)->rah      = dl_dci->res_alloc;
	    ((DCI1_20MHz_FDD_t*)DLSCH_dci)->mcs      = dl_dci->mcs[0];
	    ((DCI1_20MHz_FDD_t*)DLSCH_dci)->TPC      = dl_dci->tpc;
	    ((DCI1_20MHz_FDD_t*)DLSCH_dci)->ndi      = dl_dci->ndi[0];
	    size_bytes = sizeof(DCI1_20MHz_FDD_t);
	    size_bits  = sizeof_DCI1_20MHz_FDD_t;
	  } else if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) {
	    //TODO
	  } else if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1D) {
	    //TODO
	  }
	}
	break;
      }
      
      // If this is a new transmission
      if (round == 0) {
	// First we have to deal with the creation of the PDU based on the message instructions
	rlc_status.bytes_in_buffer = 0;

	TBS = dl_dci->tbs_size[0];

	if (dl_data->n_ce_bitmap > 0) {
	  //Check if there is TA command
	  if (dl_data->ce_bitmap[0] & PROTOCOL__PRP_CE_TYPE__PRPCET_TA) {
	    ta_len = 2;
	  } else {
	    ta_len = 0;
	  }
	}
	

	n_lc = dl_data->n_rlc_pdu;
	num_sdus = 0;
	sdu_length_total = 0;
	// Go through each one of the channel commands and create SDUs
	for (i = 0; i < n_lc; i++) {
	  lcid = dl_data->rlc_pdu[i]->rlc_pdu_tb[0]->logical_channel_id;
	  rlc_size = dl_data->rlc_pdu[i]->rlc_pdu_tb[0]->size;
	  LOG_D(MAC,"[TEST]Have to check %d channels\n", n_lc);
	  if (rlc_size > 0) {
	    if (lcid == 3) {
	      rlc_size--;
	    }
	    rlc_status = mac_rlc_status_ind(mod_id,
					    rnti,
					    mod_id,
					    frame,
					    ENB_FLAG_YES,
					    MBMS_FLAG_NO,
					    lcid,
					    rlc_size); // transport block set size

	    sdu_lengths[i] = 0;

	    LOG_D(MAC,"[eNB %d] Frame %d, LCID %d, CC_id %d, Requesting %d bytes from RLC (RRC message)\n",
                  mod_id, frame, lcid, CC_id, rlc_size);

	    LOG_D(MAC, "[TEST] Have %d bytes for LCID %d during second call\n", rlc_status.bytes_in_buffer, lcid);
	    
	    sdu_lengths[i] += mac_rlc_data_req(mod_id,
					       rnti,
					       mod_id,
					       frame,
					       ENB_FLAG_YES,
					       MBMS_FLAG_NO,
					       lcid,
					       (char *)&dlsch_buffer[sdu_lengths[sdu_length_total]]);

	    LOG_D(MAC, "[TEST] This is what I actually got from LCID %d -> %d\n",lcid,  sdu_lengths[i]);

	    LOG_D(MAC,"[eNB %d][LCID %d] CC_id %d Got %d bytes from RLC\n",mod_id, lcid, CC_id, sdu_lengths[i]);
	    sdu_length_total += sdu_lengths[i];
            sdu_lcids[i] = lcid;

	    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[i];
	    
	    if (lcid == DCCH || lcid == DCCH1) {
	      header_len_dcch += 2;
	    } else if (lcid == DTCH) {
	      if (sdu_lengths[i] < 128) {
		header_len_dtch = 2;
	      } else {
		header_len_dtch = 3;
	      }
	    }  
	    num_sdus++;
	  }
	} // SDU creation end


	if (((sdu_length_total + header_len_dcch + header_len_dtch) > 0)) {

	  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) ? (header_len_dcch - 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
	  }
	  
	  // there is a payload
	  LOG_D(MAC, "[TEST] This is the padding %d\n", TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len); 
	  if (((sdu_length_total + header_len_dcch + header_len_dtch ) > 0)) {
	    if ((TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len) <= 2
		|| (TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len) > TBS) { //protect from overflow
	      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 {
	      	header_len_dtch = header_len_dtch_tmp;
	      }
	      
	      post_padding = TBS - sdu_length_total - header_len_dcch - header_len_dtch - ta_len - 1; // 1 is for the postpadding header
	    }
	  }
	  
	  LOG_D(MAC, "[TEST] This is the current SDU length %d and this is the TBS %d\n", sdu_length_total, TBS);
	  
	  
	  
	  if (ta_len > 0) {
	    ta_update = ue_sched_ctl->ta_update;
	  } else {
	    ta_update = 0;
	  }
	  
	  offset = generate_dlsch_header((unsigned char*)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0],
					 // offset = generate_dlsch_header((unsigned char*)eNB_mac_inst[0].DLSCH_pdu[0][0].payload[0],
					 num_sdus,              //num_sdus
					 sdu_lengths,  //
					 sdu_lcids,
					 255,                                   // no drx
					 ta_update, // timing advance
					 NULL,                                  // contention res id
					 padding,
					 post_padding);

	  LOG_D(MAC, "[TEST]Have to schedule %d SDUs with length %d. TBS is %d, LCID is %d, post padding is %d, padding is %d, header offset is %d, total sdu size is %d\n", num_sdus, sdu_lengths[0], TBS, sdu_lcids[0], post_padding, padding, offset, sdu_length_total);
	  
#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(&eNB_mac_inst[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);
          }
	  
          //eNB_mac_inst[0].DLSCH_pdu[0][0].payload[0][offset+sdu_lengths[0]+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, mod_id, 3, UE_RNTI(mod_id, UE_id),
                      eNB->subframe,0,0);
            LOG_D(OPT,"[eNB %d][DLSCH] CC_id %d Frame %d  rnti %x  with size %d\n",
                  mod_id, CC_id, frame, UE_RNTI(mod_id,UE_id), TBS);
          }

          // 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].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;

          //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=dl_dci->mcs[0];
          UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2=dl_dci->mcs[0];
          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;

	  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);
	// TODO
	
	  
	}
	
	
	
      } else {
	// No need to create anything apart of DCI in case of retransmission

	/*TODO: Must add these */
	//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=nCCECC_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;
      }

      //Add DCI based on format
      if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_1) {
	add_ue_spec_dci(DCI_pdu,
			DLSCH_dci,
			rnti,
			size_bytes,
			dl_dci->aggr_level,//aggregation
			size_bits,
			format1,
			0);
      } else if (dl_dci->format ==  PROTOCOL__PRP_DCI_FORMAT__PRDCIF_2A) {
	add_ue_spec_dci(DCI_pdu,
			DLSCH_dci,
			rnti,
			size_bytes,
			dl_dci->aggr_level,//aggregation
			size_bits,
			format2A,
			0);
      }
    }
  }
}