/*
 * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The OpenAirInterface Software Alliance licenses this file to You under
 * the OAI Public License, Version 1.1  (the "License"); you may not use this file
 * except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.openairinterface.org/?page_id=698
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *-------------------------------------------------------------------------------
 * For more information about the OpenAirInterface (OAI) Software Alliance:
 *      contact@openairinterface.org
 */

/*! \file eNB_scheduler_dlsch.c
 * \brief procedures related to eNB for the DLSCH transport channel
 * \author  Navid Nikaein and Raymond Knopp
 * \date 2010 - 2014
 * \email: navid.nikaein@eurecom.fr
 * \version 1.0
 * @ingroup _mac

 */

#define _GNU_SOURCE

#include "LAYER2/MAC/mac.h"
#include "LAYER2/MAC/mac_proto.h"
#include "LAYER2/MAC/mac_extern.h"
#include "common/utils/LOG/log.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
#include "UTIL/OPT/opt.h"
#include "OCG.h"
#include "OCG_extern.h"
#include "PHY/LTE_TRANSPORT/transport_common_proto.h"

#include "RRC/LTE/rrc_extern.h"
#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h"

//#include "LAYER2/MAC/pre_processor.c"
#include "pdcp.h"

#include "SIMULATION/TOOLS/sim.h" // for taus

#include "assertions.h"

#if defined(ENABLE_ITTI)
  #include "intertask_interface.h"
#endif

#include <dlfcn.h>

#include "T.h"

#define ENABLE_MAC_PAYLOAD_DEBUG
//#define DEBUG_eNB_SCHEDULER 1

#include "common/ran_context.h"
extern RAN_CONTEXT_t RC;
extern uint8_t nfapi_mode;

//------------------------------------------------------------------------------
void
add_ue_dlsch_info(module_id_t module_idP,
                  int CC_id,
                  int UE_id,
                  sub_frame_t subframeP,
                  UE_DLSCH_STATUS status,
                  rnti_t rnti)
//------------------------------------------------------------------------------
{
  eNB_DLSCH_INFO *info = &eNB_dlsch_info[module_idP][CC_id][UE_id];
  // LOG_D(MAC, "%s(module_idP:%d, CC_id:%d, UE_id:%d, subframeP:%d, status:%d) serving_num:%d rnti:%x\n", __FUNCTION__, module_idP, CC_id, UE_id, subframeP, status, eNB_dlsch_info[module_idP][CC_id][UE_id].serving_num, UE_RNTI(module_idP,UE_id));
  info->rnti = rnti;
  //  info->weight = weight;
  info->subframe = subframeP;
  info->status = status;
  info->serving_num++;
  return;
}

//------------------------------------------------------------------------------
int
schedule_next_dlue(module_id_t module_idP, 
                   int CC_id,
                   sub_frame_t subframeP)
//------------------------------------------------------------------------------
{
  int next_ue;
  UE_list_t *UE_list = &RC.mac[module_idP]->UE_list;

  for (next_ue = UE_list->head; next_ue >= 0; next_ue = UE_list->next[next_ue]) {
    if (eNB_dlsch_info[module_idP][CC_id][next_ue].status == S_DL_WAITING) {
      return next_ue;
    }
  }

  for (next_ue = UE_list->head; next_ue >= 0; next_ue = UE_list->next[next_ue]) {
    if (eNB_dlsch_info[module_idP][CC_id][next_ue].status == S_DL_BUFFERED) {
      eNB_dlsch_info[module_idP][CC_id][next_ue].status = S_DL_WAITING;
    }
  }

  return (-1);        //next_ue;
}

//------------------------------------------------------------------------------
int
generate_dlsch_header(unsigned char *mac_header,
                      unsigned char num_sdus,
                      unsigned short *sdu_lengths,
                      unsigned char *sdu_lcids,
                      unsigned char drx_cmd,
                      unsigned short timing_advance_cmd,
                      unsigned char *ue_cont_res_id,
                      unsigned char short_padding,
                      unsigned short post_padding)
