/*
 * 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.0  (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

 */

#include "assertions.h"
#include "PHY/defs.h"
#include "PHY/extern.h"

#include "SCHED/defs.h"
#include "SCHED/extern.h"

#include "LAYER2/MAC/defs.h"
#include "LAYER2/MAC/proto.h"
#include "LAYER2/MAC/extern.h"
#include "UTIL/LOG/log.h"
#include "UTIL/LOG/vcd_signal_dumper.h"
#include "UTIL/OPT/opt.h"
#include "OCG.h"
#include "OCG_extern.h"

#include "RRC/LITE/extern.h"
#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h"

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

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

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

#include "T.h"

#define ENABLE_MAC_PAYLOAD_DEBUG
//#define DEBUG_eNB_SCHEDULER 1

extern RAN_CONTEXT_t RC;

//------------------------------------------------------------------------------
void
add_ue_dlsch_info(
  module_id_t module_idP,
  int CC_id,
  int UE_id,
  sub_frame_t subframeP,
  UE_DLSCH_STATUS status
)
//------------------------------------------------------------------------------
{

  eNB_dlsch_info[module_idP][CC_id][UE_id].rnti             = UE_RNTI(module_idP,UE_id);
  //  eNB_dlsch_info[module_idP][CC_id][ue_mod_idP].weight           = weight;
  eNB_dlsch_info[module_idP][CC_id][UE_id].subframe         = subframeP;
  eNB_dlsch_info[module_idP][CC_id][UE_id].status           = status;

  eNB_dlsch_info[module_idP][CC_id][UE_id].serving_num++;

}

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

}

//------------------------------------------------------------------------------
unsigned char
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 != 0) {
    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 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 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;
      }

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


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