//------------------------------------------------------------------------------
{
  SCH_SUBHEADER_FIXED *mac_header_ptr = (SCH_SUBHEADER_FIXED *) mac_header;
  uint8_t first_element = 0, last_size = 0, i;
  uint8_t mac_header_control_elements[16], *ce_ptr;
  ce_ptr = &mac_header_control_elements[0];

  // compute header components

  if (short_padding == 1 || short_padding == 2) {
    mac_header_ptr->R = 0;
    mac_header_ptr->E = 0;
    mac_header_ptr->LCID = SHORT_PADDING;
    first_element = 1;
    last_size = 1;
  }

  if (short_padding == 2) {
    mac_header_ptr->E = 1;
    mac_header_ptr++;
    mac_header_ptr->R = 0;
    mac_header_ptr->E = 0;
    mac_header_ptr->LCID = SHORT_PADDING;
    last_size = 1;
  }

  if (drx_cmd != 255) {
    if (first_element > 0) {
      mac_header_ptr->E = 1;
      mac_header_ptr++;
    } else {
      first_element = 1;
    }
    mac_header_ptr->R = 0;
    mac_header_ptr->E = 0;
    mac_header_ptr->LCID = DRX_CMD;
    last_size = 1;
  }

  if (timing_advance_cmd != 31) {
    if (first_element > 0) {
      mac_header_ptr->E = 1;
      mac_header_ptr++;
    } else {
      first_element = 1;
    }
    mac_header_ptr->R = 0;
    mac_header_ptr->E = 0;
    mac_header_ptr->LCID = TIMING_ADV_CMD;
    last_size = 1;
    //    msg("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr);
    ((TIMING_ADVANCE_CMD *) ce_ptr)->R = 0;
    AssertFatal(timing_advance_cmd < 64, "timing_advance_cmd %d > 63\n", 
                timing_advance_cmd);
    ((TIMING_ADVANCE_CMD *) ce_ptr)->TA = timing_advance_cmd;    //(timing_advance_cmd+31)&0x3f;
    LOG_D(MAC, "timing advance =%d (%d)\n", 
          timing_advance_cmd,
          ((TIMING_ADVANCE_CMD *) ce_ptr)->TA);
    ce_ptr += sizeof(TIMING_ADVANCE_CMD);
    //msg("offset %d\n",ce_ptr-mac_header_control_elements);
  }

  if (ue_cont_res_id) {
    if (first_element > 0) {
      mac_header_ptr->E = 1;
      /*
      printf("[eNB][MAC] last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr,
      ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R,
      ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E,
      ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID);
      */
      mac_header_ptr++;
    } else {
      first_element = 1;
    }

    mac_header_ptr->R = 0;
    mac_header_ptr->E = 0;
    mac_header_ptr->LCID = UE_CONT_RES;
    last_size = 1;
    LOG_T(MAC, "[eNB ][RAPROC] Generate contention resolution msg: %x.%x.%x.%x.%x.%x\n",
          ue_cont_res_id[0], 
          ue_cont_res_id[1], 
          ue_cont_res_id[2],
          ue_cont_res_id[3], 
          ue_cont_res_id[4], 
          ue_cont_res_id[5]);
    memcpy(ce_ptr, 
           ue_cont_res_id, 
           6);
    ce_ptr += 6;
    // msg("(cont_res) : offset %d\n",ce_ptr-mac_header_control_elements);
  }

  //msg("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr);

  for (i = 0; i < num_sdus; i++) {
    LOG_T(MAC, "[eNB] Generate DLSCH header num sdu %d len sdu %d\n",
          num_sdus, 
          sdu_lengths[i]);

    if (first_element > 0) {
      mac_header_ptr->E = 1;
      /*msg("last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr,
      ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R,
      ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E,
      ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID);
      */
      mac_header_ptr += last_size;
      //msg("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr);
    } else {
      first_element = 1;
    }

    if (sdu_lengths[i] < 128) {
      ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->R = 0;
      ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->E = 0;
      ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->F = 0;
      ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->LCID = sdu_lcids[i];
      ((SCH_SUBHEADER_SHORT *) mac_header_ptr)->L = (unsigned char) sdu_lengths[i];
      last_size = 2;
    } else {
      ((SCH_SUBHEADER_LONG *) mac_header_ptr)->R = 0;
      ((SCH_SUBHEADER_LONG *) mac_header_ptr)->E = 0;
      ((SCH_SUBHEADER_LONG *) mac_header_ptr)->F = 1;
      ((SCH_SUBHEADER_LONG *) mac_header_ptr)->LCID = sdu_lcids[i];
      ((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_MSB = ((unsigned short) sdu_lengths[i] >> 8) & 0x7f;
      ((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_LSB = (unsigned short) sdu_lengths[i] & 0xff;
      ((SCH_SUBHEADER_LONG *) mac_header_ptr)->padding = 0x00;
      last_size = 3;
#ifdef DEBUG_HEADER_PARSING
      LOG_D(MAC, "[eNB] generate long sdu, size %x (MSB %x, LSB %x)\n",
            sdu_lengths[i],
            ((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_MSB,
            ((SCH_SUBHEADER_LONG *) mac_header_ptr)->L_LSB);
#endif
    }
  }

  /*

    printf("last_size %d,mac_header_ptr %p\n",last_size,mac_header_ptr);

    printf("last subheader : %x (R%d,E%d,LCID%d)\n",*(unsigned char*)mac_header_ptr,
    ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->R,
    ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->E,
    ((SCH_SUBHEADER_FIXED *)mac_header_ptr)->LCID);


    if (((SCH_SUBHEADER_FIXED*)mac_header_ptr)->LCID < UE_CONT_RES) {
    if (((SCH_SUBHEADER_SHORT*)mac_header_ptr)->F == 0)
    printf("F = 0, sdu len (L field) %d\n",(((SCH_SUBHEADER_SHORT*)mac_header_ptr)->L));
    else
    printf("F = 1, sdu len (L field) %d\n",(((SCH_SUBHEADER_LONG*)mac_header_ptr)->L));
    }
  */
  if (post_padding > 0) {    // we have lots of padding at the end of the packet
    mac_header_ptr->E = 1;
    mac_header_ptr += last_size;
    // add a padding element
    mac_header_ptr->R = 0;
    mac_header_ptr->E = 0;
    mac_header_ptr->LCID = SHORT_PADDING;
    mac_header_ptr++;
  } else {            // no end of packet padding
    // last SDU subhead is of fixed type (sdu length implicitly to be computed at UE)
    mac_header_ptr++;
  }

  //msg("After subheaders %d\n",(uint8_t*)mac_header_ptr - mac_header);

  if ((ce_ptr - mac_header_control_elements) > 0) {
    // printf("Copying %d bytes for control elements\n",ce_ptr-mac_header_control_elements);
    memcpy((void *) mac_header_ptr, 
           mac_header_control_elements,
           ce_ptr - mac_header_control_elements);
    mac_header_ptr += (unsigned char) (ce_ptr - mac_header_control_elements);
  }

  //msg("After CEs %d\n",(uint8_t*)mac_header_ptr - mac_header);
  return ((unsigned char *) mac_header_ptr - mac_header);
}

//------------------------------------------------------------------------------
void
set_ul_DAI(int module_idP,
           int UE_idP,
           int CC_idP,
           int frameP,
           int subframeP)
//------------------------------------------------------------------------------
{
  eNB_MAC_INST *eNB = RC.mac[module_idP];
  UE_list_t *UE_list = &eNB->UE_list;
  unsigned char DAI;
  COMMON_channels_t *cc = &eNB->common_channels[CC_idP];

  if (cc->tdd_Config != NULL) {    //TDD
    DAI = (UE_list->UE_template[CC_idP][UE_idP].DAI - 1) & 3;
    LOG_D(MAC, "[eNB %d] CC_id %d Frame %d, subframe %d: DAI %d for UE %d\n",
          module_idP,
          CC_idP,
          frameP,
          subframeP,
          DAI,
          UE_idP);
    // Save DAI for Format 0 DCI

    switch (cc->tdd_Config->subframeAssignment) {
      case 0:
        //      if ((subframeP==0)||(subframeP==1)||(subframeP==5)||(subframeP==6))
        break;

      case 1:
        switch (subframeP) {
          case 0:
          case 1:
            UE_list->UE_template[CC_idP][UE_idP].DAI_ul[7] = DAI;
            break;

          case 4:
            UE_list->UE_template[CC_idP][UE_idP].DAI_ul[8] = DAI;
            break;

          case 5:
          case 6:
            UE_list->UE_template[CC_idP][UE_idP].DAI_ul[2] = DAI;
            break;

          case 9:
            UE_list->UE_template[CC_idP][UE_idP].DAI_ul[3] = DAI;
            break;
        }

        break;

      case 2:
        //      if ((subframeP==3)||(subframeP==8))
        //  UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI;
        break;

      case 3:

        //if ((subframeP==6)||(subframeP==8)||(subframeP==0)) {
        //  LOG_D(MAC,"schedule_ue_spec: setting UL DAI to %d for subframeP %d => %d\n",DAI,subframeP, ((subframeP+8)%10)>>1);
        //  UE_list->UE_template[CC_idP][UE_idP].DAI_ul[((subframeP+8)%10)>>1] = DAI;
        //}
        switch (subframeP) {
          case 5:
          case 6:
          case 1:
            UE_list->UE_template[CC_idP][UE_idP].DAI_ul[2] = DAI;
            break;

          case 7:
          case 8:
            UE_list->UE_template[CC_idP][UE_idP].DAI_ul[3] = DAI;
            break;

          case 9:
          case 0:
            UE_list->UE_template[CC_idP][UE_idP].DAI_ul[4] = DAI;
            break;

          default:
            break;
        }

        break;

      case 4:
        //      if ((subframeP==8)||(subframeP==9))
        //  UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI;
        break;

      case 5:
        //      if (subframeP==8)
        //  UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI;
        break;

      case 6:
        //      if ((subframeP==1)||(subframeP==4)||(subframeP==6)||(subframeP==9))
        //  UE_list->UE_template[CC_idP][UE_idP].DAI_ul = DAI;
        break;

      default:
        break;
    }
  }

  return;
}

//------------------------------------------------------------------------------
void
schedule_dlsch(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP, int *mbsfn_flag) {
  int i = 0;
  slice_info_t *sli = &RC.mac[module_idP]->slice_info;
  memset(sli->rballoc_sub, 0, sizeof(sli->rballoc_sub));

  for (i = 0; i < sli->n_dl; i++) {
    // Run each enabled slice-specific schedulers one by one
    sli->dl[i].sched_cb(module_idP, 
                        i, 
                        frameP, 
                        subframeP,
                        mbsfn_flag/*, dl_info*/);
  }
}

// changes to pre-processor for eMTC
//------------------------------------------------------------------------------

void  getRepetition(UE_TEMPLATE * pue_template,unsigned int *maxRep , unsigned int *narrowBandindex){
    LTE_EPDCCH_SetConfig_r11_t *epdcch_setconfig_r11;

    AssertFatal(pue_template->physicalConfigDedicated !=NULL, "no RRC physical configuration for this UE ") ;
    AssertFatal(pue_template->physicalConfigDedicated->ext4 !=NULL, "no RRC physical configuration for this UE ") ;

    AssertFatal(pue_template->physicalConfigDedicated->ext4->epdcch_Config_r11->config_r11.choice.setup.setConfigToAddModList_r11->list.count > 0 ,"epdcch config list is empty") ;

    epdcch_setconfig_r11 = pue_template->physicalConfigDedicated->ext4->epdcch_Config_r11->config_r11.choice.setup.setConfigToAddModList_r11->list.array[0] ;

    AssertFatal(epdcch_setconfig_r11->ext2 !=NULL && epdcch_setconfig_r11->ext2->mpdcch_config_r13 !=NULL," mpdcch config not found")  ;

*maxRep = epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.mpdcch_NumRepetition_r13  ;

    *narrowBandindex = epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.mpdcch_Narrowband_r13  ;




}



/*void
schedule_ue_spec_br(
    module_id_t   module_idP,
    frame_t       frameP,
    sub_frame_t   subframeP,
    int*          mbsfn_flag
)
//------------------------------------------------------------------------------
{
	uint8_t                        CC_id;
	int                            UE_id;
	unsigned char                  aggregation;
	mac_rlc_status_resp_t          rlc_status;
	unsigned char                  header_len_dcch = 0, header_len_dcch_tmp = 0;
	unsigned char                  header_len_dtch = 0, header_len_dtch_tmp = 0, header_len_dtch_last = 0;
	unsigned char                  ta_len = 0;
	unsigned char                  sdu_lcids[NB_RB_MAX], lcid, offset, num_sdus = 0;
	uint16_t                       nb_rb, nb_rb_temp, nb_available_rb;
	uint16_t                       TBS, j, sdu_lengths[NB_RB_MAX], rnti, padding = 0, post_padding = 0;
	unsigned char                  dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES];
	unsigned char                  round = 0;
	unsigned char                  harq_pid = 0;
	eNB_UE_STATS                   *eNB_UE_stats = NULL;
	uint16_t                       sdu_length_total = 0;

	eNB_MAC_INST                   *eNB = RC.mac[module_idP];
	COMMON_channels_t              *cc = eNB->common_channels;
	UE_list_t                      *UE_list = &eNB->UE_list;
	int                            continue_flag = 0;
	int32_t                        normalized_rx_power, target_rx_power;
	int32_t                        tpc = 1;
	static int32_t                 tpc_accumulated = 0;
	UE_sched_ctrl                  *ue_sched_ctl;
	int                            mcs;
	int                            i;
	int                            min_rb_unit[MAX_NUM_CCs];
	int                            N_RB_DL[MAX_NUM_CCs];
	int                            total_nb_available_rb[MAX_NUM_CCs];
	int                            N_RBG[MAX_NUM_CCs];
	nfapi_dl_config_request_body_t *dl_req;
	nfapi_dl_config_request_pdu_t  *dl_config_pdu;
	nfapi_tx_request_pdu_t         *TX_req;
	int                            tdd_sfa;

#if 0
	if (UE_list->head == -1) {
		return;
	}
#endif

	uint8_t                         *vrb_map;
	int								first_rb;
	start_meas(&eNB->schedule_dlsch);
	VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, VCD_FUNCTION_IN);



	aggregation = 2;
	for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
		N_RB_DL[CC_id] = to_prb(cc[CC_id].mib->message.dl_Bandwidth);
		min_rb_unit[CC_id] = get_min_rb_unit(module_idP, CC_id);
		// get number of PRBs less those used by common channels
		total_nb_available_rb[CC_id] = N_RB_DL[CC_id];
		for (i = 0; i < N_RB_DL[CC_id]; i++)
			if (cc[CC_id].vrb_map[i] != 0)
				total_nb_available_rb[CC_id]--;

		N_RBG[CC_id] = to_rbg(cc[CC_id].mib->message.dl_Bandwidth);

		// store the global enb stats:
		eNB->eNB_stats[CC_id].num_dlactive_UEs = UE_list->num_UEs;
		eNB->eNB_stats[CC_id].available_prbs = total_nb_available_rb[CC_id];
		eNB->eNB_stats[CC_id].total_available_prbs += total_nb_available_rb[CC_id];
		eNB->eNB_stats[CC_id].dlsch_bytes_tx = 0;
		eNB->eNB_stats[CC_id].dlsch_pdus_tx = 0;
	}

	/// CALLING Pre_Processor for downlink scheduling (Returns estimation of RBs required by each UE and the allocation on sub-band)

	VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR, VCD_FUNCTION_IN);
	//start_meas(&eNB->schedule_dlsch_preprocessor);
	//dlsch_scheduler_pre_processor(module_idP,
	 //   frameP,
	//    subframeP,
	//    N_RBG,
	 //   mbsfn_flag);
	//stop_meas(&eNB->schedule_dlsch_preprocessor);
	VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR, VCD_FUNCTION_OUT);


	for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++)
	{
		vrb_map = cc[CC_id].vrb_map;

		LOG_D(MAC, "doing schedule_ue_spec for CC_id %d\n", CC_id);

		dl_req = &eNB->DL_req[CC_id].dl_config_request_body;

		if (mbsfn_flag[CC_id] > 0)
			continue;
		
	    unsigned int rmax;
            unsigned int narrowBandindex_index;
            unsigned int first_rb, rep, reps;

            // rmax from RRC connection setup
            getRepetition(&UE_list->UE_template[CC_id][UE_id], &rmax, &narrowBandindex_index);

            first_rb = narrowband_to_first_rb(cc,narrowBandindex_index);

		if (vrb_map[first_rb] == 1)  // skip scheduling emtc UEs if first RB is taken 
			continue ; 

		for (UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id])
		{

            if (UE_list->UE_template[CC_id][UE_id].rach_resource_type ==0 )  // do  the following scheduling only if the UE is emtc
                  continue ;

            //[khalid] ******** allocate here the vrb_map
            // 1st check on the vrb_map[] and allocate the one that is next to them

            // at the end of the scheduler make sure the right subbands coresponding to these RBs are allocated the UE in UE_template directely
            // also check on the fill_DCI function

            

            vrb_map[first_rb] = 1;
            vrb_map[first_rb + 1] = 1;
            vrb_map[first_rb + 2] = 1;
            vrb_map[first_rb + 3] = 1;
            vrb_map[first_rb + 4] = 1;
            vrb_map[first_rb + 5] = 1;





			continue_flag = 0; // reset the flag to allow allocation for the remaining UEs
			rnti = UE_RNTI(module_idP, UE_id);
			eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id];
			ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id];

            //[khalid] allocate the middle RB subbands in sf 1,5 for synch signals and PBCH




			if (rnti == NOT_A_RNTI) {
				LOG_D(MAC, "Cannot find rnti for UE_id %d (num_UEs %d)\n", UE_id, UE_list->num_UEs);
				continue_flag = 1;
			}

			if (eNB_UE_stats == NULL) {
				LOG_D(MAC, "[eNB] Cannot find eNB_UE_stats\n");
				continue_flag = 1;
			}

			//if (continue_flag != 1) {
			//	switch (get_tmode(module_idP, CC_id, UE_id)) {
			//	case 1:
			//	case 2:
			//	case 7:
			//		aggregation = get_aggregation(get_bw_index(module_idP, CC_id),
			//			eNB_UE_stats->dl_cqi,
			//			format1);
			//		break;
			//	case 3:
			//		aggregation = get_aggregation(get_bw_index(module_idP, CC_id),
			//			eNB_UE_stats->dl_cqi,
			//			format2A);
			//		break;
			//	default:
			//		LOG_W(MAC, "Unsupported transmission mode %d\n", get_tmode(module_idP, CC_id, UE_id));
			//		aggregation = 2;
			//	}
			//}

			if ((ue_sched_ctl->pre_nb_available_rbs[CC_id] == 0) ||  // no RBs allocated
				CCE_allocation_infeasible(module_idP, CC_id, 0, subframeP, aggregation, rnti)
				) {
				LOG_D(MAC, "[eNB %d] Frame %d : no RB allocated for UE %d on CC_id %d: continue \n",
					module_idP, frameP, UE_id, CC_id);
				continue_flag = 1; //to next user (there might be rbs availiable for other UEs in TM5
			}

			//if (cc[CC_id].tdd_Config != NULL) { //TDD
			//	set_ue_dai(subframeP,
			//		UE_id,
			//		CC_id,
			//		cc[CC_id].tdd_Config->subframeAssignment,
			//		UE_list);
			//	// update UL DAI after DLSCH scheduling
			//	set_ul_DAI(module_idP, UE_id, CC_id, frameP, subframeP);
			//}

		   //if (continue_flag == 1) {
			//    add_ue_dlsch_info(module_idP,
		   //         CC_id,
			//        UE_id,
			//        subframeP,
			//        S_DL_NONE);
		  //      continue;
		   // }

			nb_available_rb = 6; // to be checked
			harq_pid = ue_sched_ctl->harq_pid[CC_id];
			round = ue_sched_ctl->round[CC_id];
			UE_list->eNB_UE_stats[CC_id][UE_id].crnti = rnti;
			UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status = mac_eNB_get_rrc_status(module_idP, rnti);x
			UE_list->eNB_UE_stats[CC_id][UE_id].harq_pid = harq_pid;
			UE_list->eNB_UE_stats[CC_id][UE_id].harq_round = round;

			sdu_length_total = 0;
			num_sdus = 0;


			//DevCheck(((eNB_UE_stats->dl_cqi < MIN_CQI_VALUE) || (eNB_UE_stats->dl_cqi > MAX_CQI_VALUE)),
			//eNB_UE_stats->dl_cqi, MIN_CQI_VALUE, MAX_CQI_VALUE);

			eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[eNB_UE_stats->dl_cqi]; //to be checked
			eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1, 15);


			// store stats
			UE_list->eNB_UE_stats[CC_id][UE_id].dl_cqi = eNB_UE_stats->dl_cqi;

			// initializing the rb allocation indicator for each UE
			//to be checked
			for (j = 0; j < N_RBG[CC_id]; j++) {
				UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = 0;
			}

			LOG_D(MAC, "[eNB %d] Frame %d: Scheduling UE %d on CC_id %d (rnti %x, harq_pid %d, round %d, rb %d, cqi %d, mcs %d, rrc %d)\n",
				module_idP, frameP, UE_id, CC_id, rnti, harq_pid, round, nb_available_rb,
				eNB_UE_stats->dl_cqi, eNB_UE_stats->dlsch_mcs1,
				UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status);



			// process retransmission

			if (round > 0)
			{


                // choose r3 by default for RAR (Table 9.1.5-5)
                rep = 2;
                // get actual repetition count from Table 9.1.5-3
                reps = (rmax <= 8) ? (1 << rep) : (rmax >> (3 - rep));


				// get freq_allocation
				nb_rb = 6;//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 < N_RBG[CC_id]; j++) { // for indicating the rballoc for each sub-band
							UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j];
						}
					//}
					//else {
					//	nb_rb_temp = nb_rb;
					//	j = 0;

					//	while ((nb_rb_temp > 0) && (j < N_RBG[CC_id])) {
					//		if (ue_sched_ctl->rballoc_sub_UE[CC_id][j] == 1) {
					//			UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j];

					//			if ((j == N_RBG[CC_id] - 1) &&
					//				((N_RB_DL[CC_id] == 25) ||
					//				(N_RB_DL[CC_id] == 50))) {
					//				nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id] + 1;
					//			}
					//			else {
					//				nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id];
					//			}
					//		}

					//		j = j + 1;
					//	}
					//}

					nb_available_rb -= nb_rb;

					//eNB->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb;
					//eNB->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id];

					//for(j=0; j<N_RBG[CC_id]; j++) {
					//eNB->mu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j];
					//}


					switch (get_tmode(module_idP, CC_id, UE_id)) {
					case 1:
					case 2:
					case 7:
					default:
                    {

                        if ((UE_list->UE_template[CC_id][UE_id].mpdcch_repetition_cnt == 0) &&
                            (mpdcch_sf_condition(eNB, CC_id, frameP, subframeP, rmax, TYPEUESPEC,UE_id) > 0))
						{
							// MPDCCH configuration for RAR
							dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu];
							memset((void*)dl_config_pdu, 0, sizeof(nfapi_dl_config_request_pdu_t));
							dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_MPDCCH_PDU_TYPE;
							dl_config_pdu->pdu_size = (uint8_t)(2 + sizeof(nfapi_dl_config_mpdcch_pdu));
                            dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_format = (UE_list->UE_template[CC_id][UE_id].rach_resource_type > 1) ? 11 : 10;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_narrow_band = narrowBandindex_index;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.number_of_prb_pairs = 6;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_assignment = 0; // Note: this can be dynamic
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_tansmission_type = 1; // imposed (9.1.5 in 213) for Type 2 Common search space
                            AssertFatal(cc[CC_id].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13 != NULL,
								"cc[CC_id].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13 is null\n");
                            dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.start_symbol = cc[CC_id].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->startSymbolBR_r13;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ecce_index = 0;  // Note: this should be dynamic
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.aggregation_level = 16; // OK for CEModeA r1-3 (9.1.5-1b) or CEModeB r1-4
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti_type = 4;  // other-RNTI
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti = rnti;
                            dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ce_mode = (UE_list->UE_template[CC_id][UE_id].rach_resource_type < 3) ? 1 : 2;
                            dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.drms_scrambling_init = cc[CC_id].physCellId;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.initial_transmission_sf_io = (frameP * 10) + subframeP;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.transmission_power = 6000; // 0dB

                            //[khalid] missing DCI format   should be 10 for 6-1A

							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_coding = getRIV(6, 0, 6);  // Note: still to be checked if it should not be (getRIV(N_RB_DL,first_rb,6)) : Check nFAPI specifications and what is done L1 with this parameter
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mcs = UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid]; // adjust according to size of RAR, 208 bits with N1A_PRB=3
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pdsch_reptition_levels = 4; // fix to 4 for now
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.redundancy_version = (round & 3);
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.new_data_indicator = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid];
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_process = harq_pid;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi_length = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi_flag = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_resource_offset = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_subframe_repetition_number = rep;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpc = 1;// N1A_PRB=3 (36.212); => 208 bits for mcs=4, choose mcs according t message size TBD
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.downlink_assignment_index_length = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.downlink_assignment_index = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.allocate_prach_flag = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.preamble_index = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.prach_mask_index = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.starting_ce_level = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.srs_request = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity_flag = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.frequency_hopping_enabled_flag = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.paging_direct_indication_differentiation_flag = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.direct_indication = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.total_dci_length_including_padding = 0; // this is not needed by OAI L1, but should be filled in
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.number_of_tx_antenna_ports = 1;
                            UE_list->UE_template[CC_id][UE_id].mpdcch_repetition_cnt++;
							dl_req->number_pdu++;


							

							//eNB_UE_stats->dlsch_trials[round]++;
							UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission += 1;
							UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx = nb_rb;
							UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_retx += nb_rb;
							UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 = eNB_UE_stats->dlsch_mcs1;
							UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2 = eNB_UE_stats->dlsch_mcs1;

							add_ue_dlsch_info(module_idP,
								CC_id,
								UE_id,
								subframeP,
								S_DL_SCHEDULED);

						} //repetition_count==0 && SF condition met
                        else if (UE_list->UE_template[CC_id][UE_id].mpdcch_repetition_cnt > 0)
						{
							// we're in a stream of repetitions
                            UE_list->UE_template[CC_id][UE_id].mpdcch_repetition_cnt++;
                            if (UE_list->UE_template[CC_id][UE_id].mpdcch_repetition_cnt == reps)
							{
								// this is the last mpdcch repetition
                                if (cc[CC_id].tdd_Config == NULL) { // FDD case
																	 // wait 2 subframes for PDSCH transmission
                                    if (subframeP > 7) UE_list->UE_template[CC_id][UE_id].Msg2_frame = (frameP + 1) & 1023;
                                    else             UE_list->UE_template[CC_id][UE_id].Msg2_frame = frameP;
                                    UE_list->UE_template[CC_id][UE_id].Msg2_subframe = (subframeP + 2) % 10; // +2 is the "n+x" from Section 7.1.11  in 36.213
								}
								else {
									AssertFatal(1 == 0, "TDD case not done yet\n");
								}
							} // mpdcch_repetition_count == reps
                            if ((UE_list->UE_template[CC_id][UE_id].Msg2_frame == frameP) && (UE_list->UE_template[CC_id][UE_id].Msg2_subframe == subframeP)) {
								// Program PDSCH

								dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu];
								memset((void*)dl_config_pdu, 0, sizeof(nfapi_dl_config_request_pdu_t));
								dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE;
								dl_config_pdu->pdu_size = (uint8_t)(2 + sizeof(nfapi_dl_config_dlsch_pdu));
                                dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = eNB->pdu_index[CC_id];
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = rnti;
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 4;   // format 6-1A
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0;   // localized
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = getRIV(N_RB_DL, first_rb, 6);
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = (round & 3);
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1;// first block
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = 0;
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = (cc->p_eNB == 1) ? 0 : 1;
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = 1;
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = 1;
								//	dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index                         = ;
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = 1;
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = 0;
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0;
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = (cc->p_eNB == 1) ? 1 : 2;
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = 1;
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1;
								//	dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector                    = ;

                                dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = (UE_list->UE_template[CC_id][UE_id].rach_resource_type < 3) ? 1 : 2;;
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 2;  // not SI message
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = (10 * frameP) + subframeP;
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.drms_table_flag = 0;
								dl_req->number_pdu++;


							}
						}

					}



					
					}

					

					
				}
				else {
					LOG_D(MAC, "[eNB %d] Frame %d CC_id %d : don't schedule UE %d, its retransmission takes more resources than we have\n",
						module_idP, frameP, CC_id, UE_id);
				}
			}
			else 
			{ 
				// This is a potentially new SDU opportunity //

				rlc_status.bytes_in_buffer = 0;
				// Now check RLC information to compute number of required RBs
				// get maximum TBS size for RLC request



				TBS = 408;
				// check first for RLC data on DCCH
				// add the length for  all the control elements (timing adv, drx, etc) : header + payload

				ta_len = (ue_sched_ctl->ta_update != 0) ? 2 : 0;

				header_len_dcch = 2; // 2 bytes DCCH SDU subheader

				if (TBS - ta_len - header_len_dcch > 0) {
					rlc_status = mac_rlc_status_ind(
						module_idP,
						rnti,
						module_idP,
						frameP,
						subframeP,
						ENB_FLAG_YES,
						MBMS_FLAG_NO,
						DCCH,
						(TBS - ta_len - header_len_dcch)); // transport block set size

					sdu_lengths[0] = 0;

					if (rlc_status.bytes_in_buffer > 0) {  // There is DCCH to transmit
						LOG_D(MAC, "[eNB %d] Frame %d, DL-DCCH->DLSCH CC_id %d, Requesting %d bytes from RLC (RRC message)\n",
							module_idP, frameP, CC_id, TBS - header_len_dcch);
						sdu_lengths[0] = mac_rlc_data_req(
							module_idP,
							rnti,
							module_idP,
							frameP,
							ENB_FLAG_YES,
							MBMS_FLAG_NO,
							DCCH,
							TBS, //not used
							(char *)&dlsch_buffer[0]);

						T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP),
							T_INT(harq_pid), T_INT(DCCH), T_INT(sdu_lengths[0]));

						LOG_D(MAC, "[eNB %d][DCCH] CC_id %d Got %d bytes from RLC\n", module_idP, CC_id, sdu_lengths[0]);
						sdu_length_total = sdu_lengths[0];
						sdu_lcids[0] = DCCH;
						UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[DCCH] += 1;
						UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH] += sdu_lengths[0];
						num_sdus = 1;
#ifdef DEBUG_eNB_SCHEDULER
						LOG_T(MAC, "[eNB %d][DCCH] CC_id %d Got %d bytes :", module_idP, CC_id, sdu_lengths[0]);

						for (j = 0; j < sdu_lengths[0]; j++) {
							LOG_T(MAC, "%x ", dlsch_buffer[j]);
						}

						LOG_T(MAC, "\n");
#endif
					}
					else {
						header_len_dcch = 0;
						sdu_length_total = 0;
					}
				}

				// check for DCCH1 and update header information (assume 2 byte sub-header)
				if (TBS - ta_len - header_len_dcch - sdu_length_total > 0) {
					rlc_status = mac_rlc_status_ind(
						module_idP,
						rnti,
						module_idP,
						frameP,
						subframeP,
						ENB_FLAG_YES,
						MBMS_FLAG_NO,
						DCCH + 1,
						(TBS - ta_len - header_len_dcch - sdu_length_total)); // transport block set size less allocations for timing advance and
																			  // DCCH SDU
					sdu_lengths[num_sdus] = 0;

					if (rlc_status.bytes_in_buffer > 0) {
						LOG_I(MAC, "[eNB %d], Frame %d, DCCH1->DLSCH, CC_id %d, Requesting %d bytes from RLC (RRC message)\n",
							module_idP, frameP, CC_id, TBS - header_len_dcch - sdu_length_total);
						sdu_lengths[num_sdus] += mac_rlc_data_req(
							module_idP,
							rnti,
							module_idP,
							frameP,
							ENB_FLAG_YES,
							MBMS_FLAG_NO,
							DCCH + 1,
							TBS, //not used
							(char *)&dlsch_buffer[sdu_length_total]);

						T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP),
							T_INT(harq_pid), T_INT(DCCH + 1), T_INT(sdu_lengths[num_sdus]));

						sdu_lcids[num_sdus] = DCCH1;
						sdu_length_total += sdu_lengths[num_sdus];
						header_len_dcch += 2;
						UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[DCCH1] += 1;
						UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH1] += sdu_lengths[num_sdus];
						num_sdus++;
#ifdef DEBUG_eNB_SCHEDULER
						LOG_T(MAC, "[eNB %d][DCCH1] CC_id %d Got %d bytes :", module_idP, CC_id, sdu_lengths[num_sdus]);

						for (j = 0; j < sdu_lengths[num_sdus]; j++) {
							LOG_T(MAC, "%x ", dlsch_buffer[j]);
						}

						LOG_T(MAC, "\n");
#endif

					}
				}

				// assume the max dtch header size, and adjust it later
				header_len_dtch = 0;
				header_len_dtch_last = 0; // the header length of the last mac sdu
										  // lcid has to be sorted before the actual allocation (similar struct as ue_list).
				for (lcid = NB_RB_MAX - 1; lcid >= DTCH; lcid--) {
					// TBD: check if the lcid is active

					header_len_dtch += 3;
					header_len_dtch_last = 3;
					LOG_D(MAC, "[eNB %d], Frame %d, DTCH%d->DLSCH, Checking RLC status (tbs %d, len %d)\n",
						module_idP, frameP, lcid, TBS,
						TBS - ta_len - header_len_dcch - sdu_length_total - header_len_dtch);

					if (TBS - ta_len - header_len_dcch - sdu_length_total - header_len_dtch > 0) { // NN: > 2 ? 
						rlc_status = mac_rlc_status_ind(module_idP,
							rnti,
							module_idP,
							frameP,
							subframeP,
							ENB_FLAG_YES,
							MBMS_FLAG_NO,
							lcid,
							TBS - ta_len - header_len_dcch - sdu_length_total - header_len_dtch);


						if (rlc_status.bytes_in_buffer > 0) {

							LOG_D(MAC, "[eNB %d][USER-PLANE DEFAULT DRB] Frame %d : DTCH->DLSCH, Requesting %d bytes from RLC (lcid %d total hdr len %d)\n",
								module_idP, frameP, TBS - header_len_dcch - sdu_length_total - header_len_dtch, lcid, header_len_dtch);
							sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP,
								rnti,
								module_idP,
								frameP,
								ENB_FLAG_YES,
								MBMS_FLAG_NO,
								lcid,
								TBS,	//not used
								(char*)&dlsch_buffer[sdu_length_total]);
							T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP),
								T_INT(harq_pid), T_INT(lcid), T_INT(sdu_lengths[num_sdus]));

							LOG_D(MAC, "[eNB %d][USER-PLANE DEFAULT DRB] Got %d bytes for DTCH %d \n", module_idP, sdu_lengths[num_sdus], lcid);
							sdu_lcids[num_sdus] = lcid;
							sdu_length_total += sdu_lengths[num_sdus];
							UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[lcid] += 1;
							UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[lcid] += sdu_lengths[num_sdus];
							if (sdu_lengths[num_sdus] < 128) {
								header_len_dtch--;
								header_len_dtch_last--;
							}
							num_sdus++;
						} // no data for this LCID
						else {
							header_len_dtch -= 3;
						}
					} // no TBS left
					else {
						header_len_dtch -= 3;
						break;
					}
				}
				if (header_len_dtch == 0)
					header_len_dtch_last = 0;
				// there is at least one SDU 
				// if (num_sdus > 0 ){
				if ((sdu_length_total + header_len_dcch + header_len_dtch) > 0) {

					// Now compute number of required RBs for total sdu length
					// Assume RAH format 2
					// adjust  header lengths
					header_len_dcch_tmp = header_len_dcch;
					header_len_dtch_tmp = header_len_dtch;
					if (header_len_dtch == 0) {
						header_len_dcch = (header_len_dcch > 0) ? 1 : 0;//header_len_dcch;  // remove length field
					}
					else {
						header_len_dtch_last -= 1; // now use it to find how many bytes has to be removed for the last MAC SDU 
						header_len_dtch = (header_len_dtch > 0) ? header_len_dtch - header_len_dtch_last : header_len_dtch;     // remove length field for the last SDU
					}

					//mcs = eNB_UE_stats->dlsch_mcs1;
					//if (mcs == 0) {
					//	nb_rb = 4;  // don't let the TBS get too small
					//}
					//else {
					//	nb_rb = min_rb_unit[CC_id];
					//}

                    //[khalid]: maximum MCS (7 or 15) depend on the DCI formate used from UE_list->UE_template[CC_id [UE_id].rach_resource_type

					mcs = 4;
					nb_rb = 6;


					TBS = 408;//get_TBS_DL(mcs, nb_rb);

					//while (TBS < (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) {
					//	nb_rb += min_rb_unit[CC_id];  //

					//	if (nb_rb > nb_available_rb) { // if we've gone beyond the maximum number of RBs
					//								 // (can happen if N_RB_DL is odd)
					//		TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1, nb_available_rb);
					//		nb_rb = nb_available_rb;
					//		break;
					//	}

					//	TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1, nb_rb);
					//}

					//if (nb_rb == ue_sched_ctl->pre_nb_available_rbs[CC_id]) {
						for (j = 0; j < N_RBG[CC_id]; j++) { // for indicating the rballoc for each sub-band
							UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j];
						}
					//}
					//else 
					//{
					//	nb_rb_temp = nb_rb;
					//	j = 0;

					//	while ((nb_rb_temp > 0) && (j < N_RBG[CC_id])) {
					//		if (ue_sched_ctl->rballoc_sub_UE[CC_id][j] == 1) {
					//			UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j] = ue_sched_ctl->rballoc_sub_UE[CC_id][j];

					//			if ((j == N_RBG[CC_id] - 1) &&
					//				((N_RB_DL[CC_id] == 25) ||
					//				(N_RB_DL[CC_id] == 50))) {
					//				nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id] + 1;
					//			}
					//			else {
					//				nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id];
					//			}
					//		}

					//		j = j + 1;
					//	}
					//}
					
					//RC.eNB[module_idP][CC_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb;
					//RC.eNB[module_idP][CC_id]->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id];

					//for(j=0; j<N_RBG[CC_id]; j++) {
					//RC.eNB[module_idP][CC_id]->mu_mimo_mode[UE_id].rballoc_sub[j] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][j];

					//}
					//
					// decrease mcs until TBS falls below required length
					//while ((TBS > (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && (mcs > 0)) {
					//	mcs--;
					//	TBS = get_TBS_DL(mcs, nb_rb);
					//}

                    // if we have decreased too much or we don't have enough RBs, increase MCS
					//while ((TBS < (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && (((ue_sched_ctl->dl_pow_off[CC_id] > 0) && (mcs < 28))
					//	|| ((ue_sched_ctl->dl_pow_off[CC_id] == 0) && (mcs <= 15)))) {
					//	mcs++;
					//	TBS = get_TBS_DL(mcs, nb_rb);
					//}

					LOG_D(MAC, "dlsch_mcs before and after the rate matching = (%d, %d)\n", eNB_UE_stats->dlsch_mcs1, mcs);

#ifdef DEBUG_eNB_SCHEDULER
					LOG_D(MAC, "[eNB %d] CC_id %d Generated DLSCH header (mcs %d, TBS %d, nb_rb %d)\n",
						module_idP, CC_id, mcs, TBS, nb_rb);
					// msg("[MAC][eNB ] Reminder of DLSCH with random data %d %d %d %d \n",
					//  TBS, sdu_length_total, offset, TBS-sdu_length_total-offset);
#endif

					if ((TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len) <= 2) {
						padding = (TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len);
						post_padding = 0;
					}
					else {
						padding = 0;

						// adjust the header len
						if (header_len_dtch == 0) {
							header_len_dcch = header_len_dcch_tmp;
						}
						else { //if (( header_len_dcch==0)&&((header_len_dtch==1)||(header_len_dtch==2)))
							header_len_dtch = header_len_dtch_tmp;
						}

						post_padding = TBS - sdu_length_total - header_len_dcch - header_len_dtch - ta_len; // 1 is for the postpadding header
					}


					offset = generate_dlsch_header((unsigned char*)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0],
						num_sdus,              //num_sdus
						sdu_lengths,  //
						sdu_lcids,
						255,                                   // no drx
						ue_sched_ctl->ta_update, // timing advance
						NULL,                                  // contention res id
						padding,
						post_padding);

					//#ifdef DEBUG_eNB_SCHEDULER
					if (ue_sched_ctl->ta_update) {
						LOG_I(MAC,
							"[eNB %d][DLSCH] Frame %d Generate header for UE_id %d on CC_id %d: sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d,timing advance value : %d, padding %d,post_padding %d,(mcs %d, TBS %d, nb_rb %d),header_dcch %d, header_dtch %d\n",
							module_idP, frameP, UE_id, CC_id, sdu_length_total, num_sdus, sdu_lengths[0], sdu_lcids[0], offset,
							ue_sched_ctl->ta_update, padding, post_padding, mcs, TBS, nb_rb, header_len_dcch, header_len_dtch);
					}
					//#endif
#ifdef DEBUG_eNB_SCHEDULER
					LOG_T(MAC, "[eNB %d] First 16 bytes of DLSCH : \n");

					for (i = 0; i < 16; i++) {
						LOG_T(MAC, "%x.", dlsch_buffer[i]);
					}

					LOG_T(MAC, "\n");
#endif
					// cycle through SDUs and place in dlsch_buffer
					memcpy(&UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset], dlsch_buffer, sdu_length_total);
					// memcpy(RC.mac[0].DLSCH_pdu[0][0].payload[0][offset],dcch_buffer,sdu_lengths[0]);

					// fill remainder of DLSCH with random data
					for (j = 0; j < (TBS - sdu_length_total - offset); j++) {
						UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset + sdu_length_total + j] = (char)(taus() & 0xff);
					}


					if (opt_enabled == 1) {
						trace_pdu(1, (uint8_t *)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0],
							TBS, module_idP, 3, UE_RNTI(module_idP, UE_id),
							eNB->frame, eNB->subframe, 0, 0);
						LOG_D(OPT, "[eNB %d][DLSCH] CC_id %d Frame %d  rnti %x  with size %d\n",
							module_idP, CC_id, frameP, UE_RNTI(module_idP, UE_id), TBS);
					}

					T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP),
						T_INT(harq_pid), T_BUFFER(UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], TBS));

					UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid] = nb_rb;

					add_ue_dlsch_info(module_idP,
						CC_id,
						UE_id,
						subframeP,
						S_DL_SCHEDULED);
					// store stats
					eNB->eNB_stats[CC_id].dlsch_bytes_tx += sdu_length_total;
					eNB->eNB_stats[CC_id].dlsch_pdus_tx += 1;

					UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb;
					UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used += nb_rb;
					UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 = 4;//eNB_UE_stats->dlsch_mcs1;
					UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2 = mcs;
					UE_list->eNB_UE_stats[CC_id][UE_id].TBS = TBS;

					UE_list->eNB_UE_stats[CC_id][UE_id].overhead_bytes = TBS - sdu_length_total;
					UE_list->eNB_UE_stats[CC_id][UE_id].total_sdu_bytes += sdu_length_total;
					UE_list->eNB_UE_stats[CC_id][UE_id].total_pdu_bytes += TBS;
					UE_list->eNB_UE_stats[CC_id][UE_id].total_num_pdus += 1;

					

					// do PUCCH power control
					// this is the normalized RX power
					eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id];
					normalized_rx_power = eNB_UE_stats->Po_PUCCH_dBm;
					target_rx_power = get_target_pucch_rx_power(module_idP, CC_id) + 20;

					// this assumes accumulated tpc
					// make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out
					//int32_t framex10psubframe = UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame * 10 + UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe;
					//if (((framex10psubframe + 10) <= (frameP * 10 + subframeP)) || //normal case
					//	((framex10psubframe > (frameP * 10 + subframeP)) && (((10240 - framex10psubframe + frameP * 10 + subframeP) >= 10)))) //frame wrap-around
					//	if (eNB_UE_stats->Po_PUCCH_update == 1) {
					//		eNB_UE_stats->Po_PUCCH_update = 0;

					//		UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame = frameP;
					//		UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe = subframeP;

					//		if (normalized_rx_power > (target_rx_power + 1)) {
					//			tpc = 0; //-1
					//			tpc_accumulated--;
					//		}
					//		else if (normalized_rx_power < (target_rx_power - 1)) {
					//			tpc = 2; //+1
					//			tpc_accumulated++;
					//		}
					//		else {
					//			tpc = 1; //0
					//		}
					//		
					//		

					//	} // Po_PUCCH has been updated 
					//	else {
					//		tpc = 1; //0
					//	} // time to do TPC update 
					//else {
					//	tpc = 1; //0
					//}

                    {

						// choose r3 by default for RAR (Table 9.1.5-5)
						rep = 2;
						// get actual repetition count from Table 9.1.5-3
						reps = (rmax <= 8) ? (1 << rep) : (rmax >> (3 - rep));
						


                        if ((UE_list->UE_template[CC_id][UE_id].mpdcch_repetition_cnt == 0) &&
                            (mpdcch_sf_condition(eNB, CC_id, frameP, subframeP, rmax, TYPEUESPEC,UE_id) > 0))
						{
							// MPDCCH configuration for RAR
							dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu];
							memset((void*)dl_config_pdu, 0, sizeof(nfapi_dl_config_request_pdu_t));
							dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_MPDCCH_PDU_TYPE;
							dl_config_pdu->pdu_size = (uint8_t)(2 + sizeof(nfapi_dl_config_mpdcch_pdu));
                            dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_format = (UE_list->UE_template[CC_id][UE_id].rach_resource_type > 1) ? 11 : 10;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_narrow_band = narrowBandindex_index;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.number_of_prb_pairs = 6;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_assignment = 0; // Note: this can be dynamic
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_tansmission_type = 1; // imposed (9.1.5 in 213) for Type 2 Common search space
                            AssertFatal(cc[CC_id].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13 != NULL,
								"cc[CC_id].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13 is null\n");
                            dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.start_symbol = cc[CC_id].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->startSymbolBR_r13;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ecce_index = 0;  // Note: this should be dynamic
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.aggregation_level = 16; // OK for CEModeA r1-3 (9.1.5-1b) or CEModeB r1-4
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti_type = 4;  // other-RNTI
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti = rnti;
                            dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ce_mode = (UE_list->UE_template[CC_id][UE_id].rach_resource_type < 3) ? 1 : 2;
                            dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.drms_scrambling_init = cc[CC_id].physCellId;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.initial_transmission_sf_io = (frameP * 10) + subframeP;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.transmission_power = 6000; // 0dB
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_coding = getRIV(6, 0, 6);  // Note: still to be checked if it should not be (getRIV(N_RB_DL,first_rb,6)) : Check nFAPI specifications and what is done L1 with this parameter
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mcs = 4; // adjust according to size of RAR, 208 bits with N1A_PRB=3
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pdsch_reptition_levels = 4; // fix to 4 for now
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.redundancy_version = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.new_data_indicator = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid];
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_process = harq_pid;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi_length = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi_flag = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_resource_offset = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_subframe_repetition_number = rep;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpc = 1;// N1A_PRB=3 (36.212); => 208 bits for mcs=4, choose mcs according t message size TBD
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.downlink_assignment_index_length = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.downlink_assignment_index = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.allocate_prach_flag = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.preamble_index = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.prach_mask_index = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.starting_ce_level = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.srs_request = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity_flag = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.frequency_hopping_enabled_flag = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.paging_direct_indication_differentiation_flag = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.direct_indication = 0;
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.total_dci_length_including_padding = 0; // this is not needed by OAI L1, but should be filled in
							dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.number_of_tx_antenna_ports = 1;
                            UE_list->UE_template[CC_id][UE_id].mpdcch_repetition_cnt++;
							dl_req->number_pdu++;


							// Toggle NDI for next time
							LOG_D(MAC, "CC_id %d Frame %d, subframeP %d: Toggling Format1 NDI for UE %d (rnti %x/%d) oldNDI %d\n",
								CC_id, frameP, subframeP, UE_id,
								UE_list->UE_template[CC_id][UE_id].rnti, harq_pid, UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid]);

							UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid] = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid];
							UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid] = mcs;
							UE_list->UE_template[CC_id][UE_id].oldmcs2[harq_pid] = 0;

							eNB->TX_req[CC_id].sfn_sf = (frameP << 3) + subframeP;
							TX_req = &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB->TX_req[CC_id].tx_request_body.number_of_pdus];
							TX_req->pdu_length = TBS;
							TX_req->pdu_index = eNB->pdu_index[CC_id]++;
							TX_req->num_segments = 1;
							TX_req->segments[0].segment_length = TBS;
							TX_req->segments[0].segment_data = eNB->UE_list.DLSCH_pdu[CC_id][0][(unsigned char)UE_id].payload[harq_pid];
							eNB->TX_req[CC_id].tx_request_body.number_of_pdus++;

						} //repetition_count==0 && SF condition met
                        else if (UE_list->UE_template[CC_id][UE_id].mpdcch_repetition_cnt > 0)
						{
							// we're in a stream of repetitions
                            UE_list->UE_template[CC_id][UE_id].mpdcch_repetition_cnt++;
                            if (UE_list->UE_template[CC_id][UE_id].mpdcch_repetition_cnt == reps)
							{ 
								// this is the last mpdcch repetition
                                if (cc[CC_id].tdd_Config == NULL) { // FDD case
																	 // wait 2 subframes for PDSCH transmission
                                    if (subframeP > 7) UE_list->UE_template[CC_id][UE_id].Msg2_frame = (frameP + 1) & 1023;
                                    else             UE_list->UE_template[CC_id][UE_id].Msg2_frame = frameP;
                                    UE_list->UE_template[CC_id][UE_id].Msg2_subframe = (subframeP + 2) % 10; // +2 is the "n+x" from Section 7.1.11  in 36.213
								}
								else {
									AssertFatal(1 == 0, "TDD case not done yet\n");
								}
							} // mpdcch_repetition_count == reps
                            if ((UE_list->UE_template[CC_id][UE_id].Msg2_frame == frameP) && (UE_list->UE_template[CC_id][UE_id].Msg2_subframe == subframeP)) {
								// Program PDSCH
								
								dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu];
								memset((void*)dl_config_pdu, 0, sizeof(nfapi_dl_config_request_pdu_t));
								dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE;
								dl_config_pdu->pdu_size = (uint8_t)(2 + sizeof(nfapi_dl_config_dlsch_pdu));
                                dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = eNB->pdu_index[CC_id];
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = rnti;
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 4;   // format 6-1A
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0;   // localized
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = getRIV(N_RB_DL, first_rb, 6);
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = 0;
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1;// first block
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = 0;
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = (cc->p_eNB == 1) ? 0 : 1;
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = 1;
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = 1;
								//	dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index                         = ;
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = 1;
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = 0;
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0;
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = (cc->p_eNB == 1) ? 1 : 2;
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = 1;
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1;
								//	dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector                    = ;

                                dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = (UE_list->UE_template[CC_id][UE_id].rach_resource_type < 3) ? 1 : 2;;
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 2;  // not SI message
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = (10 * frameP) + subframeP;
								dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.drms_table_flag = 0;
								dl_req->number_pdu++;

								// Program UL processing for Msg3, same as regular LTE
								//get_Msg3alloc(&cc[CC_idP], subframeP, frameP, &RA_template->Msg3_frame, &RA_template->Msg3_subframe);


								//fill_rar_br(eNB, CC_idP, RA_template, frameP, subframeP, cc[CC_idP].RAR_pdu.payload, RA_template->rach_resource_type - 1);
								//// DL request
								//eNB->TX_req[CC_idP].sfn_sf = (frameP << 3) + subframeP;
								//TX_req = &eNB->TX_req[CC_idP].tx_request_body.tx_pdu_list[eNB->TX_req[CC_idP].tx_request_body.number_of_pdus];
								//TX_req->pdu_length = 7;  // This should be changed if we have more than 1 preamble
								//TX_req->pdu_index = eNB->pdu_index[CC_idP]++;
								//TX_req->num_segments = 1;
								//TX_req->segments[0].segment_length = 7;
								//TX_req->segments[0].segment_data = cc[CC_idP].RAR_pdu.payload;
								//eNB->TX_req[CC_idP].tx_request_body.number_of_pdus++;
							}
						}

					}

					//dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu];
					//memset((void*)dl_config_pdu, 0, sizeof(nfapi_dl_config_request_pdu_t));
					//dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE;
					//dl_config_pdu->pdu_size = (uint8_t)(2 + sizeof(nfapi_dl_config_dci_dl_pdu));
					//dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1;
					//dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = get_aggregation(get_bw_index(module_idP, CC_id), eNB_UE_stats->dl_cqi, format1);
					//dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti;
					//dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1;    // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications
					//dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power

					//dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = harq_pid;
					//dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = tpc; // dont adjust power when retransmitting
					//dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = 1 - UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid];
					//dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs;
					//dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = 0;
					////deactivate second codeword
					//dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_2 = 0;
					//dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_2 = 1;
				
					//dl_req->number_dci++;
					//dl_req->number_pdu++;


				}
				else {  // There is no data from RLC or MAC header, so don't schedule

				}
			}

			if (cc[CC_id].tdd_Config != NULL) { // TDD
				set_ul_DAI(module_idP, UE_id, CC_id, frameP, subframeP);
			}

		} // UE_id loop
	}  // CC_id loop


	fill_DLSCH_dci(module_idP, frameP, subframeP, mbsfn_flag);

	stop_meas(&eNB->schedule_dlsch);
	VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, VCD_FUNCTION_OUT);

}
*/

			
//------------------------------------------------------------------------------
void
schedule_ue_spec(module_id_t module_idP,
                 int slice_idxP,
                 frame_t frameP,
                 sub_frame_t subframeP,
                 int *mbsfn_flag)
//------------------------------------------------------------------------------
{
  int CC_id;
  int UE_id;
  int aggregation;
  mac_rlc_status_resp_t rlc_status;
  int ta_len = 0;
  unsigned char sdu_lcids[NB_RB_MAX];
  int lcid, offset, num_sdus = 0;
  int nb_rb, nb_rb_temp, nb_available_rb;
  uint16_t sdu_lengths[NB_RB_MAX];
  int TBS, j, padding = 0, post_padding = 0;
  rnti_t rnti;
  unsigned char dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES];
  int round = 0;
  int harq_pid = 0;
  uint16_t release_num;
  uint8_t ra_ii;
  eNB_UE_STATS *eNB_UE_stats = NULL;
  UE_TEMPLATE *ue_template = NULL;
  eNB_STATS *eNB_stats = NULL;
  RRC_release_ctrl *release_ctrl = NULL;
  DLSCH_PDU *dlsch_pdu = NULL;
  RA_t *ra = NULL;
  int sdu_length_total = 0;
  eNB_MAC_INST *eNB = RC.mac[module_idP];
  COMMON_channels_t *cc = eNB->common_channels;
  UE_list_t *UE_list = &eNB->UE_list;
  int continue_flag = 0;
  int32_t normalized_rx_power, target_rx_power;
  int tpc = 1;
  UE_sched_ctrl *ue_sched_ctrl;
  int mcs;
  int i;
  int min_rb_unit[NFAPI_CC_MAX];
  int N_RB_DL[NFAPI_CC_MAX];
  int total_nb_available_rb[NFAPI_CC_MAX];
  int N_RBG[NFAPI_CC_MAX];
  nfapi_dl_config_request_body_t *dl_req;
  nfapi_dl_config_request_pdu_t *dl_config_pdu;
  int tdd_sfa;
  int ta_update;
  int header_length_last;
  int header_length_total;
  rrc_eNB_ue_context_t *ue_contextP = NULL;
  int nb_mac_CC = RC.nb_mac_CC[module_idP];
  long dl_Bandwidth;

  start_meas(&eNB->schedule_dlsch);
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, 
                                          VCD_FUNCTION_IN);

  // for TDD: check that we have to act here, otherwise return
  if (cc[0].tdd_Config) {
    tdd_sfa = cc[0].tdd_Config->subframeAssignment;

    switch (subframeP) {
      case 0:
        // always continue
        break;

      case 1:
      case 2:
        return;

      case 3:
        if (tdd_sfa != 2 && tdd_sfa != 5)
          return;

        break;

      case 4:
        if (tdd_sfa != 1 && tdd_sfa != 2 && tdd_sfa != 4 && tdd_sfa != 5)
          return;

        break;

      case 5:
        break;

      case 6:
      case 7:
        if (tdd_sfa != 3 && tdd_sfa != 4 && tdd_sfa != 5)
          return;

        break;

      case 8:
        if (tdd_sfa != 2 && tdd_sfa != 3 && tdd_sfa != 4 && tdd_sfa != 5)
          return;

        break;

      case 9:
        if (tdd_sfa == 0)
          return;

        break;
    }
  }

  //weight = get_ue_weight(module_idP,UE_id);
  aggregation = 2;

  for (CC_id = 0, eNB_stats = &eNB->eNB_stats[0]; CC_id < nb_mac_CC; CC_id++, eNB_stats++) {
    dl_Bandwidth = cc[CC_id].mib->message.dl_Bandwidth;
    N_RB_DL[CC_id] = to_prb(dl_Bandwidth);
    min_rb_unit[CC_id] = get_min_rb_unit(module_idP, 
                                         CC_id);
    // get number of PRBs less those used by common channels
    total_nb_available_rb[CC_id] = N_RB_DL[CC_id];

    for (i = 0; i < N_RB_DL[CC_id]; i++)
      if (cc[CC_id].vrb_map[i] != 0)
        total_nb_available_rb[CC_id]--;

    N_RBG[CC_id] = to_rbg(dl_Bandwidth);
    // store the global enb stats:
    eNB_stats->num_dlactive_UEs = UE_list->num_UEs;
    eNB_stats->available_prbs = total_nb_available_rb[CC_id];
    eNB_stats->total_available_prbs += total_nb_available_rb[CC_id];
    eNB_stats->dlsch_bytes_tx = 0;
    eNB_stats->dlsch_pdus_tx = 0;
  }

  // CALLING Pre_Processor for downlink scheduling
  // (Returns estimation of RBs required by each UE and the allocation on sub-band)
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR, 
                                          VCD_FUNCTION_IN);
  start_meas(&eNB->schedule_dlsch_preprocessor);
  dlsch_scheduler_pre_processor(module_idP,
                                slice_idxP,
                                frameP,
                                subframeP,
                                mbsfn_flag,
                                eNB->slice_info.rballoc_sub);
  stop_meas(&eNB->schedule_dlsch_preprocessor);
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_PREPROCESSOR, 
                                          VCD_FUNCTION_OUT);

  //RC.mac[module_idP]->slice_info.slice_counter--;
  // Do the multiplexing and actual allocation only when all slices have been pre-processed.
  //if (RC.mac[module_idP]->slice_info.slice_counter > 0) {
  //stop_meas(&eNB->schedule_dlsch);
  //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, VCD_FUNCTION_OUT);
  //return;
  //}

  if (RC.mac[module_idP]->slice_info.interslice_share_active) {
    dlsch_scheduler_interslice_multiplexing(module_idP,
                                            frameP,
                                            subframeP,
                                            eNB->slice_info.rballoc_sub);
    /* the interslice multiplexing re-sorts the UE_list for the slices it tries
     * to multiplex, so we need to sort it for the current slice again */
    sort_UEs(module_idP,
             slice_idxP,
             frameP,
             subframeP);
  }

  for (CC_id = 0; CC_id < nb_mac_CC; CC_id++) {
    LOG_D(MAC, "doing schedule_ue_spec for CC_id %d\n",
          CC_id);
    dl_req = &eNB->DL_req[CC_id].dl_config_request_body;

    if (mbsfn_flag[CC_id] > 0)
      continue;

    for (UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) {
      LOG_D(MAC, "doing schedule_ue_spec for CC_id %d UE %d\n",
            CC_id,
            UE_id);
      continue_flag = 0; // reset the flag to allow allocation for the remaining UEs
      rnti = UE_RNTI(module_idP, UE_id);
      ue_sched_ctrl = &UE_list->UE_sched_ctrl[UE_id];
      ue_template = &UE_list->UE_template[CC_id][UE_id];

      if (ue_template->rach_resource_type > 0) continue_flag = 1;
	
      if (&(UE_list->eNB_UE_stats[CC_id][UE_id]) == NULL) {
        LOG_D(MAC, "[eNB] Cannot find eNB_UE_stats\n");
        continue_flag = 1;
      } else {
        eNB_UE_stats = &(UE_list->eNB_UE_stats[CC_id][UE_id]);
      }

      if (continue_flag != 1) {
        switch (get_tmode(module_idP, 
                          CC_id, 
                          UE_id)) {
          case 1:
          case 2:
          case 7:
            aggregation = get_aggregation(get_bw_index(module_idP, 
                                                       CC_id),
                                          ue_sched_ctrl->dl_cqi[CC_id],
                                          format1);
            break;

          case 3:
            aggregation = get_aggregation(get_bw_index(module_idP, 
                                                       CC_id),
                                          ue_sched_ctrl->dl_cqi[CC_id],
                                          format2A);
            break;

          default:
            AssertFatal(1==0,"Unsupported transmission mode %d\n", get_tmode(module_idP, CC_id, UE_id));
            aggregation = 2;
            break;
        }
      }

      /* if (continue_flag != 1 */
      if (ue_sched_ctrl->pre_nb_available_rbs[CC_id] == 0 || // no RBs allocated
          CCE_allocation_infeasible(module_idP, 
                                    CC_id, 
                                    1, 
                                    subframeP, 
                                    aggregation, 
                                    rnti)) {
        LOG_D(MAC, "[eNB %d] Frame %d : no RB allocated for UE %d on CC_id %d: continue \n",
              module_idP,
              frameP,
              UE_id,
              CC_id);
        continue_flag = 1;  //to next user (there might be rbs availiable for other UEs in TM5
      }

      // If TDD
      if (cc[CC_id].tdd_Config != NULL) {    //TDD
        set_ue_dai(subframeP,
                   UE_id,
                   CC_id,
                   cc[CC_id].tdd_Config->subframeAssignment,
                   UE_list);
        // update UL DAI after DLSCH scheduling
        set_ul_DAI(module_idP,
                   UE_id,
                   CC_id,
                   frameP,
                   subframeP);
      }

      if (continue_flag == 1) {
        add_ue_dlsch_info(module_idP,
                          CC_id,
                          UE_id,
                          subframeP,
                          S_DL_NONE,
                          rnti);
        continue;
      }

      nb_available_rb = ue_sched_ctrl->pre_nb_available_rbs[CC_id];
      harq_pid = frame_subframe2_dl_harq_pid(cc->tdd_Config,
                                             frameP,
                                             subframeP);
      round = ue_sched_ctrl->round[CC_id][harq_pid];
      eNB_UE_stats->crnti = rnti;
      eNB_UE_stats->rrc_status = mac_eNB_get_rrc_status(module_idP, rnti);
      eNB_UE_stats->harq_pid = harq_pid;
      eNB_UE_stats->harq_round = round;

      if (eNB_UE_stats->rrc_status < RRC_CONNECTED) {
        LOG_D(MAC, "UE %d is not in RRC_CONNECTED\n",
              UE_id);
        continue;
      }

      header_length_total = 0;
      sdu_length_total = 0;
      num_sdus = 0;

      /*
      DevCheck(((eNB_UE_stats->dl_cqi < MIN_CQI_VALUE) ||
                (eNB_UE_stats->dl_cqi > MAX_CQI_VALUE)),
                eNB_UE_stats->dl_cqi, MIN_CQI_VALUE, MAX_CQI_VALUE);
      */
      if (nfapi_mode) {
        eNB_UE_stats->dlsch_mcs1 = 10; // cqi_to_mcs[ue_sched_ctrl->dl_cqi[CC_id]];
      } else { // this operation is also done in the preprocessor
        eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1,
                                        eNB->slice_info.dl[slice_idxP].maxmcs);  // cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs);
      }

      // Store stats
      // eNB_UE_stats->dl_cqi= eNB_UE_stats->dl_cqi;

      // Initializing the rb allocation indicator for each UE
      for (j = 0; j < N_RBG[CC_id]; j++) {
        ue_template->rballoc_subband[harq_pid][j] = 0;
      }

      LOG_D(MAC, "[eNB %d] Frame %d: Scheduling UE %d on CC_id %d (rnti %x, harq_pid %d, round %d, rb %d, cqi %d, mcs %d, rrc %d)\n",
            module_idP, 
            frameP, UE_id, 
            CC_id, 
            rnti, 
            harq_pid,
             round,
            nb_available_rb, 
            ue_sched_ctrl->dl_cqi[CC_id],
            eNB_UE_stats->dlsch_mcs1,
            eNB_UE_stats->rrc_status);

      /* process retransmission  */
      if (round != 8) {
        // get freq_allocation
        nb_rb = ue_template->nb_rb[harq_pid];
        TBS = get_TBS_DL(ue_template->oldmcs1[harq_pid], 
                         nb_rb);

        if (nb_rb <= nb_available_rb) {
          if (cc[CC_id].tdd_Config != NULL) {
            ue_template->DAI++;
            update_ul_dci(module_idP, 
                          CC_id, 
                          rnti,
                          ue_template->DAI, 
                          subframeP);
            LOG_D(MAC, "DAI update: CC_id %d subframeP %d: UE %d, DAI %d\n",
                  CC_id, 
                  subframeP, 
                  UE_id,
                  ue_template->DAI);
          }

          if (nb_rb == ue_sched_ctrl->pre_nb_available_rbs[CC_id]) {
            for (j = 0; j < N_RBG[CC_id]; j++) { // for indicating the rballoc for each sub-band
              ue_template->rballoc_subband[harq_pid][j] = ue_sched_ctrl->rballoc_sub_UE[CC_id][j];
            }
          } else {
            nb_rb_temp = nb_rb;
            j = 0;

            while ((nb_rb_temp > 0) && (j < N_RBG[CC_id])) {
              if (ue_sched_ctrl->rballoc_sub_UE[CC_id][j] == 1) {
                if (ue_template->rballoc_subband[harq_pid][j])
                  LOG_W(MAC, "WARN: rballoc_subband not free for retrans?\n");

                ue_template->rballoc_subband[harq_pid][j] = ue_sched_ctrl->rballoc_sub_UE[CC_id][j];

                nb_rb_temp -= min_rb_unit[CC_id];
                if ((j == N_RBG[CC_id] - 1) && (N_RB_DL[CC_id] == 25 || N_RB_DL[CC_id] == 50))
                  nb_rb_temp++;
              }
              j++;
            }
          }

          nb_available_rb -= nb_rb;
          /*
          eNB->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb;
          eNB->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctrl->dl_pow_off[CC_id];

          for(j = 0; j < N_RBG[CC_id]; ++j) {
            eNB->mu_mimo_mode[UE_id].rballoc_sub[j] = ue_template->rballoc_subband[harq_pid][j];
          }
          */

          switch (get_tmode(module_idP, CC_id, UE_id)) {
            case 1:
            case 2:
            case 7:
            default:
              LOG_D(MAC, "retransmission DL_REQ: rnti:%x\n", 
                    rnti);
              dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu];
              memset((void *) dl_config_pdu, 
                     0, 
                     sizeof(nfapi_dl_config_request_pdu_t));
              dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE;
              dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu));
              dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG;
              dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1;
              dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level =
                get_aggregation(get_bw_index(module_idP, 
                                             CC_id),
                                ue_sched_ctrl->dl_cqi[CC_id],
                                format1);
              dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti;
              dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1; // CRNTI: see Table 4-10 from SCF082 - nFAPI specifications
              dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power
              dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = harq_pid;
              dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = 1; // Don't adjust power when retransmitting
              dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = ue_template->oldNDI[harq_pid];
              dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = ue_template->oldmcs1[harq_pid];
              dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = round & 3;

              // TDD
              if (cc[CC_id].tdd_Config != NULL) {
                dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.downlink_assignment_index = (ue_template->DAI - 1) & 3;
                LOG_D(MAC, "[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, dai %d, mcs %d\n",
                      module_idP, 
                      CC_id, 
                      harq_pid, 
                      round,
                      ue_template->DAI - 1,
                      ue_template->oldmcs1[harq_pid]);
              } else {
                LOG_D(MAC, "[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, mcs %d\n",
                      module_idP, 
                      CC_id, 
                      harq_pid, 
                      round,
                      ue_template->oldmcs1[harq_pid]);
              }

              if (!CCE_allocation_infeasible(module_idP, 
                                             CC_id, 
                                             1, 
                                             subframeP,
                                             dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, 
                                             rnti)) {
                dl_req->number_dci++;
                dl_req->number_pdu++;
                dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG;
                eNB->DL_req[CC_id].sfn_sf = frameP<<4 | subframeP;
                eNB->DL_req[CC_id].header.message_id = NFAPI_DL_CONFIG_REQUEST;
                fill_nfapi_dlsch_config(eNB, 
                                        dl_req, 
                                        TBS, 
                                        -1,   // retransmission, no pdu_index 
                                        rnti, 
                                        0,    // type 0 allocation from 7.1.6 in 36.213
                                        0,    // virtual_resource_block_assignment_flag, unused here
                                        0,    // resource_block_coding, to be filled in later
                                        getQm(ue_template->oldmcs1[harq_pid]),
                                        round & 3, // redundancy version
                                        1,    // transport blocks
                                        0,    // transport block to codeword swap flag
                                        cc[CC_id].p_eNB == 1 ? 0 : 1,    // transmission_scheme
                                        1,    // number of layers
                                        1,    // number of subbands
                                        //                      uint8_t codebook_index,
                                        4,    // UE category capacity
                                        ue_template->physicalConfigDedicated->pdsch_ConfigDedicated->p_a,
                                        0,    // delta_power_offset for TM5
                                        0,    // ngap
                                        0,    // nprb
                                        cc[CC_id].p_eNB == 1 ? 1 : 2,    // transmission mode
                                        0,    //number of PRBs treated as one subband, not used here
                                        0);   // number of beamforming vectors, not used here
                                       
                LOG_D(MAC, "Filled NFAPI configuration for DCI/DLSCH %d, retransmission round %d\n",
                      eNB->pdu_index[CC_id], 
                      round);
                program_dlsch_acknak(module_idP, 
                                     CC_id, 
                                     UE_id, 
                                     frameP, 
                                     subframeP,
                                     dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.cce_idx);
                // No TX request for retransmission (check if null request for FAPI)
              } else {
                LOG_W(MAC, "Frame %d, Subframe %d: Dropping DLSCH allocation for UE %d\%x, infeasible CCE allocation\n",
                      frameP, 
                      subframeP, 
                      UE_id, 
                      rnti);
              }
          }

          add_ue_dlsch_info(module_idP, 
                            CC_id, UE_id, 
                            subframeP, 
                            S_DL_SCHEDULED, 
                            rnti);
          //eNB_UE_stats->dlsch_trials[round]++;
          eNB_UE_stats->num_retransmission += 1;
          eNB_UE_stats->rbs_used_retx = nb_rb;
          eNB_UE_stats->total_rbs_used_retx += nb_rb;
          eNB_UE_stats->dlsch_mcs2 = eNB_UE_stats->dlsch_mcs1;
        } else {
          LOG_D(MAC,
                "[eNB %d] Frame %d CC_id %d : don't schedule UE %d, its retransmission takes more resources than we have\n",
                module_idP, 
                frameP, 
                CC_id, 
                UE_id);
        }
      } else {    /* This is a potentially new SDU opportunity */
        rlc_status.bytes_in_buffer = 0;
        // Now check RLC information to compute number of required RBs
        // get maximum TBS size for RLC request
        TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1, 
                         nb_available_rb);

        // add the length for  all the control elements (timing adv, drx, etc) : header + payload

        if (ue_sched_ctrl->ta_timer == 0) {
          ta_update = ue_sched_ctrl->ta_update;

          /* if we send TA then set timer to not send it for a while */
          if (ta_update != 31) {
            ue_sched_ctrl->ta_timer = 20;
          }
          /* reset ta_update */
          ue_sched_ctrl->ta_update = 31;
        } else {
          ta_update = 31;
        }

        ta_len = (ta_update != 31) ? 2 : 0;

        // RLC data on DCCH
        if (TBS - ta_len - header_length_total - sdu_length_total - 3 > 0) {
          rlc_status = mac_rlc_status_ind(module_idP, 
                                          rnti, 
                                          module_idP, 
                                          frameP, 
                                          subframeP, 
                                          ENB_FLAG_YES, 
                                          MBMS_FLAG_NO, 
                                          DCCH,
                                          TBS - ta_len - header_length_total - sdu_length_total - 3
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
                                          , 0
                                          , 0
#endif
                                         );
          sdu_lengths[0] = 0;

          if (rlc_status.bytes_in_buffer > 0) {
            LOG_D(MAC, "[eNB %d] SFN/SF %d.%d, DL-DCCH->DLSCH CC_id %d, Requesting %d bytes from RLC (RRC message)\n",
                  module_idP, 
                  frameP, 
                  subframeP, 
                  CC_id,
                  TBS - ta_len - header_length_total - sdu_length_total - 3);
            sdu_lengths[0] = mac_rlc_data_req(module_idP, 
                                              rnti, 
                                              module_idP, 
                                              frameP, 
                                              ENB_FLAG_YES, 
                                              MBMS_FLAG_NO, 
                                              DCCH,
                                              TBS, //not used
                                              (char *)&dlsch_buffer[0]
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
                                              , 0
                                              , 0
#endif
                                              );
            pthread_mutex_lock(&rrc_release_freelist);

            if((rrc_release_info.num_UEs > 0) && (rlc_am_mui.rrc_mui_num > 0)) {
              uint16_t release_total = 0;

              for (release_num = 0, release_ctrl = &rrc_release_info.RRC_release_ctrl[0]; 
                   release_num < NUMBER_OF_UE_MAX; 
                   release_num++, release_ctrl++) {
                if(release_ctrl->flag > 0) {
                  release_total++;
                } else {
                  continue;
                }

                if(release_ctrl->flag == 1) {
                  if(release_ctrl->rnti == rnti) {
                    for(uint16_t mui_num = 0; mui_num < rlc_am_mui.rrc_mui_num; mui_num++) {
                      if(release_ctrl->rrc_eNB_mui == rlc_am_mui.rrc_mui[mui_num]) {
                        release_ctrl->flag = 3;
                        LOG_D(MAC,"DLSCH Release send:index %d rnti %x mui %d mui_num %d flag 1->3\n",
                              release_num,
                              rnti,
                              rlc_am_mui.rrc_mui[mui_num],
                              mui_num);
                        break;
                      }
                    }
                  }
                }

                if(release_ctrl->flag == 2) {
                  if(release_ctrl->rnti == rnti) {
                    for (uint16_t mui_num = 0; mui_num < rlc_am_mui.rrc_mui_num; mui_num++) {
                      if(release_ctrl->rrc_eNB_mui == rlc_am_mui.rrc_mui[mui_num]) {
                        release_ctrl->flag = 4;
                        LOG_D(MAC, "DLSCH Release send:index %d rnti %x mui %d mui_num %d flag 2->4\n",
                              release_num,
                              rnti,
                              rlc_am_mui.rrc_mui[mui_num],
                              mui_num);
                        break;
                      }
                    }
                  }
                }

                if(release_total >= rrc_release_info.num_UEs)
                  break;
              }
            }

            pthread_mutex_unlock(&rrc_release_freelist);

            for (ra_ii = 0, ra = &eNB->common_channels[CC_id].ra[0]; ra_ii < NB_RA_PROC_MAX; ra_ii++, ra++) {
              if ((ra->rnti == rnti) && (ra->state == MSGCRNTI)) {
                for (uint16_t mui_num = 0; mui_num < rlc_am_mui.rrc_mui_num; mui_num++) {
                  if (ra->crnti_rrc_mui == rlc_am_mui.rrc_mui[mui_num]) {
                    ra->crnti_harq_pid = harq_pid;
                    ra->state = MSGCRNTI_ACK;
                    break;
                  }
                }
              }
            }

            T(T_ENB_MAC_UE_DL_SDU, 
              T_INT(module_idP),
              T_INT(CC_id), 
              T_INT(rnti), 
              T_INT(frameP),
              T_INT(subframeP), 
              T_INT(harq_pid), 
              T_INT(DCCH),
              T_INT(sdu_lengths[0]));
            LOG_D(MAC, "[eNB %d][DCCH] CC_id %d Got %d bytes from RLC\n",
                  module_idP, 
                  CC_id, 
                  sdu_lengths[0]);
            sdu_length_total = sdu_lengths[0];
            sdu_lcids[0] = DCCH;
            eNB_UE_stats->lcid_sdu[0] = DCCH;
            eNB_UE_stats->sdu_length_tx[DCCH] = sdu_lengths[0];
            eNB_UE_stats->num_pdu_tx[DCCH] += 1;
            eNB_UE_stats->num_bytes_tx[DCCH] += sdu_lengths[0];
            header_length_last = 1 + 1 + (sdu_lengths[0] >= 128);
            header_length_total += header_length_last;
            num_sdus = 1;
#ifdef DEBUG_eNB_SCHEDULER
            LOG_T(MAC, "[eNB %d][DCCH] CC_id %d Got %d bytes :",
                  module_idP, 
                  CC_id, 
                  sdu_lengths[0]);
            for (j = 0; j < sdu_lengths[0]; ++j) {
              LOG_T(MAC, "%x ", 
                    dlsch_buffer[j]);
            }
            LOG_T(MAC, "\n");
#endif
          }
        }

        // RLC data on DCCH1
        if (TBS - ta_len - header_length_total - sdu_length_total - 3 > 0) {
          rlc_status = mac_rlc_status_ind(module_idP, 
                                          rnti, 
                                          module_idP, 
                                          frameP, 
                                          subframeP, 
                                          ENB_FLAG_YES, 
                                          MBMS_FLAG_NO, 
                                          DCCH + 1,
                                          TBS - ta_len - header_length_total - sdu_length_total - 3
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
                                          , 0
                                          , 0
#endif
                                          );
          // DCCH SDU
          sdu_lengths[num_sdus] = 0;

          if (rlc_status.bytes_in_buffer > 0) {
            LOG_D(MAC, "[eNB %d], Frame %d, DCCH1->DLSCH, CC_id %d, Requesting %d bytes from RLC (RRC message)\n",
                  module_idP, frameP, CC_id,
                  TBS - ta_len - header_length_total - sdu_length_total - 3);
            sdu_lengths[num_sdus] += mac_rlc_data_req(module_idP, 
                                                      rnti, 
                                                      module_idP, 
                                                      frameP, 
                                                      ENB_FLAG_YES, 
                                                      MBMS_FLAG_NO, DCCH + 1,
                                                      TBS, //not used
                                                      (char *) &dlsch_buffer[sdu_length_total]
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
                                                      , 0
                                                      , 0
#endif
                                                      );
            T(T_ENB_MAC_UE_DL_SDU, 
              T_INT(module_idP),
              T_INT(CC_id), 
              T_INT(rnti), 
              T_INT(frameP),
              T_INT(subframeP), 
              T_INT(harq_pid),
              T_INT(DCCH + 1), 
              T_INT(sdu_lengths[num_sdus]));
            sdu_lcids[num_sdus] = DCCH1;
            sdu_length_total += sdu_lengths[num_sdus];
            eNB_UE_stats->lcid_sdu[num_sdus] = DCCH1;
            eNB_UE_stats->sdu_length_tx[DCCH1] = sdu_lengths[num_sdus];
            eNB_UE_stats->num_pdu_tx[DCCH1] += 1;
            eNB_UE_stats->num_bytes_tx[DCCH1] += sdu_lengths[num_sdus];
            header_length_last = 1 + 1 + (sdu_lengths[num_sdus] >= 128);
            header_length_total += header_length_last;
            num_sdus++;
#ifdef DEBUG_eNB_SCHEDULER
            LOG_T(MAC, "[eNB %d][DCCH1] CC_id %d Got %d bytes :",
                  module_idP, 
                  CC_id, 
                  sdu_lengths[num_sdus]);
            for (j = 0; j < sdu_lengths[num_sdus]; ++j) {
              LOG_T(MAC, "%x ", 
                    dlsch_buffer[j]);
            }
            LOG_T(MAC, "\n");
#endif
          }
        }

        // TODO: lcid has to be sorted before the actual allocation (similar struct as ue_list).
        for (lcid = NB_RB_MAX - 1; lcid >= DTCH; lcid--) {
          // TODO: check if the lcid is active
          LOG_D(MAC, "[eNB %d], Frame %d, DTCH%d->DLSCH, Checking RLC status (tbs %d, len %d)\n",
                module_idP,
                frameP,
                lcid,
                TBS,
                TBS - ta_len - header_length_total - sdu_length_total - 3);

          if (TBS - ta_len - header_length_total - sdu_length_total - 3 > 0) {
            rlc_status = mac_rlc_status_ind(module_idP,
                                            rnti,
                                            module_idP,
                                            frameP,
                                            subframeP,
                                            ENB_FLAG_YES,
                                            MBMS_FLAG_NO,
                                            lcid,
                                            TBS - ta_len - header_length_total - sdu_length_total - 3
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
                                            , 0
                                            , 0
#endif
                                            );

            if (rlc_status.bytes_in_buffer > 0) {
              LOG_D(MAC, "[eNB %d][USER-PLANE DEFAULT DRB] Frame %d : DTCH->DLSCH, Requesting %d bytes from RLC (lcid %d total hdr len %d)\n",
                    module_idP,
                    frameP,
                    TBS - ta_len - header_length_total - sdu_length_total - 3,
                    lcid,
                    header_length_total);
              sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP,
                                                       rnti,
                                                       module_idP,
                                                       frameP,
                                                       ENB_FLAG_YES,
                                                       MBMS_FLAG_NO,
                                                       lcid,
                                                       TBS, //not used
                                                       (char *) &dlsch_buffer[sdu_length_total]
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
                                                       , 0
                                                       , 0
#endif
                                                       );
              T(T_ENB_MAC_UE_DL_SDU,
                T_INT(module_idP),
                T_INT(CC_id),
                T_INT(rnti),
                T_INT(frameP),
                T_INT(subframeP),
                T_INT(harq_pid),
                T_INT(lcid),
                T_INT(sdu_lengths[num_sdus]));
              LOG_D(MAC, "[eNB %d][USER-PLANE DEFAULT DRB] Got %d bytes for DTCH %d \n",
                    module_idP,
                    sdu_lengths[num_sdus],
                    lcid);
              sdu_lcids[num_sdus] = lcid;
              sdu_length_total += sdu_lengths[num_sdus];
              eNB_UE_stats->num_pdu_tx[lcid]++;
              eNB_UE_stats->lcid_sdu[num_sdus] = lcid;
              eNB_UE_stats->sdu_length_tx[lcid] = sdu_lengths[num_sdus];
              eNB_UE_stats->num_bytes_tx[lcid] += sdu_lengths[num_sdus];
              header_length_last = 1 + 1 + (sdu_lengths[num_sdus] >= 128);
              header_length_total += header_length_last;
              num_sdus++;
              ue_sched_ctrl->uplane_inactivity_timer = 0;
              // reset RRC inactivity timer after uplane activity
              ue_contextP = rrc_eNB_get_ue_context(RC.rrc[module_idP], rnti);

              if (ue_contextP != NULL) {
                ue_contextP->ue_context.ue_rrc_inactivity_timer = 1;
              } else {
                LOG_E(MAC, "[eNB %d] CC_id %d Couldn't find the context associated to UE (RNTI %d) and reset RRC inactivity timer\n",
                      module_idP,
                      CC_id,
                      rnti);
              }
            } // end if (rlc_status.bytes_in_buffer > 0)
          } else {  // no TBS left
            break;  // break for (lcid = NB_RB_MAX - 1; lcid >= DTCH; lcid--)
          }
        }

        /* last header does not have length field */
        if (header_length_total) {
          header_length_total -= header_length_last;
          header_length_total++;
        }

        // there is at least one SDU or TA command
        // if (num_sdus > 0 ){
        if (ta_len + sdu_length_total + header_length_total > 0) {
          // Now compute number of required RBs for total sdu length
          // Assume RAH format 2
          mcs = eNB_UE_stats->dlsch_mcs1;

          if (mcs == 0) {
            nb_rb = 4;    // don't let the TBS get too small
          } else {
            nb_rb = min_rb_unit[CC_id];
          }

          TBS = get_TBS_DL(mcs, nb_rb);

          while (TBS < sdu_length_total + header_length_total + ta_len) {
            nb_rb += min_rb_unit[CC_id];  //

            if (nb_rb > nb_available_rb) {  // if we've gone beyond the maximum number of RBs
              // (can happen if N_RB_DL is odd)
              TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1, 
                               nb_available_rb);
              nb_rb = nb_available_rb;
              break;
            }

            TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1, 
                             nb_rb);
          }

          if (nb_rb == ue_sched_ctrl->pre_nb_available_rbs[CC_id]) {
            for (j = 0; j < N_RBG[CC_id]; ++j) {    // for indicating the rballoc for each sub-band
              ue_template->rballoc_subband[harq_pid][j] = ue_sched_ctrl->rballoc_sub_UE[CC_id][j];
            }
          } else {
            nb_rb_temp = nb_rb;
            j = 0;

            while ((nb_rb_temp > 0) && (j < N_RBG[CC_id])) {
              if (ue_sched_ctrl->rballoc_sub_UE[CC_id][j] == 1) {
                ue_template->rballoc_subband[harq_pid][j] = ue_sched_ctrl->rballoc_sub_UE[CC_id][j];

                if ((j == N_RBG[CC_id] - 1) && ((N_RB_DL[CC_id] == 25) || (N_RB_DL[CC_id] == 50))) {
                  nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id] + 1;
                } else {
                  nb_rb_temp = nb_rb_temp - min_rb_unit[CC_id];
                }
              }

              j++;
            }
          }

          // decrease mcs until TBS falls below required length
          while ((TBS > sdu_length_total + header_length_total + ta_len) && (mcs > 0)) {
            mcs--;
            TBS = get_TBS_DL(mcs, 
                             nb_rb);
          }

          // if we have decreased too much or we don't have enough RBs, increase MCS
          while (TBS < sdu_length_total + header_length_total + ta_len && 
                 ((ue_sched_ctrl->dl_pow_off[CC_id] > 0 && mcs < 28) || (ue_sched_ctrl->dl_pow_off[CC_id] == 0 && mcs <= 15))) {
            mcs++;
            TBS = get_TBS_DL(mcs, 
                             nb_rb);
          }

          LOG_D(MAC, "dlsch_mcs before and after the rate matching = (%d, %d)\n",
                eNB_UE_stats->dlsch_mcs1, 
                mcs);
#ifdef DEBUG_eNB_SCHEDULER
          LOG_D(MAC, "[eNB %d] CC_id %d Generated DLSCH header (mcs %d, TBS %d, nb_rb %d)\n",
                module_idP, 
                CC_id, 
                mcs, TBS, 
                nb_rb);
          // msg("[MAC][eNB ] Reminder of DLSCH with random data %d %d %d %d \n",
          //  TBS, sdu_length_total, offset, TBS-sdu_length_total-offset);
#endif

          if (TBS - header_length_total - sdu_length_total - ta_len <= 2) {
            padding = TBS - header_length_total - sdu_length_total - ta_len;
            post_padding = 0;
          } else {
            padding = 0;
            post_padding = 1;
          }

          offset = generate_dlsch_header((unsigned char *) UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0],
                                         num_sdus,    //num_sdus
                                         sdu_lengths,    //
                                         sdu_lcids, 
                                         255,    // no drx
                                         ta_update,    // timing advance
                                         NULL,    // contention res id
                                         padding, 
                                         post_padding);

          //#ifdef DEBUG_eNB_SCHEDULER
          if (ta_update != 31) {
            LOG_D(MAC, 
                  "[eNB %d][DLSCH] Frame %d Generate header for UE_id %d on CC_id %d: sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d,timing advance value : %d, padding %d,post_padding %d,(mcs %d, TBS %d, nb_rb %d),header_length %d\n",
                  module_idP, 
                  frameP, 
                  UE_id, 
                  CC_id,
                  sdu_length_total, 
                  num_sdus, 
                  sdu_lengths[0],
                  sdu_lcids[0], 
                  offset, 
                  ta_update, 
                  padding,
                  post_padding, 
                  mcs, 
                  TBS, 
                  nb_rb,
                  header_length_total);
          }

          //#endif