/*unsigned int getRepetition(UE_TEMPLATE * pue_template){
    EPDCCH_SetConfig_r11_t *epdcch_setconfig_r11;

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


    epdcch_setconfig_r11->setConfigId_r11 = 0;
    epdcch_setconfig_r11->transmissionType_r11 = EPDCCH_SetConfig_r11__transmissionType_r11_localised;
    epdcch_setconfig_r11->resourceBlockAssignment_r11.numberPRB_Pairs_r11 = EPDCCH_SetConfig_r11__resourceBlockAssignment_r11__numberPRB_Pairs_r11_n2;
    //epdcch_setconfig_r11->resourceBlockAssignment_r11.resourceBlockAssignment_r11 = calloc(0, sizeof(BIT_STRING_t));
    epdcch_setconfig_r11->resourceBlockAssignment_r11.resourceBlockAssignment_r11.buf = calloc(0, 2 * sizeof(uint8_t));
    epdcch_setconfig_r11->resourceBlockAssignment_r11.resourceBlockAssignment_r11.size = 2;
    epdcch_setconfig_r11->resourceBlockAssignment_r11.resourceBlockAssignment_r11.bits_unused = 6;
    epdcch_setconfig_r11->resourceBlockAssignment_r11.resourceBlockAssignment_r11.buf[0] = 0x0E;

    epdcch_setconfig_r11->dmrs_ScramblingSequenceInt_r11 = 0;
    epdcch_setconfig_r11->pucch_ResourceStartOffset_r11 = 0;
    epdcch_setconfig_r11->re_MappingQCL_ConfigId_r11 = NULL;

    epdcch_setconfig_r11->ext2 = calloc(1, sizeof(struct EPDCCH_SetConfig_r11__ext2));
    epdcch_setconfig_r11->ext2->numberPRB_Pairs_v1310 = NULL;
    epdcch_setconfig_r11->ext2->mpdcch_config_r13 = calloc(1, sizeof(struct EPDCCH_SetConfig_r11__ext2__mpdcch_config_r13));
    epdcch_setconfig_r11->ext2->mpdcch_config_r13->present = EPDCCH_SetConfig_r11__ext2__mpdcch_config_r13_PR_setup;
    epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.csi_NumRepetitionCE_r13 = EPDCCH_SetConfig_r11__ext2__mpdcch_config_r13__setup__csi_NumRepetitionCE_r13_sf1;
    epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.mpdcch_pdsch_HoppingConfig_r13 = EPDCCH_SetConfig_r11__ext2__mpdcch_config_r13__setup__mpdcch_pdsch_HoppingConfig_r13_off;
    epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.mpdcch_StartSF_UESS_r13.present = EPDCCH_SetConfig_r11__ext2__mpdcch_config_r13__setup__mpdcch_StartSF_UESS_r13_PR_fdd_r13;
    epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.mpdcch_StartSF_UESS_r13.choice.fdd_r13 = EPDCCH_SetConfig_r11__ext2__mpdcch_config_r13__setup__mpdcch_StartSF_UESS_r13__fdd_r13_v1;
    epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.mpdcch_NumRepetition_r13 = EPDCCH_SetConfig_r11__ext2__mpdcch_config_r13__setup__mpdcch_NumRepetition_r13_r1;
    epdcch_setconfig_r11->ext2->mpdcch_config_r13->choice.setup.mpdcch_Narrowband_r13 = 3;
    ASN_SEQUENCE_ADD(physicalConfigDedicated2->ext4->epdcch_Config_r11->config_r11.choice.setup.setConfigToAddModList_r11, epdcch_setconfig_r11);

}*/

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


    // 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:
    //		return;
    //		break;
    //	case 2:
    //		return;
    //		break;
    //	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 != 1) && (tdd_sfa != 2) && (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 != 1) && (tdd_sfa != 3) && (tdd_sfa != 4) && (tdd_sfa != 6)) return;
    //		break;

    //	}
    //}
    //weight = get_ue_weight(module_idP,UE_id);
    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;

        for (UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id])
        {
            first_rb = 0;
            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];


            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);
            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) {
                // get freq_allocation
                nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid];

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

                    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:
                        {

                            // rmax from SIB2 information
                            rmax = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->mpdcch_NumRepetition_RA_r13;
                            // 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 narrowband according to higher-layer config
                            num_nb = p[RA_template->rach_resource_type - 1]->mpdcch_NarrowbandsToMonitor_r13.list.count;
                            RA_template->msg2_narrowband = *p[RA_template->rach_resource_type - 1]->mpdcch_NarrowbandsToMonitor_r13.list.array[RA_template->preamble_index%num_nb];
                            first_rb = RA_template->msg2_narrowband * 6;

                            if ((RA_template->msg2_mpdcch_repetition_cnt == 0) &&
                                (mpdcch_sf_condition(eNB, CC_idP, frameP, subframeP, rmax, TYPE2)>0)) {
                                // MPDCCH configuration for RAR



                                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 = (RA_template->rach_resource_type > 1) ? 11 : 10;
                                dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_narrow_band = RA_template->msg2_narrowband;
                                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_idP].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_idP].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 = 2;  // RA-RNTI
                                dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti = RA_template->RA_rnti;
                                dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ce_mode = (RA_template->rach_resource_type < 3) ? 1 : 2;
                                dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.drms_scrambling_init = cc[CC_idP].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 = 0;
                                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 = 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;
                                RA_template->msg2_mpdcch_repetition_cnt++;
                                dl_req->number_pdu++;

                            } //repetition_count==0 && SF condition met
                            else if (RA_template->msg2_mpdcch_repetition_cnt>0) { // we're in a stream of repetitions
                                RA_template->msg2_mpdcch_repetition_cnt++;
                                if (RA_template->msg2_mpdcch_repetition_cnt == reps) { // this is the last mpdcch repetition
                                    if (cc[CC_idP].tdd_Config == NULL) { // FDD case
                                                                         // wait 2 subframes for PDSCH transmission
                                        if (subframeP>7) RA_template->Msg2_frame = (frameP + 1) & 1023;
                                        else             RA_template->Msg2_frame = frameP;
                                        RA_template->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 ((RA_template->Msg2_frame == frameP) && (RA_template->Msg2_subframe == subframeP)) {
                                    // Program PDSCH
                                    RA_template->generate_rar = 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_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_idP];
                                    dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti = RA_template->RA_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(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 = (RA_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++;

                                    // 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 = 1; // dont adjust power when retransmitting
                       // dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1 = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid];
                      //  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1 = UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid];
                       // dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1 = round & 3;


                        if (!CCE_allocation_infeasible(module_idP, CC_id, 0, subframeP,
                            dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level,
                            rnti)) {
                            dl_req->number_dci++;
                            dl_req->number_pdu++;

                        }
                        else {
                            // No TX request for retransmission (check if null request for FAPI)
                        }
                    }

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

                    //eNB_UE_stats->dlsch_trials[round]++;
                    UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission += 1;
                    UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx = nb_rb;
                    UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_retx += nb_rb;
                    UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1 = eNB_UE_stats->dlsch_mcs1;
                    UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2 = eNB_UE_stats->dlsch_mcs1;
                }
                else {
                    LOG_D(MAC, "[eNB %d] Frame %d CC_id %d : don't schedule UE %d, its retransmission takes more resources than we have\n",
                        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
                //to be checked
                TBS = get_TBS_DL(eNB_UE_stats->dlsch_mcs1, nb_available_rb);
                // check first for RLC data on DCCH
                // add the length for  all the control elements (timing adv, drx, etc) : header + payload

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

                    TBS = 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);
                    }
                    /////////////////////////////////////////////////////////////
                    // alter the allocation of the emtc UE here
                    //////////////////////////////////////////////////////////////
                    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;
                        }
                    }
                    ///////////////////////////////////


                    // 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
                    UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used = nb_rb;
                    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 = 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
                    }

                    //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++;

                    // 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++;

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

                }
            }


        } // 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,
  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

  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:
      return;
	break;
    case 2:
      return;
      break;
    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!=1)&&(tdd_sfa!=2)&&(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!=1)&&(tdd_sfa!=3)&&(tdd_sfa!=4)&&(tdd_sfa!=6)) return;
      break;
   
    }
  }
  //weight = get_ue_weight(module_idP,UE_id);
  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++) {
    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]) {
      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];


      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 (continue_flag != 1 */

      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 = ue_sched_ctl->pre_nb_available_rbs[CC_id];
      harq_pid = ue_sched_ctl->harq_pid[CC_id];
      round = ue_sched_ctl->round[CC_id];
      UE_list->eNB_UE_stats[CC_id][UE_id].crnti= rnti;
      UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status=mac_eNB_get_rrc_status(module_idP,rnti);
      UE_list->eNB_UE_stats[CC_id][UE_id].harq_pid = harq_pid; 
      UE_list->eNB_UE_stats[CC_id][UE_id].harq_round = round;

      sdu_length_total=0;
      num_sdus=0;

      /*
      DevCheck(((eNB_UE_stats->dl_cqi < 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];
      eNB_UE_stats->dlsch_mcs1 = eNB_UE_stats->dlsch_mcs1;//cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs);


      // 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
      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) {
        // get freq_allocation
        nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid];

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

          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:
	    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                         = 1; // dont adjust power when retransmitting
	    dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1        = UE_list->UE_template[CC_id][UE_id].oldNDI[harq_pid];
	    dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = UE_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid];
	    dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1        = round&3;

	    if (cc[CC_id].tdd_Config != NULL) { //TDD
	      dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.downlink_assignment_index = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3;
	      LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, dai %d, mcs %d\n",
		    module_idP,CC_id,harq_pid,round,
		    (UE_list->UE_template[CC_id][UE_id].DAI-1),
		    UE_list->UE_template[CC_id][UE_id].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_list->UE_template[CC_id][UE_id].oldmcs1[harq_pid]);
	      
	    }
	    if (!CCE_allocation_infeasible(module_idP,CC_id,0,subframeP,
					   dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level,
					   rnti)) {
	      dl_req->number_dci++;
	      dl_req->number_pdu++;

	    }
	    else {
	      // No TX request for retransmission (check if null request for FAPI)
	    }
	  }

	  add_ue_dlsch_info(module_idP,
			    CC_id,
			    UE_id,
			    subframeP,
			    S_DL_SCHEDULED);
	  
	  //eNB_UE_stats->dlsch_trials[round]++;
	  UE_list->eNB_UE_stats[CC_id][UE_id].num_retransmission+=1;
	  UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_retx=nb_rb;
	  UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_retx+=nb_rb;
	  UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs1=eNB_UE_stats->dlsch_mcs1;
	  UE_list->eNB_UE_stats[CC_id][UE_id].dlsch_mcs2=eNB_UE_stats->dlsch_mcs1;
	} else {
          LOG_D(MAC,"[eNB %d] Frame %d CC_id %d : don't schedule UE %d, its retransmission takes more resources than we have\n",
                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);
        // 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];
          }

          TBS = 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=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;

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

	  // do PUCCH power control
          // this is the normalized RX power
	  eNB_UE_stats =  &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
	      }
	      /*	      
	      LOG_I(MAC,"[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n",
		    module_idP,frameP, subframeP,harq_pid,tpc,
		    tpc_accumulated,normalized_rx_power,target_rx_power);*/

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

	  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;
	  if (cc[CC_id].tdd_Config != NULL) { //TDD
	    dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.downlink_assignment_index = (UE_list->UE_template[CC_id][UE_id].DAI-1)&3;
	    LOG_D(MAC,"[eNB %d] Retransmission CC_id %d : harq_pid %d, round %d, dai %d, mcs %d\n",
		  module_idP,CC_id,harq_pid,round,
		  (UE_list->UE_template[CC_id][UE_id].DAI-1),
		  mcs);
	  } 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,mcs);
	    
	  }
	  dl_req->number_dci++;
	  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++;

        } 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
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_UE_STATS      *eNB_UE_stats;

  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<MAX_NUM_CCs; 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]) {
      LOG_T(MAC,"CC_id %d, UE_id: %d => status %d\n",CC_id,UE_id,eNB_dlsch_info[module_idP][CC_id][UE_id].status);

      if (eNB_dlsch_info[module_idP][CC_id][UE_id].status == S_DL_SCHEDULED) {

        // clear scheduling flag
        eNB_dlsch_info[module_idP][CC_id][UE_id].status = S_DL_WAITING;
        rnti = UE_RNTI(module_idP,UE_id);
	harq_pid = UE_list->UE_sched_ctrl[UE_id].harq_pid[CC_id];
        nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid];

	eNB_UE_stats = &UE_list->eNB_UE_stats[CC_id][UE_id]; 

	
        /// Synchronizing rballoc with rballoc_sub
        for(i=0; i<N_RBG; i++) {
          rballoc_sub[i] = UE_list->UE_template[CC_id][UE_id].rballoc_subband[harq_pid][i];
        }

	nfapi_dl_config_request_t      *DL_req         = &RC.mac[module_idP]->DL_req[0];
	nfapi_dl_config_request_pdu_t* dl_config_pdu;

	for (i=0;i<DL_req[CC_id].dl_config_request_body.number_pdu;i++) {
	  dl_config_pdu                    = &DL_req[CC_id].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.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;
	    break;
	  }
	}
      }
    }

  }

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

  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]);
  } else {
    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)
//------------------------------------------------------------------------------
{

  nfapi_hi_dci0_request_t *HI_DCI0_req    = &RC.mac[module_idP]->HI_DCI0_req[CC_idP];
  nfapi_hi_dci0_request_pdu_t  *hi_dci0_pdu    = &HI_DCI0_req->hi_dci0_request_body.hi_dci0_pdu_list[0];
  COMMON_channels_t    *cc                     = &RC.mac[module_idP]->common_channels[CC_idP];
  int i;

  if (cc->tdd_Config != NULL) { // TDD 
    for (i=0; i<HI_DCI0_req->hi_dci0_request_body.number_of_dci + HI_DCI0_req->hi_dci0_request_body.number_of_dci; i++) {

      if ((hi_dci0_pdu[i].pdu_type == NFAPI_HI_DCI0_DCI_PDU_TYPE)  && 
	  (hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.rnti == rntiP))
        hi_dci0_pdu[i].dci_pdu.dci_pdu_rel8.dl_assignment_index = (daiP-1)&3;
      
    }
  }
}


//------------------------------------------------------------------------------
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_N(MAC,"unknow TDD config %d\n",tdd_config);
    break;
  }
}