#ifdef DEBUG_eNB_SCHEDULER
          LOG_T(MAC, "[eNB %d] First 16 bytes of DLSCH : \n");
          for (i = 0; i < 16; i++) {
            LOG_T(MAC, "%x.", 
                  dlsch_buffer[i]);
          }
          LOG_T(MAC, "\n");
#endif
          // cycle through SDUs and place in dlsch_buffer
          dlsch_pdu = &UE_list->DLSCH_pdu[CC_id][0][UE_id];
          memcpy(&dlsch_pdu->payload[0][offset], 
                 dlsch_buffer, 
                 sdu_length_total);
          // memcpy(RC.mac[0].DLSCH_pdu[0][0].payload[0][offset],dcch_buffer,sdu_lengths[0]);

          // fill remainder of DLSCH with 0
          for (j = 0; j < (TBS - sdu_length_total - offset); j++) {
            dlsch_pdu->payload[0][offset + sdu_length_total + j] = 0;
          }

          if (opt_enabled == 1) {
            trace_pdu(DIRECTION_DOWNLINK,
                      (uint8_t *) dlsch_pdu->payload[0],
                      TBS, 
                      module_idP, 
                      WS_C_RNTI,
                      UE_RNTI(module_idP, 
                              UE_id), 
                      eNB->frame,
                      eNB->subframe, 
                      0, 
                      0);
            LOG_D(OPT, "[eNB %d][DLSCH] CC_id %d Frame %d  rnti %x  with size %d\n",
                  module_idP, 
                  CC_id, 
                  frameP,
                  UE_RNTI(module_idP, 
                          UE_id), 
                  TBS);
          }

          T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, 
            T_INT(module_idP),
            T_INT(CC_id), 
            T_INT(rnti), 
            T_INT(frameP),
            T_INT(subframeP), 
            T_INT(harq_pid),
            T_BUFFER(dlsch_pdu->payload[0], 
                     TBS));
          ue_template->nb_rb[harq_pid] = nb_rb;
          add_ue_dlsch_info(module_idP, 
                            CC_id, 
                            UE_id, 
                            subframeP, 
                            S_DL_SCHEDULED, 
                            rnti);
          // store stats
          eNB->eNB_stats[CC_id].dlsch_bytes_tx += sdu_length_total;
          eNB->eNB_stats[CC_id].dlsch_pdus_tx += 1;
          eNB_UE_stats->rbs_used = nb_rb;
          eNB_UE_stats->num_mac_sdu_tx = num_sdus;
          eNB_UE_stats->total_rbs_used += nb_rb;
          eNB_UE_stats->dlsch_mcs2 = mcs;
          eNB_UE_stats->TBS = TBS;
          eNB_UE_stats->overhead_bytes = TBS - sdu_length_total;
          eNB_UE_stats->total_sdu_bytes += sdu_length_total;
          eNB_UE_stats->total_pdu_bytes += TBS;
          eNB_UE_stats->total_num_pdus += 1;

          if (cc[CC_id].tdd_Config != NULL) { // TDD
            ue_template->DAI++;
            update_ul_dci(module_idP, 
                          CC_id, 
                          rnti,
                          ue_template->DAI,
                          subframeP);
          }

          // do PUCCH power control
          // this is the normalized RX power
          // unit is not dBm, it's special from nfapi 
          // converting to dBm: ToDo: Noise power hard coded to 30
          normalized_rx_power = (((5 * ue_sched_ctrl->pucch1_snr[CC_id]) - 640) / 10) + 30;
          target_rx_power= (eNB->puCch10xSnr / 10) + 30;
          // 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_template->pucch_tpc_tx_frame * 10 + ue_template->pucch_tpc_tx_subframe;

          if (framex10psubframe + 10 <= (frameP * 10) + subframeP ||  //normal case
              (framex10psubframe > (frameP * 10) + subframeP && 10240 - framex10psubframe + (frameP * 10) + subframeP >= 10)) //frame wrap-around
            if (ue_sched_ctrl->pucch1_cqi_update[CC_id] == 1) {
              ue_sched_ctrl->pucch1_cqi_update[CC_id] = 0;
              ue_template->pucch_tpc_tx_frame = frameP;
              ue_template->pucch_tpc_tx_subframe = subframeP;

              if (normalized_rx_power > (target_rx_power + 4)) {
                tpc = 0;  //-1
              } else if (normalized_rx_power < (target_rx_power - 4)) {
                tpc = 2;  //+1
              } else {
                tpc = 1;  //0
              }

              LOG_D(MAC, "[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, normalized/target rx power %d/%d\n",
                    module_idP, 
                    frameP, 
                    subframeP, 
                    harq_pid, 
                    tpc,
                    normalized_rx_power, 
                    target_rx_power);
            } // Po_PUCCH has been updated
            else {
              tpc = 1;  //0
            } // time to do TPC update
          else {
            tpc = 1;  //0
          }

          dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu];
          memset((void *) dl_config_pdu, 
                 0, 
                 sizeof(nfapi_dl_config_request_pdu_t));
          dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE;
          dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu));
          dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1;
          dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level =
            get_aggregation(get_bw_index(module_idP, 
                                        CC_id), 
                            ue_sched_ctrl->dl_cqi[CC_id], 
                            format1);
          dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG;
          dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti;
          dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1;    // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications
          dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000;    // equal to RS power
          dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process = harq_pid;
          dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc = tpc;    // dont adjust power when retransmitting
          dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = 1 - ue_template->oldNDI[harq_pid];
          dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = mcs;
          dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = 0;
          //deactivate second codeword
          dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_2 = 0;
          dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_2 = 1;

          if (cc[CC_id].tdd_Config != NULL) {    //TDD
            dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.downlink_assignment_index = (ue_template->DAI - 1) & 3;
            LOG_D(MAC, "[eNB %d] Initial transmission CC_id %d : harq_pid %d, dai %d, mcs %d\n",
                  module_idP, 
                  CC_id, 
                  harq_pid,
                  (ue_template->DAI - 1),
                  mcs);
          } else {
            LOG_D(MAC, "[eNB %d] Initial transmission CC_id %d : harq_pid %d, mcs %d\n",
                  module_idP, 
                  CC_id, 
                  harq_pid, 
                  mcs);
          }

          LOG_D(MAC, "Checking feasibility pdu %d (new sdu)\n",
                dl_req->number_pdu);

          if (!CCE_allocation_infeasible(module_idP, 
                                         CC_id, 
                                         1, 
                                         subframeP,
                                         dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, 
                                         rnti)) {
            ue_sched_ctrl->round[CC_id][harq_pid] = 0;
            dl_req->number_dci++;
            dl_req->number_pdu++;
            dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG;
            eNB->DL_req[CC_id].sfn_sf = frameP << 4 | subframeP;
            eNB->DL_req[CC_id].header.message_id = NFAPI_DL_CONFIG_REQUEST;
            // Toggle NDI for next time
            LOG_D(MAC, "CC_id %d Frame %d, subframeP %d: Toggling Format1 NDI for UE %d (rnti %x/%d) oldNDI %d\n",
                  CC_id, 
                  frameP, 
                  subframeP, 
                  UE_id, 
                  rnti, 
                  harq_pid,
                  ue_template->oldNDI[harq_pid]);
            ue_template->oldNDI[harq_pid] = 1 - ue_template->oldNDI[harq_pid];
            ue_template->oldmcs1[harq_pid] = mcs;
            ue_template->oldmcs2[harq_pid] = 0;
            AssertFatal(ue_template->physicalConfigDedicated != NULL, "physicalConfigDedicated is NULL\n");
            AssertFatal(ue_template->physicalConfigDedicated->pdsch_ConfigDedicated != NULL,
                        "physicalConfigDedicated->pdsch_ConfigDedicated is NULL\n");
            fill_nfapi_dlsch_config(eNB, 
                                    dl_req, 
                                    TBS, 
                                    eNB->pdu_index[CC_id], 
                                    rnti, 
                                    0, // type 0 allocation from 7.1.6 in 36.213
                                    0,  // virtual_resource_block_assignment_flag, unused here
                                    0,  // resource_block_coding, to be filled in later
                                    getQm(mcs), 
                                    0,  // redundancy version
                                    1,  // transport blocks
                                    0,  // transport block to codeword swap flag
                                    cc[CC_id].p_eNB == 1 ? 0 : 1, // transmission_scheme
                                    1,  // number of layers
                                    1,  // number of subbands
                                    //                       uint8_t codebook_index,
                                    4,  // UE category capacity
                                    ue_template->physicalConfigDedicated->pdsch_ConfigDedicated->p_a, 
                                    0,  // delta_power_offset for TM5
                                    0,  // ngap
                                    0,  // nprb
                                    cc[CC_id].p_eNB == 1 ? 1 : 2, // transmission mode
                                    0,  //number of PRBs treated as one subband, not used here
                                    0); // number of beamforming vectors, not used here
                                    
            eNB->TX_req[CC_id].sfn_sf = fill_nfapi_tx_req(&eNB->TX_req[CC_id].tx_request_body,
                                                          (frameP * 10) + subframeP,
                                                          TBS, 
                                                          eNB->pdu_index[CC_id],
                                                          dlsch_pdu->payload[0]);
            LOG_D(MAC, "Filled NFAPI configuration for DCI/DLSCH/TXREQ %d, new SDU\n",
                  eNB->pdu_index[CC_id]);
            eNB->pdu_index[CC_id]++;
            program_dlsch_acknak(module_idP, 
                                 CC_id, 
                                 UE_id,
                                 frameP, 
                                 subframeP,
                                 dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.cce_idx);
          } else {
            LOG_W(MAC, "Frame %d, Subframe %d: Dropping DLSCH allocation for UE %d/%x, infeasible CCE allocations\n",
                  frameP, 
                  subframeP, 
                  UE_id, 
                  rnti);
          }
        } else {  // There is no data from RLC or MAC header, so don't schedule
        }
      }

      if (cc[CC_id].tdd_Config != NULL) {    // TDD
        set_ul_DAI(module_idP, 
                   UE_id, 
                   CC_id, 
                   frameP, 
                   subframeP);
      }
    }     // UE_id loop
  }       // CC_id loop

  fill_DLSCH_dci(module_idP, 
                 frameP, 
                 subframeP, 
                 mbsfn_flag);
  stop_meas(&eNB->schedule_dlsch);
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH, 
                                          VCD_FUNCTION_OUT);
}

//------------------------------------------------------------------------------
void 
dlsch_scheduler_interslice_multiplexing(module_id_t Mod_id,
                                        int frameP,
                                        sub_frame_t subframeP,
                                        uint8_t rballoc_sub[NFAPI_CC_MAX][N_RBG_MAX])
//------------------------------------------------------------------------------
{
  // FIXME: I'm prototyping the algorithm, so there may be arrays and variables that carry redundant information here and in pre_processor_results struct.
  int UE_id, CC_id, rbg, i;
  int N_RB_DL, min_rb_unit, tm;
  int owned, used;
  eNB_MAC_INST *eNB = RC.mac[Mod_id];
  int nb_mac_CC = RC.nb_mac_CC[Mod_id];
  UE_list_t *UE_list = &eNB->UE_list;
  slice_info_t *sli = &eNB->slice_info;
  UE_sched_ctrl *ue_sched_ctl;
  COMMON_channels_t *cc;
  int N_RBG[NFAPI_CC_MAX];
  int slice_sorted_list[MAX_NUM_SLICES];
  int slice_idx;
  int8_t free_rbgs_map[NFAPI_CC_MAX][N_RBG_MAX];
  int has_traffic[NFAPI_CC_MAX][MAX_NUM_SLICES];
  uint8_t allocation_mask[NFAPI_CC_MAX][N_RBG_MAX];
  uint16_t (*nb_rbs_remaining)[MAX_MOBILES_PER_ENB];
  uint16_t (*nb_rbs_required)[MAX_MOBILES_PER_ENB];
  uint8_t  (*MIMO_mode_indicator)[N_RBG_MAX];
   
  // Initialize the free RBGs map
  // free_rbgs_map[CC_id][rbg] = -1 if RBG is allocated,
  // otherwise it contains the id of the slice it belongs to.
  // (Information about slicing must be retained to deal with isolation).
  // FIXME: This method does not consider RBGs that are free and belong to no slices
  for (CC_id = 0; CC_id < nb_mac_CC; CC_id++) {
    cc = &eNB->common_channels[CC_id];
    N_RBG[CC_id] = to_rbg(cc->mib->message.dl_Bandwidth);

    for (rbg = 0; rbg < N_RBG[CC_id]; rbg++) {
      for (i = 0; i < sli->n_dl; ++i) {
        owned = sli->pre_processor_results[i].slice_allocation_mask[CC_id][rbg];

        if (owned) {
          used = rballoc_sub[CC_id][rbg];
          free_rbgs_map[CC_id][rbg] = used ? -1 : i;
          break;
        }
      }
    }
  }

  // Find out which slices need other resources.
  // FIXME: I don't think is really needed since we check nb_rbs_remaining later
  for (CC_id = 0; CC_id < nb_mac_CC; CC_id++) {
    for (i = 0; i < sli->n_dl; i++) {
      has_traffic[CC_id][i] = 0;

      for (UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) {
        if (sli->pre_processor_results[i].nb_rbs_remaining[CC_id][UE_id] > 0) {
          has_traffic[CC_id][i] = 1;
          break;
        }
      }
    }
  }

  slice_priority_sort(Mod_id, 
                      slice_sorted_list);

  // MULTIPLEXING
  // This part is an adaptation of dlsch_scheduler_pre_processor_allocate() code
  for (CC_id = 0; CC_id < nb_mac_CC; ++CC_id) {
    N_RB_DL = to_prb(eNB->common_channels[CC_id].mib->message.dl_Bandwidth);
    min_rb_unit = get_min_rb_unit(Mod_id, 
                                  CC_id);

    for (i = 0; i < sli->n_dl; ++i) {
      slice_idx = slice_sorted_list[i];

      if (has_traffic[CC_id][slice_idx] == 0) continue;

      // Build an ad-hoc allocation mask fo the slice
      for (rbg = 0; rbg < N_RBG[CC_id]; ++rbg) {
        if (free_rbgs_map[CC_id][rbg] == -1) {
          // RBG is already allocated
          allocation_mask[CC_id][rbg] = 0;
          continue;
        }

        if (sli->dl[free_rbgs_map[CC_id][rbg]].isol == 1) {
          // RBG belongs to an isolated slice
          allocation_mask[CC_id][rbg] = 0;
          continue;
        }

        // RBG is free
        allocation_mask[CC_id][rbg] = 1;
      }

      // Sort UE again
      // (UE list gets sorted every time pre_processor is called so it is probably dirty at this point)
      // FIXME: There is only one UE_list for all slices, so it must be sorted again each time we use it
      sort_UEs(Mod_id, 
               slice_idx, 
               frameP, 
               subframeP);
      nb_rbs_remaining = sli->pre_processor_results[slice_idx].nb_rbs_remaining;
      nb_rbs_required = sli->pre_processor_results[slice_idx].nb_rbs_required;
      MIMO_mode_indicator = sli->pre_processor_results[slice_idx].MIMO_mode_indicator;

      // Allocation
      for (UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) {
        ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
        tm = get_tmode(Mod_id, 
                       CC_id, 
                       UE_id);

        for (rbg = 0; rbg < N_RBG[CC_id]; ++rbg) {
          // FIXME: I think that some of these checks are redundant
          if (allocation_mask[CC_id][rbg] == 0) continue;

          if (rballoc_sub[CC_id][rbg] != 0) continue;

          if (ue_sched_ctl->rballoc_sub_UE[CC_id][rbg] != 0) continue;

          if (nb_rbs_remaining[CC_id][UE_id] <= 0) continue;

          if (ue_sched_ctl->pre_nb_available_rbs[CC_id] >= nb_rbs_required[CC_id][UE_id]) continue;

          if (ue_sched_ctl->dl_pow_off[CC_id] == 0) continue;

          if ((rbg == N_RBG[CC_id] - 1) && ((N_RB_DL == 25) || (N_RB_DL == 50))) {
            // Allocating last, smaller RBG
            if (nb_rbs_remaining[CC_id][UE_id] >= min_rb_unit - 1) {
              rballoc_sub[CC_id][rbg] = 1;
              free_rbgs_map[CC_id][rbg] = -1;
              ue_sched_ctl->rballoc_sub_UE[CC_id][rbg] = 1;
              MIMO_mode_indicator[CC_id][rbg] = 1;

              if (tm == 5) {
                ue_sched_ctl->dl_pow_off[CC_id] = 1;
              }

              nb_rbs_remaining[CC_id][UE_id] -= (min_rb_unit - 1);
              ue_sched_ctl->pre_nb_available_rbs[CC_id] += (min_rb_unit - 1);
            }
          } else {
            // Allocating a standard-sized RBG
            if (nb_rbs_remaining[CC_id][UE_id] >= min_rb_unit) {
              rballoc_sub[CC_id][rbg] = 1;
              free_rbgs_map[CC_id][rbg] = -1;
              ue_sched_ctl->rballoc_sub_UE[CC_id][rbg] = 1;
              MIMO_mode_indicator[CC_id][rbg] = 1;

              if (tm == 5) {
                ue_sched_ctl->dl_pow_off[CC_id] = 1;
              }

              nb_rbs_remaining[CC_id][UE_id] -= min_rb_unit;
              ue_sched_ctl->pre_nb_available_rbs[CC_id] += min_rb_unit;
            }
          }
        }
      }
    }
  }
  return;
}

//------------------------------------------------------------------------------
void dlsch_scheduler_qos_multiplexing(module_id_t Mod_id, int frameP, sub_frame_t subframeP)
//------------------------------------------------------------------------------
{
  // int UE_id; 
  int CC_id, i;
  // UE_list_t *UE_list = &RC.mac[Mod_id]->UE_list;
  slice_info_t *sli = &RC.mac[Mod_id]->slice_info;
  //UE_sched_ctrl *ue_sched_ctl;

  for (CC_id = 0; CC_id < RC.nb_mac_CC[Mod_id]; CC_id++) {
    for (i = 0; i < sli->n_dl; i++) {
      // Sort UE again
      // FIXME: There is only one UE_list for all slices, so it must be sorted again each time we use it
      sort_UEs(Mod_id, 
               (uint8_t)i, 
               frameP, 
               subframeP);
      /*
      for (UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) {
        //ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
        // TODO: Do something here
        // ue_sched_ctl->pre_nb_available_rbs[CC_id];
      }
      */
    }
  }
}


#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
//------------------------------------------------------------------------------
void
schedule_ue_spec_br(
		    module_id_t   module_idP,
		    frame_t       frameP,
		    sub_frame_t   subframeP
		    ) {
  int CC_id = 0,UE_id;
  eNB_MAC_INST                        *mac = RC.mac[module_idP];
  COMMON_channels_t                    *cc = mac->common_channels;
  UE_list_t                      *UE_list  = &mac->UE_list;
  UE_TEMPLATE       *UE_template;
  UE_sched_ctrl     *ue_sched_ctl;
  int32_t                        tpc=1;
  int rvseq[4] = {0,2,3,1};
  mac_rlc_status_resp_t          rlc_status;
  unsigned char                  header_len_dcch=0, header_len_dcch_tmp=0; 
  unsigned char                  header_len_dtch=0, header_len_dtch_tmp=0, header_len_dtch_last=0; 
  unsigned char                  ta_len=0;
  unsigned char                  sdu_lcids[NB_RB_MAX],lcid,offset,num_sdus=0;
  uint16_t                       TBS,j,sdu_lengths[NB_RB_MAX],rnti,padding=0,post_padding=0;
  unsigned char                  dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES];
  int round;
  int                            ta_update;
  uint16_t                       sdu_length_total = 0;
  int                            mcs;
  int32_t                        normalized_rx_power, target_rx_power;

  nfapi_dl_config_request_pdu_t *dl_config_pdu;
  nfapi_ul_config_request_pdu_t *ul_config_pdu;
  nfapi_tx_request_pdu_t *TX_req;
  nfapi_dl_config_request_body_t *dl_req;
  nfapi_ul_config_request_body_t *ul_req;

  struct LTE_PRACH_ConfigSIB_v1310 *ext4_prach;
  struct LTE_PUCCH_ConfigCommon_v1310 *ext4_pucch;
  LTE_PRACH_ParametersListCE_r13_t *prach_ParametersListCE_r13;
  struct LTE_N1PUCCH_AN_InfoList_r13 *pucch_N1PUCCH_AN_InfoList_r13;
  int             pucchreps[4] = { 1, 1, 1, 1 };
  int             n1pucchan[4] = { 0, 0, 0, 0 }; 
  uint32_t        ackNAK_absSF;
  int             first_rb;

  dl_req = &mac->DL_req[CC_id].dl_config_request_body;
  dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu];

  if ((frameP&1) == 0) return;

  if (cc[CC_id].mib->message.schedulingInfoSIB1_BR_r13 ==0) return;

  if (cc[CC_id].radioResourceConfigCommon_BR) {

    ext4_prach = cc[CC_id].radioResourceConfigCommon_BR->ext4->prach_ConfigCommon_v1310;
    ext4_pucch = cc[CC_id].radioResourceConfigCommon_BR->ext4->pucch_ConfigCommon_v1310;
    prach_ParametersListCE_r13 = &ext4_prach->prach_ParametersListCE_r13;
    pucch_N1PUCCH_AN_InfoList_r13 = ext4_pucch->n1PUCCH_AN_InfoList_r13;
    AssertFatal (prach_ParametersListCE_r13 != NULL, "prach_ParametersListCE_r13 is null\n");
    AssertFatal (pucch_N1PUCCH_AN_InfoList_r13 != NULL, "pucch_N1PUCCH_AN_InfoList_r13 is null\n");
    // check to verify CE-Level compatibility in SIB2_BR
    AssertFatal (prach_ParametersListCE_r13->list.count == pucch_N1PUCCH_AN_InfoList_r13->list.count, "prach_ParametersListCE_r13->list.count!= pucch_N1PUCCH_AN_InfoList_r13->list.count\n");

    switch (prach_ParametersListCE_r13->list.count) {
    case 4:
      n1pucchan[3] = *pucch_N1PUCCH_AN_InfoList_r13->list.array[3];
      AssertFatal (ext4_pucch->pucch_NumRepetitionCE_Msg4_Level3_r13 != NULL, "pucch_NumRepetitionCE_Msg4_Level3 shouldn't be NULL\n");
      pucchreps[3] = (int) (4 << *ext4_pucch->pucch_NumRepetitionCE_Msg4_Level3_r13);

    case 3:
      n1pucchan[2] = *pucch_N1PUCCH_AN_InfoList_r13->list.array[2];
      AssertFatal (ext4_pucch->pucch_NumRepetitionCE_Msg4_Level2_r13 != NULL, "pucch_NumRepetitionCE_Msg4_Level2 shouldn't be NULL\n");
      pucchreps[2] = (int) (4 << *ext4_pucch->pucch_NumRepetitionCE_Msg4_Level2_r13);
    case 2:
      n1pucchan[1] = *pucch_N1PUCCH_AN_InfoList_r13->list.array[1];
      AssertFatal (ext4_pucch->pucch_NumRepetitionCE_Msg4_Level1_r13 != NULL, "pucch_NumRepetitionCE_Msg4_Level1 shouldn't be NULL\n");
      pucchreps[1] = (int) (1 << *ext4_pucch->pucch_NumRepetitionCE_Msg4_Level1_r13);
    case 1:
      n1pucchan[0] = *pucch_N1PUCCH_AN_InfoList_r13->list.array[0];
      AssertFatal (ext4_pucch->pucch_NumRepetitionCE_Msg4_Level0_r13 != NULL, "pucch_NumRepetitionCE_Msg4_Level0 shouldn't be NULL\n");
      pucchreps[0] = (int) (1 << *ext4_pucch->pucch_NumRepetitionCE_Msg4_Level0_r13);
      break;
    default:
      AssertFatal (1 == 0, "Illegal count for prach_ParametersListCE_r13 %d\n", prach_ParametersListCE_r13->list.count);
    }
  }

  for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) {

    int harq_pid = 0;

    rnti = UE_RNTI(module_idP,UE_id);
    if (rnti==NOT_A_RNTI)  continue;

    ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
    UE_template  = &UE_list->UE_template[CC_id][UE_id];

    if (UE_template->rach_resource_type == 0) continue;
    uint8_t rrc_status = mac_eNB_get_rrc_status(module_idP, rnti);

    if (rrc_status < RRC_CONNECTED) continue;

    round = ue_sched_ctl->round[CC_id][harq_pid];

    AssertFatal (UE_template->physicalConfigDedicated != NULL, 
		 "UE_template->physicalConfigDedicated is null\n");
    AssertFatal (UE_template->physicalConfigDedicated->ext4 != NULL, 
		 "UE_template->physicalConfigDedicated->ext4 is null\n");
    AssertFatal (UE_template->physicalConfigDedicated->ext4->epdcch_Config_r11 != NULL, 
		 "UE_template->physicalConfigDedicated->ext4->epdcch_Config_r11 is null\n");
    AssertFatal (UE_template->physicalConfigDedicated->ext4->epdcch_Config_r11->config_r11.present == LTE_EPDCCH_Config_r11__config_r11_PR_setup, 
		 "UE_template->physicalConfigDedicated->ext4->epdcch_Config_r11->config_r11.present != setup\n");
    AssertFatal (UE_template->physicalConfigDedicated->ext4->epdcch_Config_r11->config_r11.choice.setup.setConfigToAddModList_r11 != NULL,
		 "UE_template->physicalConfigDedicated->ext4->epdcch_Config_r11->config_r11.choice.setup.setConfigToAddModList_r11 = NULL\n");

    LTE_EPDCCH_SetConfig_r11_t *epdcch_setconfig_r11 = UE_template->physicalConfigDedicated->ext4->epdcch_Config_r11->config_r11.choice.setup.setConfigToAddModList_r11->list.array[0];

    AssertFatal(epdcch_setconfig_r11 != NULL, "epdcch_setconfig_r11 is null\n");
    AssertFatal(epdcch_setconfig_r11->ext2!=NULL, "epdcch_setconfig_r11->ext2 is null\n");
    AssertFatal(epdcch_setconfig_r11->ext2->mpdcch_config_r13!=NULL,
		"epdcch_setconfig_r11->ext2->mpdcch_config_r13 is null");
    AssertFatal(epdcch_setconfig_r11->ext2->mpdcch_config_r13!=NULL,
		"epdcch_setconfig_r11->ext2->mpdcch_config_r13 is null");
    AssertFatal(epdcch_setconfig_r11->ext2->mpdcch_config_r13->present==LTE_EPDCCH_SetConfig_r11__ext2__mpdcch_config_r13_PR_setup, 
		"epdcch_setconfig_r11->ext2->mpdcch_config_r13->present is not setup\n");
    AssertFatal(epdcch_setconfig_r11->ext2->numberPRB_Pairs_v1310!=NULL,
		"epdcch_setconfig_r11->ext2->numberPRB_Pairs_v1310 is null");
    AssertFatal(epdcch_setconfig_r11->ext2->numberPRB_Pairs_v1310->present==LTE_EPDCCH_SetConfig_r11__ext2__numberPRB_Pairs_v1310_PR_setup, 
		"epdcch_setconfig_r11->ext2->numberPRB_Pairs_v1310->present is not setup\n");
           

    // simple scheduler for 1 repetition, 1 HARQ
    if (subframeP == 5) { // MPDCCH

      if (round == 8) {
        rlc_status.bytes_in_buffer = 0;
        // Now check RLC information to compute number of required RBs
        // get maximum TBS size for RLC request
        TBS = get_TBS_DL(9,6);
        // check first for RLC data on DCCH
        // add the length for  all the control elements (timing adv, drx, etc) : header + payload

        if (ue_sched_ctl->ta_timer == 0) {
          ta_update = ue_sched_ctl->ta_update;
          /* if we send TA then set timer to not send it for a while */
          if (ta_update != 31)
            ue_sched_ctl->ta_timer = 20;
          /* reset ta_update */
          ue_sched_ctl->ta_update = 31;
        } else {
          ta_update = 31;
        }

        ta_len = (ta_update != 31) ? 2 : 0;

        header_len_dcch = 2; // 2 bytes DCCH SDU subheader

        if ( TBS-ta_len-header_len_dcch > 0 ) {
	  LOG_I(MAC,"Calling mac_rlc_status_ind for DCCH\n");
          rlc_status = mac_rlc_status_ind(
					  module_idP,
					  rnti,
					  module_idP,
					  frameP,
					  subframeP,
					  ENB_FLAG_YES,
					  MBMS_FLAG_NO,
					  DCCH,
					  (TBS-ta_len-header_len_dcch)
					  ,0, 0
					  ); // transport block set size

          sdu_lengths[0]=0;

          if (rlc_status.bytes_in_buffer > 0) {  // There is DCCH to transmit
            LOG_I(MAC,"[eNB %d] Frame %d, DL-DCCH->DLSCH CC_id %d, Requesting %d bytes from RLC (RRC message)\n",
                  module_idP,frameP,CC_id,TBS-header_len_dcch);
            sdu_lengths[0] = mac_rlc_data_req(
					      module_idP,
					      rnti,
					      module_idP,
					      frameP,
					      ENB_FLAG_YES,
					      MBMS_FLAG_NO,
					      DCCH,
					      TBS, //not used
					      (char *)&dlsch_buffer[0]
					      ,0, 0
);

            T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP),
              T_INT(harq_pid), T_INT(DCCH), T_INT(sdu_lengths[0]));

            LOG_I(MAC,"[eNB %d][DCCH] CC_id %d Got %d bytes from RLC\n",module_idP,CC_id,sdu_lengths[0]);
            sdu_length_total = sdu_lengths[0];
            sdu_lcids[0] = DCCH;
            UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[DCCH]+=1;
            UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH]+=sdu_lengths[0];
            num_sdus = 1;
          } else {
            header_len_dcch = 0;
            sdu_length_total = 0;
          }
        }
	
        // check for DCCH1 and update header information (assume 2 byte sub-header)
        if (TBS-ta_len-header_len_dcch-sdu_length_total > 0 ) {
          rlc_status = mac_rlc_status_ind(
					  module_idP,
					  rnti,
					  module_idP,
					  frameP,
					  subframeP,
					  ENB_FLAG_YES,
					  MBMS_FLAG_NO,
					  DCCH+1,
					  (TBS-ta_len-header_len_dcch-sdu_length_total)
					  ,0, 0); // transport block set size less allocations for timing advance and
          // DCCH SDU
	  sdu_lengths[num_sdus] = 0;
	  
          if (rlc_status.bytes_in_buffer > 0) {
            LOG_I(MAC,"[eNB %d], Frame %d, DCCH1->DLSCH, CC_id %d, Requesting %d bytes from RLC (RRC message)\n",
                  module_idP,frameP,CC_id,TBS-header_len_dcch-sdu_length_total);
            sdu_lengths[num_sdus] += mac_rlc_data_req(
						      module_idP,
						      rnti,
						      module_idP,
						      frameP,
						      ENB_FLAG_YES,
						      MBMS_FLAG_NO,
						      DCCH+1,
						      TBS, //not used
						      (char *)&dlsch_buffer[sdu_length_total]
						      ,0, 0
						      );
	    
            T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP),
              T_INT(harq_pid), T_INT(DCCH+1), T_INT(sdu_lengths[num_sdus]));

            sdu_lcids[num_sdus] = DCCH1;
            sdu_length_total += sdu_lengths[num_sdus];
            header_len_dcch += 2;
            UE_list->eNB_UE_stats[CC_id][UE_id].num_pdu_tx[DCCH1]+=1;
            UE_list->eNB_UE_stats[CC_id][UE_id].num_bytes_tx[DCCH1]+=sdu_lengths[num_sdus];
	    num_sdus++;
	  }
        }

	// assume the max dtch header size, and adjust it later
	header_len_dtch=0;
	header_len_dtch_last=0; // the header length of the last mac sdu
	// lcid has to be sorted before the actual allocation (similar struct as ue_list).
	for (lcid=NB_RB_MAX-1; lcid>=DTCH ; lcid--){
	  // TBD: check if the lcid is active
	  
	  header_len_dtch+=3; 
	  header_len_dtch_last=3;
	  LOG_D(MAC,"[eNB %d], Frame %d, DTCH%d->DLSCH, Checking RLC status (tbs %d, len %d)\n",
		module_idP,frameP,lcid,TBS,
		TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch);
	  
	  if (TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch > 0 ) { // NN: > 2 ? 
	    rlc_status = mac_rlc_status_ind(module_idP,
					    rnti,
					    module_idP,
					    frameP,
					    subframeP,
					    ENB_FLAG_YES,
					    MBMS_FLAG_NO,
					    lcid,
					    TBS-ta_len-header_len_dcch-sdu_length_total-header_len_dtch
					    ,0, 0);
	    

	    if (rlc_status.bytes_in_buffer > 0) {
	      
	      LOG_I(MAC,"[eNB %d][USER-PLANE DEFAULT DRB] Frame %d : DTCH->DLSCH, Requesting %d bytes from RLC (lcid %d total hdr len %d)\n",
		    module_idP,frameP,TBS-header_len_dcch-sdu_length_total-header_len_dtch,lcid, header_len_dtch);
	      sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP,
						       rnti,
						       module_idP,
						       frameP,
						       ENB_FLAG_YES,
						       MBMS_FLAG_NO,
						       lcid,
						       TBS,	//not used
						       (char*)&dlsch_buffer[sdu_length_total]
						       ,0, 0);
	      T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP),
              T_INT(harq_pid), T_INT(lcid), T_INT(sdu_lengths[num_sdus]));

	      LOG_I(MAC,"[eNB %d][USER-PLANE DEFAULT DRB] Got %d bytes for DTCH %d \n",module_idP,sdu_lengths[num_sdus],lcid);
	      sdu_lcids[num_sdus] = lcid;
	      sdu_length_total += sdu_lengths[num_sdus];

	      if (sdu_lengths[num_sdus] < 128) {
		header_len_dtch--;
		header_len_dtch_last--;
	      }
	      num_sdus++;
	    } // no data for this LCID
	    else {
	      header_len_dtch-=3;
	    }
	  } // no TBS left
	  else {
	    header_len_dtch-=3;
	    break; 
	  }
	}
	if (header_len_dtch == 0 )
	  header_len_dtch_last= 0;
	// there is at least one SDU 
	// if (num_sdus > 0 ){
	if ((sdu_length_total + header_len_dcch + header_len_dtch )> 0) {
	  
	  // Now compute number of required RBs for total sdu length
	  // Assume RAH format 2
	  // adjust  header lengths
	  header_len_dcch_tmp = header_len_dcch;
	  header_len_dtch_tmp = header_len_dtch;
	  if (header_len_dtch==0) {
	    header_len_dcch = (header_len_dcch >0) ? 1 : 0;//header_len_dcch;  // remove length field
	  } else {
	    header_len_dtch_last-=1; // now use it to find how many bytes has to be removed for the last MAC SDU 
	    header_len_dtch = (header_len_dtch > 0) ? header_len_dtch - header_len_dtch_last  :header_len_dtch;     // remove length field for the last SDU
	  }

          mcs = 9;

          // decrease mcs until TBS falls below required length
          while ((TBS > (sdu_length_total + header_len_dcch + header_len_dtch + ta_len)) && (mcs>0)) {
            mcs--;
            TBS = get_TBS_DL(mcs,6);
          }

          // 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)) {
            mcs++;
            TBS = get_TBS_DL(mcs,6);
          }

	  //#ifdef DEBUG_eNB_SCHEDULER
          LOG_I(MAC,"[eNB %d] CC_id %d Generated DLSCH header (mcs %d, TBS %d, nb_rb %d)\n",
                module_idP,CC_id,mcs,TBS,6);
          // msg("[MAC][eNB ] Reminder of DLSCH with random data %d %d %d %d \n",
          //  TBS, sdu_length_total, offset, TBS-sdu_length_total-offset);


          if ((TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len) <= 2) {
            padding = (TBS - header_len_dcch - header_len_dtch - sdu_length_total - ta_len);
            post_padding = 0;
          } else {
            padding = 0;

            // adjust the header len
            if (header_len_dtch==0) {
              header_len_dcch = header_len_dcch_tmp;
            } else { //if (( header_len_dcch==0)&&((header_len_dtch==1)||(header_len_dtch==2)))
              header_len_dtch = header_len_dtch_tmp;
            }

            post_padding = TBS - sdu_length_total - header_len_dcch - header_len_dtch - ta_len ; // 1 is for the postpadding header
          }


          offset = generate_dlsch_header((unsigned char*)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0],
                                         num_sdus,              //num_sdus
                                         sdu_lengths,  //
                                         sdu_lcids,
                                         255,                                   // no drx
                                         ta_update, // timing advance
                                         NULL,                                  // contention res id
                                         padding,
                                         post_padding);


          if (ta_update != 31) {
            LOG_D(MAC,
                  "[eNB %d][DLSCH] Frame %d Generate header for UE_id %d on CC_id %d: sdu_length_total %d, num_sdus %d, sdu_lengths[0] %d, sdu_lcids[0] %d => payload offset %d,timing advance value : %d, padding %d,post_padding %d,(mcs %d, TBS %d, nb_rb %d),header_dcch %d, header_dtch %d\n",
                  module_idP,frameP, UE_id, CC_id, sdu_length_total,num_sdus,sdu_lengths[0],sdu_lcids[0],offset,
                  ta_update,padding,post_padding,mcs,TBS,6,header_len_dcch,header_len_dtch);
	  }



          // cycle through SDUs and place in dlsch_buffer
          memcpy(&UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset],dlsch_buffer,sdu_length_total);
          // memcpy(RC.mac[0].DLSCH_pdu[0][0].payload[0][offset],dcch_buffer,sdu_lengths[0]);

          // fill remainder of DLSCH with random data
          for (j=0; j<(TBS-sdu_length_total-offset); j++) {
            UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0][offset+sdu_length_total+j] = (char)(taus()&0xff);
          }


          if (opt_enabled == 1) {
            trace_pdu(1, (uint8_t *)UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0],
                      TBS, module_idP, 3, UE_RNTI(module_idP,UE_id),
                      mac->frame, mac->subframe,0,0);
            LOG_D(OPT,"[eNB %d][DLSCH] CC_id %d Frame %d  rnti %x  with size %d\n",
                  module_idP, CC_id, frameP, UE_RNTI(module_idP,UE_id), TBS);
          }

          T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP),
            T_INT(harq_pid), T_BUFFER(UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], TBS));

	  // do PUCCH power control
          // this is the normalized RX power

          /* TODO: fix how we deal with power, unit is not dBm, it's special from nfapi */
	  normalized_rx_power = (5*ue_sched_ctl->pucch1_snr[CC_id]-640)/10+30;
	  target_rx_power = mac->puCch10xSnr/10+30;
	    
          // this assumes accumulated tpc
	  // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out
	  int32_t framex10psubframe = UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame*10+UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe;
          if (((framex10psubframe+10)<=(frameP*10+subframeP)) || //normal case
	      ((framex10psubframe>(frameP*10+subframeP)) && (((10240-framex10psubframe+frameP*10+subframeP)>=10)))) //frame wrap-around
	    if (ue_sched_ctl->pucch1_cqi_update[CC_id] == 1) { 
	      ue_sched_ctl->pucch1_cqi_update[CC_id] = 0;

	      UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame=frameP;
	      UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe=subframeP;
	      
	      if (normalized_rx_power>(target_rx_power+4)) {
		tpc = 0; //-1
	      } else if (normalized_rx_power<(target_rx_power-4)) {
		tpc = 2; //+1
	      } else {
		tpc = 1; //0
	      }
	      	      
	      LOG_D(MAC,"[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, normalized/target rx power %d/%d\n",
		    module_idP,frameP, subframeP,harq_pid,tpc,
		    normalized_rx_power,target_rx_power);

	    } // Po_PUCCH has been updated 
	    else {
	      tpc = 1; //0
	    } // time to do TPC update 
	  else {
	    tpc = 1; //0
	  }

	  // Toggle NDI in first round
	  UE_template->oldNDI[harq_pid] = 1-UE_template->oldNDI[harq_pid];
	  ue_sched_ctl->round[CC_id][harq_pid] = 0;
	  round=0;
	}

      }

      if (round < 8) {
	// fill in MDPDCCH
	memset ((void *) dl_config_pdu, 0, sizeof (nfapi_dl_config_request_pdu_t));
	dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_MPDCCH_PDU_TYPE;
	dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof (nfapi_dl_config_mpdcch_pdu));
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_format = (UE_template->rach_resource_type > 1) ? 11 : 10;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_narrow_band = epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.mpdcch_Narrowband_r13-1;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.number_of_prb_pairs = 6;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_assignment = 0; // Note: this can be dynamic
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_tansmission_type = epdcch_setconfig_r11->transmissionType_r11;  
	AssertFatal(UE_template->physicalConfigDedicated->ext4->epdcch_Config_r11->config_r11.choice.setup.startSymbol_r11!=NULL,
		    "UE_template->physicalConfigDedicated->ext4->epdcch_Config_r11->config_r11.choice.setup.startSymbol_r11 is null\n");
	
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.start_symbol = *UE_template->physicalConfigDedicated->ext4->epdcch_Config_r11->config_r11.choice.setup.startSymbol_r11;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ecce_index = 0;        // Note: this should be dynamic
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.aggregation_level = 24;        // OK for CEModeA r1-3 (9.1.5-1b) or CEModeB r1-4
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti_type = 4; // t-CRNTI
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti = rnti;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ce_mode = (UE_template->rach_resource_type < 3) ? 1 : 2;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.drms_scrambling_init = epdcch_setconfig_r11->dmrs_ScramblingSequenceInt_r11;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.initial_transmission_sf_io = (frameP * 10) + subframeP;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.transmission_power = 6000;     // 0dB
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_coding = getRIV (6, 0, 6) | ((epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.mpdcch_Narrowband_r13-1)<<5);
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mcs = 9;       // adjust according to size of RAR, 208 bits with N1A_PRB=3
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pdsch_reptition_levels = 0;    // fix to 4 for now
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.redundancy_version = rvseq[round&3];
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.new_data_indicator = UE_template->oldNDI[harq_pid];
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_process = 0;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi_length = 0;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi = 0;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi_flag = 0;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi = 0;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_resource_offset = 0;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_subframe_repetition_number = 0;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpc = 3; 
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.downlink_assignment_index_length = 0;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.downlink_assignment_index = 0;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.allocate_prach_flag = 0;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.preamble_index = 0;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.prach_mask_index = 0;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.starting_ce_level = 0;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.srs_request = 0;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity_flag = 0;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity = 0;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.frequency_hopping_enabled_flag = 0;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.paging_direct_indication_differentiation_flag = 0;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.direct_indication = 0;
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.total_dci_length_including_padding = 0;        // this is not needed by OAI L1, but should be filled in
	dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.number_of_tx_antenna_ports = 1;
	dl_req->number_pdu++;
	UE_template->mcs[harq_pid] = dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mcs;
      }
    }
    else if ((subframeP == 7)&&(round<8)) {  // DLSCH
	  
	  int             absSF = (frameP * 10) + subframeP;
	  
	  // Have to check that MPDCCH was generated
	  LOG_I (MAC, "[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d: Generating DLSCH (ce_level %d RNTI %x)\n",
	    module_idP, CC_id, frameP, subframeP, UE_template->rach_resource_type - 1,rnti);
	  
	  first_rb = narrowband_to_first_rb (&cc[CC_id], epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.mpdcch_Narrowband_r13-1);            
	  dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu];
	  memset ((void *) dl_config_pdu, 0, sizeof (nfapi_dl_config_request_pdu_t));
      dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE;
      dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof (nfapi_dl_config_dlsch_pdu));
      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index = mac->pdu_index[CC_id];
      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = rnti;
      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type = 2;   // format 1A/1B/1D
      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0;     // localized
      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = getRIV (to_prb (cc[CC_id].mib->message.dl_Bandwidth), first_rb, 6);  // check that this isn't getRIV(6,0,6)
      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation = 2; //QPSK
      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version = 0;
      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks = 1;   // first block
      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag = 0;
      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme = (cc[CC_id].p_eNB == 1) ? 0 : 1;
      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers = 1;
      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands = 1;
      //      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index                         = ;
      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity = 1;
      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa = 4; // 0 dB
      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index = 0;
      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap = 0;
      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb = get_subbandsize (cc[CC_id].mib->message.dl_Bandwidth); // ignored
      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode = (cc[CC_id].p_eNB == 1) ? 1 : 2;
      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband = 1;
      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector = 1;
      //      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector                    = ; 
      
      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start = *UE_template->physicalConfigDedicated->ext4->epdcch_Config_r11->config_r11.choice.setup.startSymbol_r11;
      
      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type = (UE_template->rach_resource_type < 3) ? 1 : 2;
      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type = 2;        // not SI message
      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io = (10 * frameP) + subframeP;
      dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.drms_table_flag = 0;
      dl_req->number_pdu++;

      // DL request
      mac->TX_req[CC_id].sfn_sf = (frameP << 4) + subframeP;
      TX_req = &mac->TX_req[CC_id].tx_request_body.tx_pdu_list[mac->TX_req[CC_id].tx_request_body.number_of_pdus];
      TX_req->pdu_length = get_TBS_DL(UE_template->mcs[harq_pid],
				      6);
      TX_req->pdu_index = mac->pdu_index[CC_id]++;
      TX_req->num_segments = 1;
      TX_req->segments[0].segment_length = TX_req->pdu_length;
      TX_req->segments[0].segment_data = mac->UE_list.DLSCH_pdu[CC_id][0][(unsigned char) UE_id].payload[0];
      mac->TX_req[CC_id].tx_request_body.number_of_pdus++;

      ackNAK_absSF = absSF + 4;
      ul_req = &mac->UL_req_tmp[CC_id][ackNAK_absSF % 10].ul_config_request_body;
      ul_config_pdu = &ul_req->ul_config_pdu_list[ul_req->number_of_pdus];
      
      ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE;
      ul_config_pdu->pdu_size = (uint8_t) (2 + sizeof (nfapi_ul_config_uci_harq_pdu));
      ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.handle = 0;      // don't know how to use this
      ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.rnti = rnti;
      ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel13.ue_type = (UE_template->rach_resource_type < 3) ? 1 : 2;
      ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel13.empty_symbols = 0;
      ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel13.total_number_of_repetitions = pucchreps[UE_template->rach_resource_type - 1];
      ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel13.repetition_number = 0;

      if (cc[CC_id].tdd_Config == NULL) {    // FDD case
	ul_config_pdu->uci_harq_pdu.harq_information.harq_information_rel9_fdd.n_pucch_1_0 = n1pucchan[UE_template->rach_resource_type - 1];
	// NOTE: How to fill in the rest of the n_pucch_1_0 information 213 Section 10.1.2.1 in the general case
	// = N_ECCE_q + Delta_ARO + n1pucchan[ce_level]
	// higher in the MPDCCH configuration, N_ECCE_q is hard-coded to 0, and harq resource offset to 0 =>
	// Delta_ARO = 0 from Table 10.1.2.1-1
	ul_config_pdu->uci_harq_pdu.harq_information.harq_information_rel9_fdd.harq_size = 1; // 1-bit ACK/NAK
	ul_config_pdu->uci_harq_pdu.harq_information.harq_information_rel9_fdd.number_of_pucch_resources = 1;
      } else {
	AssertFatal (1 == 0, "PUCCH configuration for ACK/NAK not handled yet for TDD BL/CE case\n");
      }
      ul_req->number_of_pdus++;
      T (T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT (module_idP), T_INT (CC_id), T_INT (rnti), T_INT (frameP), T_INT (subframeP),
	 T_INT (0 /*harq_pid always 0? */ ), T_BUFFER (&mac->UE_list.DLSCH_pdu[CC_id][0][UE_id].payload[0], TX_req->pdu_length));
      
      if (opt_enabled == 1) {
	trace_pdu (1, (uint8_t *) mac->UE_list.DLSCH_pdu[CC_id][0][(unsigned char) UE_id].payload[0], TX_req->pdu_length , UE_id, 3, rnti, frameP, subframeP, 0, 0);
	LOG_D (OPT, "[eNB %d][DLSCH] CC_id %d Frame %d trace pdu for rnti %x with size %d\n", module_idP, CC_id, frameP, rnti, TX_req->pdu_length );
      }

    }
  }

}
#endif

//------------------------------------------------------------------------------
void
fill_DLSCH_dci(module_id_t module_idP,
               frame_t frameP, 
               sub_frame_t subframeP, 
               int *mbsfn_flagP)
//------------------------------------------------------------------------------
{
  // loop over all allocated UEs and compute frequency allocations for PDSCH
  int UE_id = -1;
  uint8_t /* first_rb, */ nb_rb = 3;
  rnti_t rnti;
  //unsigned char *vrb_map;
  uint8_t rballoc_sub[25];
  //uint8_t number_of_subbands=13;
  //unsigned char round;
  unsigned char harq_pid;
  int i;
  int CC_id;
  eNB_MAC_INST *eNB = RC.mac[module_idP];
  UE_list_t *UE_list = &eNB->UE_list;
  int N_RBG;
  int N_RB_DL;
  COMMON_channels_t *cc;
  eNB_DLSCH_INFO *dlsch_info;
  UE_TEMPLATE *ue_template;

  start_meas(&eNB->fill_DLSCH_dci);
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_FILL_DLSCH_DCI, 
                                          VCD_FUNCTION_IN);

  for (CC_id = 0; CC_id < RC.nb_mac_CC[module_idP]; CC_id++) {
    LOG_D(MAC, "Doing fill DCI for CC_id %d\n", 
          CC_id);

    if (mbsfn_flagP[CC_id] > 0)
      continue;

    cc = &eNB->common_channels[CC_id];
    N_RBG = to_rbg(cc->mib->message.dl_Bandwidth);
    N_RB_DL = to_prb(cc->mib->message.dl_Bandwidth);

    // UE specific DCIs
    for (UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) {
      dlsch_info = &eNB_dlsch_info[module_idP][CC_id][UE_id];
      LOG_T(MAC, "CC_id %d, UE_id: %d => status %d\n", 
            CC_id, 
            UE_id,
            dlsch_info->status);

      if (dlsch_info->status == S_DL_SCHEDULED) {
        // clear scheduling flag
        dlsch_info->status = S_DL_WAITING;
        rnti = UE_RNTI(module_idP, UE_id);
        harq_pid = frame_subframe2_dl_harq_pid(cc->tdd_Config,frameP,
                                               subframeP);
        ue_template = &UE_list->UE_template[CC_id][UE_id];
        nb_rb = ue_template->nb_rb[harq_pid];

        /// Synchronizing rballoc with rballoc_sub
        for (i = 0; i < N_RBG; i++) {
          rballoc_sub[i] = ue_template->rballoc_subband[harq_pid][i];
        }

        nfapi_dl_config_request_body_t *dl_config_request_body = &RC.mac[module_idP]->DL_req[CC_id].dl_config_request_body;
        nfapi_dl_config_request_pdu_t *dl_config_pdu;

        for (i = 0; i < dl_config_request_body->number_pdu; i++) {
          dl_config_pdu = &dl_config_request_body->dl_config_pdu_list[i];

          if (dl_config_pdu->pdu_type == NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE &&
              dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti == rnti &&
              dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format != 1) {
            dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = allocate_prbs_sub(nb_rb, 
                                                                                                N_RB_DL, 
                                                                                                N_RBG,
                                                                                                rballoc_sub);
            dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_allocation_type = 0;
          } else if (dl_config_pdu->pdu_type == NFAPI_DL_CONFIG_DLSCH_PDU_TYPE &&
                     dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti == rnti &&
                     dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type == 0) {
            dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding = allocate_prbs_sub(nb_rb, 
                                                                                              N_RB_DL, 
                                                                                              N_RBG,
                                                                                              rballoc_sub);
          }
        }
      }
    }
  }

  stop_meas(&eNB->fill_DLSCH_dci);
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_FILL_DLSCH_DCI, 
                                          VCD_FUNCTION_OUT);
}

//------------------------------------------------------------------------------
unsigned char *get_dlsch_sdu(module_id_t module_idP,
                             int CC_id, 
                             frame_t frameP, 
                             rnti_t rntiP,
                             uint8_t TBindex)
//------------------------------------------------------------------------------
{
  int UE_id;
  eNB_MAC_INST *eNB = RC.mac[module_idP];

  if (rntiP == SI_RNTI) {
    LOG_D(MAC, "[eNB %d] CC_id %d Frame %d Get DLSCH sdu for BCCH \n",
          module_idP, 
          CC_id, 
          frameP);
    return ((unsigned char *) &eNB->common_channels[CC_id].BCCH_pdu.payload[0]);
  }

  if (rntiP == P_RNTI) {
    LOG_D(MAC, "[eNB %d] CC_id %d Frame %d Get PCH sdu for PCCH \n", 
          module_idP, 
          CC_id, 
          frameP);
    return ((unsigned char *) &eNB->common_channels[CC_id].PCCH_pdu.payload[0]);
  }

  UE_id = find_UE_id(module_idP, rntiP);

  if (UE_id != -1) {
    LOG_D(MAC, "[eNB %d] Frame %d:  CC_id %d Get DLSCH sdu for rnti %x => UE_id %d\n",
          module_idP, 
          frameP, 
          CC_id, 
          rntiP, 
          UE_id);
    return ((unsigned char *) &eNB->UE_list.DLSCH_pdu[CC_id][TBindex][UE_id].payload[0]);
  } 

  LOG_E(MAC, "[eNB %d] Frame %d: CC_id %d UE with RNTI %x does not exist\n",
        module_idP, 
        frameP, 
        CC_id, 
        rntiP);
  return NULL;
}


//------------------------------------------------------------------------------
void
update_ul_dci(module_id_t module_idP,
              uint8_t CC_idP, 
              rnti_t rntiP, 
              uint8_t daiP, 
              sub_frame_t subframe)
//------------------------------------------------------------------------------
{
  eNB_MAC_INST *eNB = RC.mac[module_idP];
  COMMON_channels_t *cc = &eNB->common_channels[CC_idP];
  
  if (cc->tdd_Config != NULL) { // TDD
    nfapi_hi_dci0_request_t *HI_DCI0_req = &eNB->HI_DCI0_req[CC_idP][subframe];
    nfapi_hi_dci0_request_pdu_t *hi_dci0_pdu = &HI_DCI0_req->hi_dci0_request_body.hi_dci0_pdu_list[0];
    int limit = HI_DCI0_req->hi_dci0_request_body.number_of_dci + HI_DCI0_req->hi_dci0_request_body.number_of_hi;
    for (int i = 0; i < limit; i++, hi_dci0_pdu++) {
      if (hi_dci0_pdu->pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE && hi_dci0_pdu->dci_pdu.dci_pdu_rel8.rnti == rntiP)
        hi_dci0_pdu->dci_pdu.dci_pdu_rel8.dl_assignment_index = (daiP - 1) & 3;
    }
  }
  return;
}


//------------------------------------------------------------------------------
void
set_ue_dai(sub_frame_t subframeP,
           int UE_id,
           uint8_t CC_id,
           uint8_t tdd_config,
           UE_list_t *UE_list)
//------------------------------------------------------------------------------
{
  switch (tdd_config) {
    case 0:
      if (subframeP == 0 || subframeP == 1 || subframeP == 3 || subframeP == 5 || subframeP == 6 || subframeP == 8) {
        UE_list->UE_template[CC_id][UE_id].DAI = 0;
      }

      break;

    case 1:
      if (subframeP == 0 || subframeP == 4 || subframeP == 5 || subframeP == 9) {
        UE_list->UE_template[CC_id][UE_id].DAI = 0;
      }

      break;

    case 2:
      if (subframeP == 4 || subframeP == 5) {
        UE_list->UE_template[CC_id][UE_id].DAI = 0;
      }

      break;

    case 3:
      if (subframeP == 5 || subframeP == 7 || subframeP == 9) {
        UE_list->UE_template[CC_id][UE_id].DAI = 0;
      }

      break;

    case 4:
      if (subframeP == 0 || subframeP == 6) {
        UE_list->UE_template[CC_id][UE_id].DAI = 0;
      }

      break;

    case 5:
      if (subframeP == 9) {
        UE_list->UE_template[CC_id][UE_id].DAI = 0;
      }

      break;

    case 6:
      if (subframeP == 0 || subframeP == 1 || subframeP == 5 || subframeP == 6 || subframeP == 9) {
        UE_list->UE_template[CC_id][UE_id].DAI = 0;
      }

      break;

    default:
      UE_list->UE_template[CC_id][UE_id].DAI = 0;
      LOG_I(MAC, "unknown TDD config %d\n",
            tdd_config);
      break;
  }

  return;
}

void 
schedule_PCH(module_id_t module_idP, 
             frame_t frameP, 
             sub_frame_t subframeP) 
{
  /* DCI:format 1A/1C P-RNTI:0xFFFE */
  /* PDU:eNB_rrc_inst[Mod_idP].common_channels[CC_id].PCCH_pdu.payload */
  uint16_t pcch_sdu_length;
  int mcs = -1;
  int CC_id;
  eNB_MAC_INST *eNB = RC.mac[module_idP];
  COMMON_channels_t *cc;
  uint8_t *vrb_map;
  int n_rb_dl;
  int first_rb = -1;
  nfapi_dl_config_request_pdu_t *dl_config_pdu;
  nfapi_tx_request_pdu_t *TX_req;
  nfapi_dl_config_request_body_t *dl_req;
  UE_PF_PO_t *ue_pf_po;
#ifdef FORMAT1C
  int gap_index = 0;      /* indicate which gap(1st or 2nd) is used (0:1st) */
  const int GAP_MAP [9][2] = {
    {-1, 0},        /* N_RB_DL [6-10] -1: |N_RB/2| 0: N/A*/
    {4, 0},         /* N_RB_DL [11] */
    {8, 0},         /* N_RB_DL [12-19] */
    {12, 0},        /* N_RB_DL [20-26] */
    {18, 0},        /* N_RB_DL [27-44] */
    {27, 0},        /* N_RB_DL [45-49] */
    {27, 9},        /* N_RB_DL [50-63] */
    {32, 16},       /* N_RB_DL [64-79] */
    {48, 16}        /* N_RB_DL [80-110] */
  };
  uint8_t n_rb_step = 0;
  uint8_t n_gap = 0;
  uint8_t n_vrb_dl = 0;
  uint8_t Lcrbs = 0;
  uint16_t rb_bit = 168;    /* RB bit number value is unsure */
#endif

  start_meas(&eNB->schedule_pch);

  for (CC_id = 0; CC_id < RC.nb_mac_CC[module_idP]; CC_id++) {
    cc              = &eNB->common_channels[CC_id];
    vrb_map         = (void *) &cc->vrb_map;
    n_rb_dl         = to_prb(cc->mib->message.dl_Bandwidth);
    dl_req          = &eNB->DL_req[CC_id].dl_config_request_body;

    for (uint16_t i = 0; i < MAX_MOBILES_PER_ENB; i++) {
      ue_pf_po = &UE_PF_PO[CC_id][i];
      if (ue_pf_po->enable_flag != TRUE) {
        continue;
      }

      if (frameP % ue_pf_po->T == ue_pf_po->PF_min && subframeP == ue_pf_po->PO) {
        pcch_sdu_length = mac_rrc_data_req(module_idP,
                                           CC_id,
                                           frameP,
                                           PCCH, 
                                           1,
                                           &cc->PCCH_pdu.payload[0],
                                           i); // used for ue index

        if (pcch_sdu_length == 0) {
          LOG_D(MAC, "[eNB %d] Frame %d subframe %d: PCCH not active(size = 0 byte)\n", 
                module_idP, 
                frameP, 
                subframeP);
          continue;
        }

        LOG_D(MAC, "[eNB %d] Frame %d subframe %d: PCCH->PCH CC_id %d UE_id %d, Received %d bytes \n", 
              module_idP,
              frameP, 
              subframeP, 
              CC_id, 
              i, 
              pcch_sdu_length);

#ifdef FORMAT1C
        //NO SIB
        if ((subframeP == 0 || subframeP == 1 || subframeP == 2 || subframeP == 4 || subframeP == 6 || subframeP == 9) ||
            (subframeP == 5 && ((frameP % 2) != 0 && (frameP % 8) != 1))) {
          switch (n_rb_dl) {
            case 25:
              n_gap = GAP_MAP[3][0];  /* expect: 12 */
              n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap));  /* expect: 24 */
              first_rb = 10;
              break;

            case 50:
              n_gap = GAP_MAP[6][gap_index];  /* expect: 27 or 9 */

              if (gap_index > 0) {
                n_vrb_dl = (n_rb_dl / (2*n_gap)) * (2*n_gap);  /* 36 */
              } else {
                n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap));  /* expect: 46 */
              }

              first_rb = 24;
              break;

            case 100:
              n_gap = GAP_MAP[8][gap_index];  /* expect: 48 or 16 */

              if (gap_index > 0) {
                n_vrb_dl = (n_rb_dl / (2*n_gap)) * (2*n_gap);  /* expect: 96 */
              } else {
                n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap));  /* expect: 96 */
              }

              first_rb = 48;
              break;
          }
        } else if (subframeP == 5 && ((frameP % 2) == 0 || (frameP % 8) == 1)) {  // SIB + paging
          switch (n_rb_dl) {
            case 25:
              n_gap = GAP_MAP[3][0];  /* expect: 12 */
              n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap));  /* expect: 24 */
              first_rb = 14;
              break;

            case 50:
              n_gap = GAP_MAP[6][gap_index];  /* expect: 27 or 9 */

              if (gap_index > 0) {
                n_vrb_dl = (n_rb_dl / (2*n_gap)) * (2*n_gap);  /* 36 */
              } else {
                n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap));  /* expect: 46 */
              }

              first_rb = 28;
              break;

            case 100:
              n_gap = GAP_MAP[8][gap_index];  /* expect: 48 or 16 */

              if (gap_index > 0) {
                n_vrb_dl = (n_rb_dl / (2*n_gap)) * (2*n_gap);  /* expect: 96 */
              } else {
                n_vrb_dl = 2*((n_gap < (n_rb_dl - n_gap)) ? n_gap : (n_rb_dl - n_gap));  /* expect: 96 */
              }

              first_rb = 52;
              break;
          }
        }

        /* Get MCS for length of PCH */
        if (pcch_sdu_length <= TBStable1C[0]) {
          mcs=0;
        } else if (pcch_sdu_length <= TBStable1C[1]) {
          mcs=1;
        } else if (pcch_sdu_length <= TBStable1C[2]) {
          mcs=2;
        } else if (pcch_sdu_length <= TBStable1C[3]) {
          mcs=3;
        } else if (pcch_sdu_length <= TBStable1C[4]) {
          mcs=4;
        } else if (pcch_sdu_length <= TBStable1C[5]) {
          mcs=5;
        } else if (pcch_sdu_length <= TBStable1C[6]) {
          mcs=6;
        } else if (pcch_sdu_length <= TBStable1C[7]) {
          mcs=7;
        } else if (pcch_sdu_length <= TBStable1C[8]) {
          mcs=8;
        } else if (pcch_sdu_length <= TBStable1C[9]) {
          mcs=9;
        } else {
          /* unexpected: pcch sdb size is over max value*/
          LOG_E(MAC,"[eNB %d] Frame %d : PCCH->PCH CC_id %d, Received %d bytes is over max length(256) \n",
                module_idP, 
                frameP,
                CC_id, 
                pcch_sdu_length);
          return;
        }

        rb_num = TBStable1C[mcs] / rb_bit + ( (TBStable1C[mcs] % rb_bit == 0)? 0: 1) + 1;

        /* calculate N_RB_STEP and Lcrbs */
        if (n_rb_dl < 50) {
          n_rb_step = 2;
          Lcrbs = rb_num / 2 + ((rb_num % 2 == 0) ? 0:2);
        } else {
          n_rb_step = 4;
          Lcrbs = rb_num / 4 + ((rb_num % 4 == 0) ? 0:4);
        }

        for(i = 0; i < Lcrbs ; i++) {
          vrb_map[first_rb+i] = 1;
        }

#else

        //NO SIB
        if ((subframeP == 0 || subframeP == 1 || subframeP == 2 || subframeP == 4 || subframeP == 6 || subframeP == 9) ||
            (subframeP == 5 && ((frameP % 2) != 0 && (frameP % 8) != 1))) {
          switch (n_rb_dl) {
            case 25:
              first_rb = 10;
              break;

            case 50:
              first_rb = 24;
              break;

            case 100:
              first_rb = 48;
              break;
          }
        } else if (subframeP == 5 && ((frameP % 2) == 0 || (frameP % 8) == 1)) {  // SIB + paging
          switch (n_rb_dl) {
            case 25:
              first_rb = 14;
              break;

            case 50:
              first_rb = 28;
              break;

            case 100:
              first_rb = 52;
              break;
          }
        }

        vrb_map[first_rb] = 1;
        vrb_map[first_rb + 1] = 1;
        vrb_map[first_rb + 2] = 1;
        vrb_map[first_rb + 3] = 1;

        /* Get MCS for length of PCH */
        if (pcch_sdu_length <= get_TBS_DL(0, 3)) {
          mcs = 0;
        } else if (pcch_sdu_length <= get_TBS_DL(1, 3)) {
          mcs = 1;
        } else if (pcch_sdu_length <= get_TBS_DL(2, 3)) {
          mcs = 2;
        } else if (pcch_sdu_length <= get_TBS_DL(3, 3)) {
          mcs = 3;
        } else if (pcch_sdu_length <= get_TBS_DL(4, 3)) {
          mcs = 4;
        } else if (pcch_sdu_length <= get_TBS_DL(5, 3)) {
          mcs = 5;
        } else if (pcch_sdu_length <= get_TBS_DL(6, 3)) {
          mcs = 6;
        } else if (pcch_sdu_length <= get_TBS_DL(7, 3)) {
          mcs = 7;
        } else if (pcch_sdu_length <= get_TBS_DL(8, 3)) {
          mcs = 8;
        } else if (pcch_sdu_length <= get_TBS_DL(9, 3)) {
          mcs = 9;
        }

#endif
        dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu];
        memset((void *) dl_config_pdu, 
               0, 
               sizeof(nfapi_dl_config_request_pdu_t));
        dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE;
        dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu));
#ifdef FORMAT1C
        dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format                  = NFAPI_DL_DCI_FORMAT_1C;
        dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding       = getRIV(n_vrb_dl/n_rb_step, first_rb/n_rb_step, Lcrbs/n_rb_step);
        dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.ngap                        = n_gap;
#else
        dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format                  = NFAPI_DL_DCI_FORMAT_1A;
        dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process                = 0;
        dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc                         = 1; // no TPC
        dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1        = 1;
        dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1        = 1;
        dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding       = getRIV(n_rb_dl, 
                                                                                       first_rb, 
                                                                                       4);
        dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.virtual_resource_block_assignment_flag = 0;
#endif
        dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level           = 4;
        dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti                        = 0xFFFE; // P-RNTI
        dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type                   = 2;    // P-RNTI : see Table 4-10 from SCF082 - nFAPI specifications
        dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power          = 6000; // equal to RS power
        dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = mcs;

        if (!CCE_allocation_infeasible(module_idP, 
                                       CC_id, 
                                       0, 
                                       subframeP, 
                                       dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level, 
                                       P_RNTI)) {
          LOG_D(MAC,"Frame %d: Subframe %d : Adding common DCI for P_RNTI\n", 
                frameP,
                subframeP);
          dl_req->number_dci++;
          dl_req->number_pdu++;
          dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG;
          eNB->DL_req[CC_id].sfn_sf = frameP<<4 | subframeP;
          eNB->DL_req[CC_id].header.message_id = NFAPI_DL_CONFIG_REQUEST;

          dl_config_pdu                                                                  = &dl_req->dl_config_pdu_list[dl_req->number_pdu];
          memset((void *)dl_config_pdu,
                 0,
                 sizeof(nfapi_dl_config_request_pdu_t));
          dl_config_pdu->pdu_type                                                        = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE;
          dl_config_pdu->pdu_size                                                        = (uint8_t)(2 + sizeof(nfapi_dl_config_dlsch_pdu));
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index                              = eNB->pdu_index[CC_id];
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti                                   = 0xFFFE;
#ifdef FORMAT1C
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type               = 3;   // format 1C
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding                  = getRIV(n_vrb_dl / n_rb_step, 
                                                                                                  first_rb / n_rb_step, 
                                                                                                  Lcrbs / n_rb_step);
#else
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type               = 2;   // format 1A/1B/1D
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding                  = getRIV(n_rb_dl, 
                                                                                                  first_rb, 
                                                                                                  4);
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0;   // localized
#endif
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation                             = 2; //QPSK
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version                     = 1;
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks                       = 1;// first block
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag  = 0;
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme                    = (cc->p_eNB==1 ) ? 0 : 1;
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers                       = 1;
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands                     = 1;
          // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index                         = ;
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity                   = 1;
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa                                     = 4; // 0 dB
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index               = 0;
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap                                   = 0;
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb                                   = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode                      = (cc->p_eNB==1 ) ? 1 : 2;
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband                 = 1;
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector                          = 1;
          // dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector                    = ;
          // Rel10 fields
#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0))
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.pdsch_start                           = 3;
#endif
          // Rel13 fields
#if (LTE_RRC_VERSION >= MAKE_VERSION(13, 0, 0))
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type                               = 0; // regular UE
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type                    = 2; // not BR
          dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io            = 0xFFFF;
#endif
          dl_req->number_pdu++;
          eNB->TX_req[CC_id].sfn_sf                                                      = (frameP<<4)+subframeP;
          TX_req = &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB->TX_req[CC_id].tx_request_body.number_of_pdus];
          TX_req->pdu_length                                                             = pcch_sdu_length;
          TX_req->pdu_index                                                              = eNB->pdu_index[CC_id]++;
          TX_req->num_segments                                                           = 1;
          TX_req->segments[0].segment_length                                             = pcch_sdu_length;
          TX_req->segments[0].segment_data                                               = cc[CC_id].PCCH_pdu.payload;
          eNB->TX_req[CC_id].tx_request_body.tl.tag                                      = NFAPI_TX_REQUEST_BODY_TAG;
          eNB->TX_req[CC_id].tx_request_body.number_of_pdus++;
        } else {
          LOG_E(MAC,"[eNB %d] CCid %d Frame %d, subframe %d : Cannot add DCI 1A/1C for Paging\n",
                module_idP, 
                CC_id, 
                frameP, 
                subframeP);
          continue;
        }

        if (opt_enabled == 1) {
          trace_pdu(DIRECTION_DOWNLINK,
                    &eNB->common_channels[CC_id].PCCH_pdu.payload[0],
                    pcch_sdu_length,
                    0xffff,
                    PCCH,
                    P_RNTI,
                    eNB->frame,
                    eNB->subframe,
                    0,
                    0);
          LOG_D(OPT,"[eNB %d][PCH] Frame %d trace pdu for CC_id %d rnti %x with size %d\n",
                module_idP, 
                frameP, 
                CC_id, 
                0xffff, 
                pcch_sdu_length);
        }

        eNB->eNB_stats[CC_id].total_num_pcch_pdu++;
        eNB->eNB_stats[CC_id].pcch_buffer = pcch_sdu_length;
        eNB->eNB_stats[CC_id].total_pcch_buffer += pcch_sdu_length;
        eNB->eNB_stats[CC_id].pcch_mcs = mcs;
        //paging first_rb log
        LOG_D(MAC,"[eNB %d] Frame %d subframe %d PCH: paging_ue_index %d pcch_sdu_length %d mcs %d first_rb %d\n",
              module_idP, 
              frameP, 
              subframeP, 
              ue_pf_po->ue_index_value, 
              pcch_sdu_length, 
              mcs, 
              first_rb);
        pthread_mutex_lock(&ue_pf_po_mutex);
        memset(ue_pf_po, 
               0, 
               sizeof(UE_PF_PO_t));
        pthread_mutex_unlock(&ue_pf_po_mutex);
      }
    }
  }

  /* this might be misleading when pcch is inactive */
  stop_meas(&eNB->schedule_pch);
  return;
}

static int 
slice_priority_compare(const void *_a, 
                       const void *_b, 
                       void *_c) 
{
  const int slice_id1 = *(const int *) _a;
  const int slice_id2 = *(const int *) _b;
  const module_id_t Mod_id = *(int *)  _c;
  const slice_info_t *sli = &RC.mac[Mod_id]->slice_info;

  if (sli->dl[slice_id1].prio > sli->dl[slice_id2].prio) {
    return -1;
  }

  return 1;
}

void 
slice_priority_sort(module_id_t Mod_id, 
                    int slice_list[MAX_NUM_SLICES]) 
{
  int i;
  int n_dl = RC.mac[Mod_id]->slice_info.n_dl;
  for (i = 0; i < n_dl; i++) {
    slice_list[i] = i;
  }

  qsort_r(slice_list, 
          n_dl, 
          sizeof(int),
          slice_priority_compare, 
          &Mod_id);
  return;
}