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

/*! \file PHY/LTE_TRANSPORT/dci_tools.c
 * \brief PHY Support routines (eNB/UE) for filling PDSCH/PUSCH/DLSCH/ULSCH data structures based on DCI PDUs generated by eNB MAC scheduler.
 * \author R. Knopp
 * \date 2011
 * \version 0.1
 * \company Eurecom
 * \email: knopp@eurecom.fr
 * \note
 * \warning
 */

#include "PHY/defs_eNB.h"
#include "PHY/phy_extern.h"
#include "SCHED/sched_eNB.h"
#ifdef DEBUG_DCI_TOOLS
#include "PHY/phy_vars.h"
#endif
#include "assertions.h"
#include "nfapi_interface.h"

//#define DEBUG_HARQ


#include "LAYER2/MAC/mac.h"

//#define DEBUG_DCI
#include "dci_tools_common_extern.h"
#include "transport_proto.h"

int16_t find_dlsch(uint16_t rnti, PHY_VARS_eNB *eNB,find_type_t type)
{
  uint16_t i;
  int16_t first_free_index=-1;

  AssertFatal(eNB!=NULL,"eNB is null\n");
  for (i=0; i<NUMBER_OF_UE_MAX; i++) {
    AssertFatal(eNB->dlsch[i]!=NULL,"eNB->dlsch[%d] is null\n",i);
    AssertFatal(eNB->dlsch[i]!=NULL,"eNB->dlsch[%d][0] is null\n",i);
    LOG_D(PHY,"searching for rnti %x : UE index %d=> harq_mask %x, rnti %x, first_free_index %d\n", rnti,i,eNB->dlsch[i][0]->harq_mask,eNB->dlsch[i][0]->rnti,first_free_index);
    if ((eNB->dlsch[i][0]->harq_mask >0) &&
        (eNB->dlsch[i][0]->rnti==rnti))       return i;
    else if ((eNB->dlsch[i][0]->harq_mask == 0) && (first_free_index==-1)) first_free_index=i;
  }
  if (type == SEARCH_EXIST) return -1;
  if (first_free_index != -1)
    eNB->dlsch[first_free_index][0]->rnti = 0;
  return first_free_index;
}

int16_t find_ulsch(uint16_t rnti, PHY_VARS_eNB *eNB,find_type_t type)
{
  uint16_t i;
  int16_t first_free_index=-1;

  AssertFatal(eNB!=NULL,"eNB is null\n");
  for (i=0; i<NUMBER_OF_UE_MAX; i++) {
    AssertFatal(eNB->ulsch[i]!=NULL,"eNB->ulsch[%d] is null\n",i);
    if ((eNB->ulsch[i]->harq_mask >0) &&
        (eNB->ulsch[i]->rnti==rnti))       return i;
    else if ((eNB->ulsch[i]->harq_mask == 0) && (first_free_index==-1)) first_free_index=i;
  }
  if (type == SEARCH_EXIST) return -1;
  if (first_free_index != -1)
    eNB->ulsch[first_free_index]->rnti = 0;
  return first_free_index;
}





void fill_pdcch_order(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_alloc,nfapi_dl_config_dci_dl_pdu *pdu)
{
  LTE_DL_FRAME_PARMS                *fp      = &eNB->frame_parms;
  uint8_t                           *dci_pdu = &dci_alloc->dci_pdu[0];
  nfapi_dl_config_dci_dl_pdu_rel8_t *rel8    = &pdu->dci_dl_pdu_rel8;

  dci_alloc->firstCCE = rel8->cce_idx;
  dci_alloc->L        = rel8->aggregation_level;
  dci_alloc->rnti     = rel8->rnti;
  dci_alloc->harq_pid = rel8->harq_process;
  dci_alloc->ra_flag  = 0;
  dci_alloc->format   = format1A;

  LOG_D(PHY,"NFAPI: DCI format %d, nCCE %d, L %d, rnti %x,harq_pid %d\n",
        rel8->dci_format,rel8->cce_idx,rel8->aggregation_level,rel8->rnti,rel8->harq_process);

  switch (fp->N_RB_DL) {
  case 6:
    if (fp->frame_type == TDD) {
      dci_alloc->dci_length                         = sizeof_DCI1A_1_5MHz_TDD_1_6_t;
      ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->type     = 1;
      ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->vrb_type = rel8->virtual_resource_block_assignment_flag;
      ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->mcs      = rel8->mcs_1;
      ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->ndi      = rel8->new_data_indicator_1;
      ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->rballoc  = rel8->resource_block_coding;
      ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->rv       = rel8->redundancy_version_1;
      ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->TPC      = rel8->tpc;
      ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->harq_pid = rel8->harq_process;
      ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->dai      = rel8->downlink_assignment_index;
      ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->padding  = 0;
    } else {
      dci_alloc->dci_length                         = sizeof_DCI1A_1_5MHz_FDD_t;
      ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->type         = 1;
      ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->vrb_type     = rel8->virtual_resource_block_assignment_flag;
      ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->mcs          = rel8->mcs_1;
      ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->ndi          = rel8->new_data_indicator_1;
      ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->rballoc      = rel8->resource_block_coding;
      ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->rv           = rel8->redundancy_version_1;
      ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->TPC          = rel8->tpc;
      ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->harq_pid     = rel8->harq_process;
      ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->padding      = 0;
      //      printf("FDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
    }
    break;
  case 25:
    if (fp->frame_type == TDD) {
      dci_alloc->dci_length                         = sizeof_DCI1A_5MHz_TDD_1_6_t;
      ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->type       = 1;
      ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->vrb_type   = rel8->virtual_resource_block_assignment_flag;
      ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->mcs        = rel8->mcs_1;
      ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->ndi        = rel8->new_data_indicator_1;
      ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->rballoc    = rel8->resource_block_coding;
      ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->rv         = rel8->redundancy_version_1;
      ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->TPC        = rel8->tpc;
      ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->harq_pid   = rel8->harq_process;
      ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->dai        = rel8->downlink_assignment_index;
      ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->padding    = 0;
       //        printf("TDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
    } else {
      dci_alloc->dci_length                         = sizeof_DCI1A_5MHz_FDD_t;
      ((DCI1A_5MHz_FDD_t *)dci_pdu)->type           = 1;
      ((DCI1A_5MHz_FDD_t *)dci_pdu)->vrb_type       = rel8->virtual_resource_block_assignment_flag;
      ((DCI1A_5MHz_FDD_t *)dci_pdu)->mcs            = rel8->mcs_1;
      ((DCI1A_5MHz_FDD_t *)dci_pdu)->ndi            = rel8->new_data_indicator_1;
      ((DCI1A_5MHz_FDD_t *)dci_pdu)->rballoc        = rel8->resource_block_coding;
      ((DCI1A_5MHz_FDD_t *)dci_pdu)->rv             = rel8->redundancy_version_1;
      ((DCI1A_5MHz_FDD_t *)dci_pdu)->TPC            = rel8->tpc;
      ((DCI1A_5MHz_FDD_t *)dci_pdu)->harq_pid       = rel8->harq_process;
      ((DCI1A_5MHz_FDD_t *)dci_pdu)->padding        = 0;
      //      printf("FDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
    }
    break;
  case 50:
    if (fp->frame_type == TDD) {
      dci_alloc->dci_length                         = sizeof_DCI1A_10MHz_TDD_1_6_t;
      ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->type      = 1;
      ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->vrb_type  = rel8->virtual_resource_block_assignment_flag;
      ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->mcs       = rel8->mcs_1;
      ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->ndi       = rel8->new_data_indicator_1;
      ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->rballoc   = rel8->resource_block_coding;
      ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->rv        = rel8->redundancy_version_1;
      ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->TPC       = rel8->tpc;
      ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->harq_pid  = rel8->harq_process;
      ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->dai       = rel8->downlink_assignment_index;
      ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->padding   = 0;
      //        printf("TDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
    } else {
      dci_alloc->dci_length                         = sizeof_DCI1A_10MHz_FDD_t;
      ((DCI1A_10MHz_FDD_t *)dci_pdu)->type          = 1;
      ((DCI1A_10MHz_FDD_t *)dci_pdu)->vrb_type      = rel8->virtual_resource_block_assignment_flag;
      ((DCI1A_10MHz_FDD_t *)dci_pdu)->mcs           = rel8->mcs_1;
      ((DCI1A_10MHz_FDD_t *)dci_pdu)->ndi           = rel8->new_data_indicator_1;
      ((DCI1A_10MHz_FDD_t *)dci_pdu)->rballoc       = rel8->resource_block_coding;
      ((DCI1A_10MHz_FDD_t *)dci_pdu)->rv            = rel8->redundancy_version_1;
      ((DCI1A_10MHz_FDD_t *)dci_pdu)->TPC           = rel8->tpc;
      ((DCI1A_10MHz_FDD_t *)dci_pdu)->harq_pid      = rel8->harq_process;
      ((DCI1A_10MHz_FDD_t *)dci_pdu)->padding       = 0;
      //      printf("FDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
    }
    break;
  case 100:
    if (fp->frame_type == TDD) {
      dci_alloc->dci_length                         = sizeof_DCI1A_20MHz_TDD_1_6_t;
      ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->type      = 1;
      ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->vrb_type  = rel8->virtual_resource_block_assignment_flag;
      ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->mcs       = rel8->mcs_1;
      ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->ndi       = rel8->new_data_indicator_1;
      ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->rballoc   = rel8->resource_block_coding;
      ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->rv        = rel8->redundancy_version_1;
      ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->TPC       = rel8->tpc;
      ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->harq_pid  = rel8->harq_process;
      ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->dai       = rel8->downlink_assignment_index;
      ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->padding   = 0;
      //        printf("TDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
    } else {
      dci_alloc->dci_length                         = sizeof_DCI1A_20MHz_FDD_t;
      ((DCI1A_20MHz_FDD_t *)dci_pdu)->type          = 1;
      ((DCI1A_20MHz_FDD_t *)dci_pdu)->vrb_type      = rel8->virtual_resource_block_assignment_flag;
      ((DCI1A_20MHz_FDD_t *)dci_pdu)->mcs           = rel8->mcs_1;
      ((DCI1A_20MHz_FDD_t *)dci_pdu)->ndi           = rel8->new_data_indicator_1;
      ((DCI1A_20MHz_FDD_t *)dci_pdu)->rballoc       = rel8->resource_block_coding;
      ((DCI1A_20MHz_FDD_t *)dci_pdu)->rv            = rel8->redundancy_version_1;
      ((DCI1A_20MHz_FDD_t *)dci_pdu)->TPC           = rel8->tpc;
      ((DCI1A_20MHz_FDD_t *)dci_pdu)->harq_pid      = rel8->harq_process;
      ((DCI1A_20MHz_FDD_t *)dci_pdu)->padding       = 0;
      //      printf("FDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
    }
    break;
  }

  LOG_I(PHY,"%d.%d: DCI 1A: rnti %x, PDCCH order to do PRACH\n",
        proc->frame_tx, proc->subframe_tx, rel8->rnti);
}

void fill_dci_and_dlsch(PHY_VARS_eNB *eNB,int frame,int subframe,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_alloc,nfapi_dl_config_dci_dl_pdu *pdu)
{
  LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;
  uint8_t *dci_pdu = &dci_alloc->dci_pdu[0];
  nfapi_dl_config_dci_dl_pdu_rel8_t *rel8 = &pdu->dci_dl_pdu_rel8;

  /* check if this is a DCI 1A PDCCH order for RAPROC */
  if (rel8->dci_format == NFAPI_DL_DCI_FORMAT_1A && rel8->rnti_type == 1) {
    int full_rb;
    switch (fp->N_RB_DL) {
    case 6:   full_rb = 63;   break;
    case 25:  full_rb = 511;  break;
    case 50:  full_rb = 2047; break;
    case 100: full_rb = 8191; break;
    default:  abort();
    }
    if (rel8->resource_block_coding == full_rb)
      return fill_pdcch_order(eNB, proc, dci_alloc, pdu);
  }

  LTE_eNB_DLSCH_t *dlsch0=NULL,*dlsch1=NULL;
  LTE_DL_eNB_HARQ_t *dlsch0_harq=NULL,*dlsch1_harq=NULL;
  int beamforming_mode = 0;
  int UE_id=-1;
  int NPRB;
  int TB0_active;
  int TB1_active;
  uint16_t DL_pmi_single=0; // This should be taken from DLSCH parameters for PUSCH precoding
  uint8_t I_mcs = 0;
 
  dci_alloc->firstCCE = rel8->cce_idx;
  dci_alloc->L        = rel8->aggregation_level;
  dci_alloc->rnti     = rel8->rnti;
  dci_alloc->harq_pid = rel8->harq_process;
  dci_alloc->ra_flag  = 0;

  LOG_D(PHY,"NFAPI: SFN/SF:%04d%d proc:TX:[SFN/SF:%04d%d] DCI format %d, nCCE %d, L %d, rnti %x, harq_pid %d\n",
	frame,subframe,proc->frame_tx,proc->subframe_tx,rel8->dci_format,rel8->cce_idx,rel8->aggregation_level,rel8->rnti,rel8->harq_process);
  if ((rel8->rnti_type == 2 ) && (rel8->rnti != SI_RNTI) && (rel8->rnti != P_RNTI)) dci_alloc->ra_flag = 1;

  UE_id = find_dlsch(rel8->rnti,eNB,SEARCH_EXIST_OR_FREE);
  if( (UE_id<0) || (UE_id>=NUMBER_OF_UE_MAX) ){
    LOG_E(PHY,"illegal UE_id found!!! rnti %04x UE_id %d\n",rel8->rnti,UE_id);
    return;
  }
  //AssertFatal(UE_id!=-1,"no free or exiting dlsch_context\n");
  //AssertFatal(UE_id<NUMBER_OF_UE_MAX,"returned UE_id %d >= %d(NUMBER_OF_UE_MAX)\n",UE_id,NUMBER_OF_UE_MAX);
  dlsch0 = eNB->dlsch[UE_id][0];
  dlsch1 = eNB->dlsch[UE_id][1];

    
  beamforming_mode                          = eNB->transmission_mode[(uint8_t)UE_id]<7?0:eNB->transmission_mode[(uint8_t)UE_id];
  dlsch0_harq                               = dlsch0->harq_processes[rel8->harq_process];
  dlsch0_harq->codeword                     = 0;
  dlsch1_harq                               = dlsch1->harq_processes[rel8->harq_process];
  dlsch1_harq->codeword                     = 1;
  dlsch0->subframe_tx[subframe]             = 1;

  LOG_D(PHY,"NFAPI: SFN/SF:%04d%d proc:TX:SFN/SF:%04d%d dlsch0[rnti:%x harq_mask:%04x] dci_pdu[rnti:%x rnti_type:%d harq_process:%d ndi1:%d] dlsch0_harq[round:%d harq_mask:%x ndi:%d]\n", 
      frame,subframe,
      proc->frame_tx,proc->subframe_tx,
      dlsch0->rnti,dlsch0->harq_mask,
      rel8->rnti, rel8->rnti_type, rel8->harq_process, rel8->new_data_indicator_1,
      dlsch0_harq->round, dlsch0->harq_mask, dlsch0_harq->ndi);

  if (dlsch0->rnti != rel8->rnti) { // if rnti of dlsch is not the same as in the config, this is a new entry
    dlsch0_harq->round=0;
    dlsch0->harq_mask=0;
  }
  if ((dlsch0->harq_mask & (1<<rel8->harq_process)) > 0 ) {
    if (rel8->new_data_indicator_1 != dlsch0_harq->ndi)
      dlsch0_harq->round=0;
  }
  else  { // process is inactive, so activate and set round to 0
    dlsch0_harq->round=0;
  }
  dlsch0_harq->ndi = rel8->new_data_indicator_1;

#ifdef PHY_TX_THREAD
  dlsch0->active[subframe]        = 1;
#else
  dlsch0->active        = 1;
#endif
  if (rel8->rnti_type == 2)
      dlsch0_harq->round    = 0;

  LOG_D(PHY,"NFAPI: rel8[rnti %x dci_format %d harq_process %d ndi1 %d rnti type %d] dlsch0[rnti %x harq_mask %x] dlsch0_harq[round %d ndi %d]\n",
      rel8->rnti,rel8->dci_format,rel8->harq_process, rel8->new_data_indicator_1, rel8->rnti_type,
      dlsch0->rnti,dlsch0->harq_mask,
      dlsch0_harq->round,dlsch0_harq->ndi
      );

  switch (rel8->dci_format) {

  case NFAPI_DL_DCI_FORMAT_1A:

      AssertFatal(rel8->resource_block_coding < 8192, "SFN/SF:%04d%d proc:TX:SFN/SF:%04d%d: rel8->resource_block_coding (%p) %u >= 8192 (rnti %x, rnti_type %d, format %d, harq_id %d\n",
                frame,subframe,proc->frame_tx,subframe,
                &rel8->resource_block_coding,rel8->resource_block_coding,rel8->rnti,rel8->rnti_type,rel8->dci_format,rel8->harq_process);
  

    dci_alloc->format     = format1A;

    switch (fp->N_RB_DL) {
    case 6:
      if (fp->frame_type == TDD) {
	dci_alloc->dci_length                         = sizeof_DCI1A_1_5MHz_TDD_1_6_t; 
        ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->type     = 1;
        ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->vrb_type = rel8->virtual_resource_block_assignment_flag;
        ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->mcs      = rel8->mcs_1;
        ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->ndi      = rel8->new_data_indicator_1;
        ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->rballoc  = rel8->resource_block_coding;
        ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->rv       = rel8->redundancy_version_1;
        ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->TPC      = rel8->tpc;
        ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->harq_pid = rel8->harq_process;
        ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->dai      = rel8->downlink_assignment_index;
        ((DCI1A_1_5MHz_TDD_1_6_t *)dci_pdu)->padding  = 0;
	
      } else {
	dci_alloc->dci_length                         = sizeof_DCI1A_1_5MHz_FDD_t; 
	((DCI1A_1_5MHz_FDD_t *)dci_pdu)->type         = 1;
        ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->vrb_type     = rel8->virtual_resource_block_assignment_flag;
        ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->mcs          = rel8->mcs_1;
        ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->ndi          = rel8->new_data_indicator_1;
        ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->rballoc      = rel8->resource_block_coding;
        ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->rv           = rel8->redundancy_version_1;
        ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->TPC          = rel8->tpc;
        ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->harq_pid     = rel8->harq_process;
        ((DCI1A_1_5MHz_FDD_t *)dci_pdu)->padding      = 0;
        //      printf("FDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
      }
      AssertFatal(rel8->virtual_resource_block_assignment_flag==LOCALIZED,"Distributed RB allocation not done yet\n");
      dlsch0_harq->rb_alloc[0]    = localRIV2alloc_LUT6[rel8->resource_block_coding];
      dlsch0_harq->vrb_type           =  rel8->virtual_resource_block_assignment_flag;
      dlsch0_harq->nb_rb          = RIV2nb_rb_LUT6[rel8->resource_block_coding];//NPRB;
      break;
    case 25:
      if (fp->frame_type == TDD) {
	dci_alloc->dci_length                         = sizeof_DCI1A_5MHz_TDD_1_6_t; 
        ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->type       = 1;
        ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->vrb_type   = rel8->virtual_resource_block_assignment_flag;
        ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->mcs        = rel8->mcs_1;
        ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->ndi        = rel8->new_data_indicator_1;
        ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->rballoc    = rel8->resource_block_coding;
        ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->rv         = rel8->redundancy_version_1;
        ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->TPC        = rel8->tpc;
        ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->harq_pid   = rel8->harq_process;
        ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->dai        = rel8->downlink_assignment_index;
        ((DCI1A_5MHz_TDD_1_6_t *)dci_pdu)->padding    = 0;
         //        printf("TDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
      } else {
	dci_alloc->dci_length                         = sizeof_DCI1A_5MHz_FDD_t; 
	((DCI1A_5MHz_FDD_t *)dci_pdu)->type           = 1;
        ((DCI1A_5MHz_FDD_t *)dci_pdu)->vrb_type       = rel8->virtual_resource_block_assignment_flag;
        ((DCI1A_5MHz_FDD_t *)dci_pdu)->mcs            = rel8->mcs_1;
        ((DCI1A_5MHz_FDD_t *)dci_pdu)->ndi            = rel8->new_data_indicator_1;
        ((DCI1A_5MHz_FDD_t *)dci_pdu)->rballoc        = rel8->resource_block_coding;
        ((DCI1A_5MHz_FDD_t *)dci_pdu)->rv             = rel8->redundancy_version_1;
        ((DCI1A_5MHz_FDD_t *)dci_pdu)->TPC            = rel8->tpc;
        ((DCI1A_5MHz_FDD_t *)dci_pdu)->harq_pid       = rel8->harq_process;
        ((DCI1A_5MHz_FDD_t *)dci_pdu)->padding        = 0;
        //      printf("FDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
      }
      AssertFatal(rel8->virtual_resource_block_assignment_flag==LOCALIZED,"Distributed RB allocation not done yet\n");
      dlsch0_harq->rb_alloc[0]    = localRIV2alloc_LUT25[rel8->resource_block_coding];
      dlsch0_harq->vrb_type           =  rel8->virtual_resource_block_assignment_flag;
      dlsch0_harq->nb_rb          = RIV2nb_rb_LUT25[rel8->resource_block_coding];//NPRB;
      break;
    case 50:
      if (fp->frame_type == TDD) {
	dci_alloc->dci_length                         = sizeof_DCI1A_10MHz_TDD_1_6_t; 
        ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->type      = 1;
        ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->vrb_type  = rel8->virtual_resource_block_assignment_flag;
        ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->mcs       = rel8->mcs_1;
        ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->ndi       = rel8->new_data_indicator_1;
        ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->rballoc   = rel8->resource_block_coding;
        ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->rv        = rel8->redundancy_version_1;
        ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->TPC       = rel8->tpc;
        ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->harq_pid  = rel8->harq_process;
        ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->dai       = rel8->downlink_assignment_index;
        ((DCI1A_10MHz_TDD_1_6_t *)dci_pdu)->padding   = 0;
        //        printf("TDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
      } else {
	dci_alloc->dci_length                         = sizeof_DCI1A_10MHz_FDD_t; 
	((DCI1A_10MHz_FDD_t *)dci_pdu)->type          = 1;
        ((DCI1A_10MHz_FDD_t *)dci_pdu)->vrb_type      = rel8->virtual_resource_block_assignment_flag;
        ((DCI1A_10MHz_FDD_t *)dci_pdu)->mcs           = rel8->mcs_1;
        ((DCI1A_10MHz_FDD_t *)dci_pdu)->ndi           = rel8->new_data_indicator_1;
        ((DCI1A_10MHz_FDD_t *)dci_pdu)->rballoc       = rel8->resource_block_coding;
        ((DCI1A_10MHz_FDD_t *)dci_pdu)->rv            = rel8->redundancy_version_1;
        ((DCI1A_10MHz_FDD_t *)dci_pdu)->TPC           = rel8->tpc;
        ((DCI1A_10MHz_FDD_t *)dci_pdu)->harq_pid      = rel8->harq_process;
        ((DCI1A_10MHz_FDD_t *)dci_pdu)->padding       = 0;
	//      printf("FDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
      }
      AssertFatal(rel8->virtual_resource_block_assignment_flag==LOCALIZED,"Distributed RB allocation not done yet\n");
      dlsch0_harq->rb_alloc[0]     = localRIV2alloc_LUT50_0[rel8->resource_block_coding];
      dlsch0_harq->rb_alloc[1]     = localRIV2alloc_LUT50_1[rel8->resource_block_coding];
      dlsch0_harq->vrb_type           =  rel8->virtual_resource_block_assignment_flag;
      dlsch0_harq->nb_rb              = RIV2nb_rb_LUT50[rel8->resource_block_coding];//NPRB;
      break;
    case 100:
      if (fp->frame_type == TDD) {
	dci_alloc->dci_length                         = sizeof_DCI1A_20MHz_TDD_1_6_t; 
        ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->type      = 1;
        ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->vrb_type  = rel8->virtual_resource_block_assignment_flag;
        ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->mcs       = rel8->mcs_1;
        ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->ndi       = rel8->new_data_indicator_1;
        ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->rballoc   = rel8->resource_block_coding;
        ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->rv        = rel8->redundancy_version_1;
        ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->TPC       = rel8->tpc;
        ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->harq_pid  = rel8->harq_process;
        ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->dai       = rel8->downlink_assignment_index;
        ((DCI1A_20MHz_TDD_1_6_t *)dci_pdu)->padding   = 0;
        //        printf("TDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
      } else {
	dci_alloc->dci_length                         = sizeof_DCI1A_20MHz_FDD_t; 
	((DCI1A_20MHz_FDD_t *)dci_pdu)->type          = 1;
        ((DCI1A_20MHz_FDD_t *)dci_pdu)->vrb_type      = rel8->virtual_resource_block_assignment_flag;
        ((DCI1A_20MHz_FDD_t *)dci_pdu)->mcs           = rel8->mcs_1;
        ((DCI1A_20MHz_FDD_t *)dci_pdu)->ndi           = rel8->new_data_indicator_1;
        ((DCI1A_20MHz_FDD_t *)dci_pdu)->rballoc       = rel8->resource_block_coding;
        ((DCI1A_20MHz_FDD_t *)dci_pdu)->rv            = rel8->redundancy_version_1;
        ((DCI1A_20MHz_FDD_t *)dci_pdu)->TPC           = rel8->tpc;
        ((DCI1A_20MHz_FDD_t *)dci_pdu)->harq_pid      = rel8->harq_process;
        ((DCI1A_20MHz_FDD_t *)dci_pdu)->padding       = 0;
	//      printf("FDD 1A: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
      }
      AssertFatal(rel8->virtual_resource_block_assignment_flag==LOCALIZED,"Distributed RB allocation not done yet\n");
      dlsch0_harq->rb_alloc[0]      = localRIV2alloc_LUT100_0[rel8->resource_block_coding];
      dlsch0_harq->rb_alloc[1]      = localRIV2alloc_LUT100_1[rel8->resource_block_coding];
      dlsch0_harq->rb_alloc[2]      = localRIV2alloc_LUT100_2[rel8->resource_block_coding];
      dlsch0_harq->rb_alloc[3]      = localRIV2alloc_LUT100_3[rel8->resource_block_coding];
      dlsch0_harq->vrb_type         =  rel8->virtual_resource_block_assignment_flag;
      dlsch0_harq->nb_rb            = RIV2nb_rb_LUT100[rel8->resource_block_coding];//NPRB;
      break;
    }

    if (rel8->rnti_type == 2 ) {
      // see 36-212 V8.6.0 p. 45
      NPRB      = (rel8->tpc&1)+2;
      // 36-213 sec.7.1.7.2 p.26
      I_mcs     = rel8->mcs_1;
    }
    else {
      NPRB      = dlsch0_harq->nb_rb;
      I_mcs     = get_I_TBS(rel8->mcs_1);
    }
    AssertFatal(NPRB>0,"DCI 1A: NPRB = 0 (rnti %x, rnti type %d, tpc %d, round %d, resource_block_coding %d, harq process %d)\n",rel8->rnti,rel8->rnti_type,rel8->tpc,dlsch0_harq->round,rel8->resource_block_coding,rel8->harq_process);
    dlsch0_harq->rvidx         = rel8->redundancy_version_1;
    dlsch0_harq->Nl            = 1;
    dlsch0_harq->mimo_mode     = (fp->nb_antenna_ports_eNB == 1) ? SISO : ALAMOUTI;
    dlsch0_harq->dl_power_off  = 1;
    
    

    dlsch0_harq->mcs             = rel8->mcs_1;
    dlsch0_harq->Qm              = 2;
    dlsch0_harq->TBS             = TBStable[I_mcs][NPRB-1];
    dlsch0->harq_ids[frame%2][subframe]   = rel8->harq_process;
#ifdef PHY_TX_THREAD
    dlsch0->active[subframe]     = 1;
#else
    dlsch0->active               = 1;
#endif
    dlsch0->rnti                 = rel8->rnti;
    //dlsch0->harq_ids[subframe]   = rel8->harq_process;
    if (dlsch0_harq->round == 0)
      dlsch0_harq->status = ACTIVE;

    dlsch0->harq_mask            |= (1<<rel8->harq_process);

    if (rel8->rnti_type == 1) LOG_I(PHY,"DCI 1A: round %d, mcs %d, rballoc %x, rv %d, rnti %x, harq process %d\n",dlsch0_harq->round,rel8->mcs_1,rel8->resource_block_coding,rel8->redundancy_version_1,rel8->rnti,rel8->harq_process);

    break;
  case NFAPI_DL_DCI_FORMAT_1:

    dci_alloc->format           = format1;
#ifdef PHY_TX_THREAD
    dlsch0->active[subframe]    = 1;
#else
    dlsch0->active              = 1;
#endif

    LOG_D(PHY,"SFN/SF:%04d%d proc:TX:SFN/SF:%04d%d: Programming DLSCH for Format 1 DCI, harq_pid %d\n",frame,subframe,proc->frame_tx,subframe,rel8->harq_process);

    switch (fp->N_RB_DL) {
    case 6:
      if (fp->frame_type == TDD) {
	dci_alloc->dci_length                     = sizeof_DCI1_1_5MHz_TDD_t; 
        ((DCI1_1_5MHz_TDD_t *)dci_pdu)->rah       = rel8->resource_allocation_type;
        ((DCI1_1_5MHz_TDD_t *)dci_pdu)->mcs       = rel8->mcs_1;
        ((DCI1_1_5MHz_TDD_t *)dci_pdu)->ndi       = rel8->new_data_indicator_1;
        ((DCI1_1_5MHz_TDD_t *)dci_pdu)->rballoc   = rel8->resource_block_coding;
        ((DCI1_1_5MHz_TDD_t *)dci_pdu)->rv        = rel8->redundancy_version_1;
        ((DCI1_1_5MHz_TDD_t *)dci_pdu)->TPC       = rel8->tpc;
        ((DCI1_1_5MHz_TDD_t *)dci_pdu)->harq_pid  = rel8->harq_process;
        ((DCI1_1_5MHz_TDD_t *)dci_pdu)->dai       = rel8->downlink_assignment_index;
        ((DCI1_1_5MHz_TDD_t *)dci_pdu)->padding   = 0;
        //        printf("TDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
      } else {
	dci_alloc->dci_length                         = sizeof_DCI1_1_5MHz_FDD_t; 
        ((DCI1_1_5MHz_FDD_t *)dci_pdu)->rah           = rel8->resource_allocation_type;
        ((DCI1_1_5MHz_FDD_t *)dci_pdu)->mcs           = rel8->mcs_1;
        ((DCI1_1_5MHz_FDD_t *)dci_pdu)->ndi       = rel8->new_data_indicator_1;
        ((DCI1_1_5MHz_FDD_t *)dci_pdu)->rballoc       = rel8->resource_block_coding;
        ((DCI1_1_5MHz_FDD_t *)dci_pdu)->rv            = rel8->redundancy_version_1;
        ((DCI1_1_5MHz_FDD_t *)dci_pdu)->TPC           = rel8->tpc;
        ((DCI1_1_5MHz_FDD_t *)dci_pdu)->harq_pid      = rel8->harq_process;
        ((DCI1_1_5MHz_FDD_t *)dci_pdu)->padding       = 0;
        //      printf("FDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
      }
      break;
    case 25:
      if (fp->frame_type == TDD) {
	dci_alloc->dci_length                      = sizeof_DCI1_5MHz_TDD_t; 
        ((DCI1_5MHz_TDD_t *)dci_pdu)->rah      = rel8->resource_allocation_type;
        ((DCI1_5MHz_TDD_t *)dci_pdu)->mcs      = rel8->mcs_1;
        ((DCI1_5MHz_TDD_t *)dci_pdu)->ndi      = rel8->new_data_indicator_1;
        ((DCI1_5MHz_TDD_t *)dci_pdu)->rballoc  = rel8->resource_block_coding;
        ((DCI1_5MHz_TDD_t *)dci_pdu)->rv       = rel8->redundancy_version_1;
        ((DCI1_5MHz_TDD_t *)dci_pdu)->TPC      = rel8->tpc;
        ((DCI1_5MHz_TDD_t *)dci_pdu)->harq_pid = rel8->harq_process;
        ((DCI1_5MHz_TDD_t *)dci_pdu)->dai      = rel8->downlink_assignment_index;
        ((DCI1_5MHz_TDD_t *)dci_pdu)->padding  = 0;
        //        printf("TDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
      } else {
	dci_alloc->dci_length                  = sizeof_DCI1_5MHz_FDD_t; 
        ((DCI1_5MHz_FDD_t *)dci_pdu)->rah      = rel8->resource_allocation_type;
        ((DCI1_5MHz_FDD_t *)dci_pdu)->mcs      = rel8->mcs_1;
        ((DCI1_5MHz_FDD_t *)dci_pdu)->ndi      = rel8->new_data_indicator_1;
        ((DCI1_5MHz_FDD_t *)dci_pdu)->rballoc  = rel8->resource_block_coding;
        ((DCI1_5MHz_FDD_t *)dci_pdu)->rv       = rel8->redundancy_version_1;
        ((DCI1_5MHz_FDD_t *)dci_pdu)->TPC      = rel8->tpc;
        ((DCI1_5MHz_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process;
        ((DCI1_5MHz_FDD_t *)dci_pdu)->padding  = 0;
        //      printf("FDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
      }
      break;
    case 50:
      if (fp->frame_type == TDD) {
	dci_alloc->dci_length                       = sizeof_DCI1_10MHz_TDD_t; 
        ((DCI1_10MHz_TDD_t *)dci_pdu)->rah      = rel8->resource_allocation_type;
        ((DCI1_10MHz_TDD_t *)dci_pdu)->mcs      = rel8->mcs_1;
        ((DCI1_10MHz_TDD_t *)dci_pdu)->ndi      = rel8->new_data_indicator_1;
        ((DCI1_10MHz_TDD_t *)dci_pdu)->rballoc  = rel8->resource_block_coding;
        ((DCI1_10MHz_TDD_t *)dci_pdu)->rv       = rel8->redundancy_version_1;
        ((DCI1_10MHz_TDD_t *)dci_pdu)->TPC      = rel8->tpc;
        ((DCI1_10MHz_TDD_t *)dci_pdu)->harq_pid = rel8->harq_process;
        ((DCI1_10MHz_TDD_t *)dci_pdu)->dai      = rel8->downlink_assignment_index;
        ((DCI1_10MHz_TDD_t *)dci_pdu)->padding  = 0;
        //        printf("TDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
      } else {
	dci_alloc->dci_length                   = sizeof_DCI1_10MHz_FDD_t; 
        ((DCI1_10MHz_FDD_t *)dci_pdu)->rah      = rel8->resource_allocation_type;
        ((DCI1_10MHz_FDD_t *)dci_pdu)->mcs      = rel8->mcs_1;
        ((DCI1_10MHz_FDD_t *)dci_pdu)->ndi      = rel8->new_data_indicator_1;
        ((DCI1_10MHz_FDD_t *)dci_pdu)->rballoc  = rel8->resource_block_coding;
        ((DCI1_10MHz_FDD_t *)dci_pdu)->rv       = rel8->redundancy_version_1;
        ((DCI1_10MHz_FDD_t *)dci_pdu)->TPC      = rel8->tpc;
        ((DCI1_10MHz_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process;
        ((DCI1_10MHz_FDD_t *)dci_pdu)->padding  = 0;
      }
      break;
    case 100:
      if (fp->frame_type == TDD) {
	dci_alloc->dci_length                       = sizeof_DCI1_20MHz_TDD_t; 
        ((DCI1_20MHz_TDD_t *)dci_pdu)->rah      = rel8->resource_allocation_type;
        ((DCI1_20MHz_TDD_t *)dci_pdu)->mcs      = rel8->mcs_1;
        ((DCI1_20MHz_TDD_t *)dci_pdu)->ndi      = rel8->new_data_indicator_1;
        ((DCI1_20MHz_TDD_t *)dci_pdu)->rballoc  = rel8->resource_block_coding;
        ((DCI1_20MHz_TDD_t *)dci_pdu)->rv       = rel8->redundancy_version_1;
        ((DCI1_20MHz_TDD_t *)dci_pdu)->TPC      = rel8->tpc;
        ((DCI1_20MHz_TDD_t *)dci_pdu)->harq_pid = rel8->harq_process;
        ((DCI1_20MHz_TDD_t *)dci_pdu)->dai      = rel8->downlink_assignment_index;
        ((DCI1_20MHz_TDD_t *)dci_pdu)->padding  = 0;
        //        printf("TDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
      } else {
	dci_alloc->dci_length                   = sizeof_DCI1_20MHz_FDD_t; 
        ((DCI1_20MHz_FDD_t *)dci_pdu)->rah      = rel8->resource_allocation_type;
        ((DCI1_20MHz_FDD_t *)dci_pdu)->mcs      = rel8->mcs_1;
        ((DCI1_20MHz_FDD_t *)dci_pdu)->ndi      = rel8->new_data_indicator_1;
        ((DCI1_20MHz_FDD_t *)dci_pdu)->rballoc  = rel8->resource_block_coding;
        ((DCI1_20MHz_FDD_t *)dci_pdu)->rv       = rel8->redundancy_version_1;
        ((DCI1_20MHz_FDD_t *)dci_pdu)->TPC      = rel8->tpc;
        ((DCI1_20MHz_FDD_t *)dci_pdu)->harq_pid = rel8->harq_process;
        ((DCI1_20MHz_FDD_t *)dci_pdu)->padding  = 0;
      }
      break;
    }

    AssertFatal(rel8->harq_process<8,"Format 1: harq_pid=%d >= 8\n", rel8->harq_process);


    dlsch0_harq = dlsch0->harq_processes[rel8->harq_process];
    dlsch0_harq->codeword=0;

    // printf("DCI: Setting subframe_tx for subframe %d\n",subframe);
    dlsch0->subframe_tx[subframe] = 1;

    conv_rballoc(rel8->resource_allocation_type,
                 rel8->resource_block_coding,
		 fp->N_RB_DL,
                 dlsch0_harq->rb_alloc);

    dlsch0_harq->nb_rb = conv_nprb(rel8->resource_allocation_type,
                                   rel8->resource_block_coding,
                                   fp->N_RB_DL);

    NPRB      = dlsch0_harq->nb_rb;


    AssertFatal(NPRB>0,"NPRB == 0\n");

    dlsch0_harq->rvidx       = rel8->redundancy_version_1;

    dlsch0_harq->Nl          = 1;
    //    dlsch[0]->layer_index = 0;
    if (beamforming_mode == 0)
      dlsch0_harq->mimo_mode = (fp->nb_antenna_ports_eNB == 1) ? SISO : ALAMOUTI;
    else if (beamforming_mode == 7)
      dlsch0_harq->mimo_mode = TM7;
    else
      LOG_E(PHY,"Invalid beamforming mode %dL\n", beamforming_mode);

    dlsch0_harq->dl_power_off = 1;

#ifdef PHY_TX_THREAD
    dlsch0->active[subframe] = 1;
#else
    dlsch0->active = 1;
#endif



    if (dlsch0_harq->round == 0) {
      dlsch0_harq->status = ACTIVE;

      //            printf("Setting DLSCH process %d to ACTIVE\n",rel8->harq_process);
      // MCS and TBS don't change across HARQ rounds
      dlsch0_harq->mcs         = rel8->mcs_1;
      dlsch0_harq->Qm          = get_Qm(rel8->mcs_1);
      dlsch0_harq->TBS         = TBStable[get_I_TBS(dlsch0_harq->mcs)][NPRB-1];

    }

    LOG_D(PHY,"DCI: Set harq_ids[%d] to %d (%p)\n",subframe,rel8->harq_process,dlsch0);
    dlsch0->harq_ids[frame%2][subframe] = rel8->harq_process;

    dlsch0->harq_mask          |= (1<<rel8->harq_process);


    dlsch0->rnti = rel8->rnti;


    break;
  case NFAPI_DL_DCI_FORMAT_2A:

    dci_alloc->format     = format2A;
    switch (fp->N_RB_DL) {
    case 6:
      if (fp->frame_type == TDD) {
	dci_alloc->dci_length                         = sizeof_DCI2A_1_5MHz_2A_TDD_t; 
        ((DCI2A_1_5MHz_2A_TDD_t *)dci_pdu)->rah      = rel8->resource_allocation_type;
        ((DCI2A_1_5MHz_2A_TDD_t *)dci_pdu)->mcs1     = rel8->mcs_1;
        ((DCI2A_1_5MHz_2A_TDD_t *)dci_pdu)->mcs2     = rel8->mcs_2;
        ((DCI2A_1_5MHz_2A_TDD_t *)dci_pdu)->ndi1     = rel8->new_data_indicator_1;
        ((DCI2A_1_5MHz_2A_TDD_t *)dci_pdu)->ndi2     = rel8->new_data_indicator_2;
        ((DCI2A_1_5MHz_2A_TDD_t *)dci_pdu)->rballoc  = rel8->resource_block_coding;
        ((DCI2A_1_5MHz_2A_TDD_t *)dci_pdu)->rv1      = rel8->redundancy_version_1;
        ((DCI2A_1_5MHz_2A_TDD_t *)dci_pdu)->rv2      = rel8->redundancy_version_2;
        ((DCI2A_1_5MHz_2A_TDD_t *)dci_pdu)->TPC      = rel8->tpc;
        ((DCI2A_1_5MHz_2A_TDD_t *)dci_pdu)->harq_pid = rel8->harq_process;
	((DCI2A_1_5MHz_2A_TDD_t *)dci_pdu)->tb_swap  = rel8->transport_block_to_codeword_swap_flag;
        ((DCI2A_1_5MHz_2A_TDD_t *)dci_pdu)->dai      = rel8->downlink_assignment_index;
        /* there is no padding in this structure, it is exactly 32 bits */
        //        printf("TDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
      } else {
	dci_alloc->dci_length                         = sizeof_DCI2A_1_5MHz_2A_FDD_t; 
        ((DCI2A_1_5MHz_2A_FDD_t *)dci_pdu)->rah          = rel8->resource_allocation_type;
        ((DCI2A_1_5MHz_2A_FDD_t *)dci_pdu)->mcs1         = rel8->mcs_1;
        ((DCI2A_1_5MHz_2A_FDD_t *)dci_pdu)->mcs2         = rel8->mcs_2;
        ((DCI2A_1_5MHz_2A_FDD_t *)dci_pdu)->ndi1         = rel8->new_data_indicator_1;
        ((DCI2A_1_5MHz_2A_FDD_t *)dci_pdu)->ndi2         = rel8->new_data_indicator_2;
        ((DCI2A_1_5MHz_2A_FDD_t *)dci_pdu)->rballoc      = rel8->resource_block_coding;
        ((DCI2A_1_5MHz_2A_FDD_t *)dci_pdu)->rv1          = rel8->redundancy_version_1;
        ((DCI2A_1_5MHz_2A_FDD_t *)dci_pdu)->rv2          = rel8->redundancy_version_2;
        ((DCI2A_1_5MHz_2A_FDD_t *)dci_pdu)->TPC          = rel8->tpc;
        ((DCI2A_1_5MHz_2A_FDD_t *)dci_pdu)->harq_pid     = rel8->harq_process;
	((DCI2A_1_5MHz_2A_FDD_t *)dci_pdu)->tb_swap      = rel8->transport_block_to_codeword_swap_flag;
	((DCI2A_1_5MHz_2A_FDD_t *)dci_pdu)->padding      = 0;
        //      printf("FDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
      }
      break;
    case 25:
      if (fp->frame_type == TDD) {
	dci_alloc->dci_length                        = sizeof_DCI2A_5MHz_2A_TDD_t; 
        ((DCI2A_5MHz_2A_TDD_t *)dci_pdu)->rah       = rel8->resource_allocation_type;
        ((DCI2A_5MHz_2A_TDD_t *)dci_pdu)->mcs1      = rel8->mcs_1;
        ((DCI2A_5MHz_2A_TDD_t *)dci_pdu)->mcs2      = rel8->mcs_2;
        ((DCI2A_5MHz_2A_TDD_t *)dci_pdu)->ndi1      = rel8->new_data_indicator_1;
        ((DCI2A_5MHz_2A_TDD_t *)dci_pdu)->ndi2      = rel8->new_data_indicator_2;
        ((DCI2A_5MHz_2A_TDD_t *)dci_pdu)->rballoc   = rel8->resource_block_coding;
        ((DCI2A_5MHz_2A_TDD_t *)dci_pdu)->rv1       = rel8->redundancy_version_1;
        ((DCI2A_5MHz_2A_TDD_t *)dci_pdu)->rv2       = rel8->redundancy_version_2;
        ((DCI2A_5MHz_2A_TDD_t *)dci_pdu)->TPC       = rel8->tpc;
        ((DCI2A_5MHz_2A_TDD_t *)dci_pdu)->harq_pid  = rel8->harq_process;
	((DCI2A_5MHz_2A_TDD_t *)dci_pdu)->tb_swap   = rel8->transport_block_to_codeword_swap_flag;
        ((DCI2A_5MHz_2A_TDD_t *)dci_pdu)->dai       = rel8->downlink_assignment_index;
        ((DCI2A_5MHz_2A_TDD_t *)dci_pdu)->padding   = 0;
        //        printf("TDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
      } else {
	dci_alloc->dci_length                           = sizeof_DCI2A_5MHz_2A_FDD_t; 
        ((DCI2A_5MHz_2A_FDD_t *)dci_pdu)->rah           = rel8->resource_allocation_type;
        ((DCI2A_5MHz_2A_FDD_t *)dci_pdu)->mcs1          = rel8->mcs_1;
        ((DCI2A_5MHz_2A_FDD_t *)dci_pdu)->mcs2          = rel8->mcs_2;
        ((DCI2A_5MHz_2A_FDD_t *)dci_pdu)->ndi1          = rel8->new_data_indicator_1;
        ((DCI2A_5MHz_2A_FDD_t *)dci_pdu)->ndi2          = rel8->new_data_indicator_2;
        ((DCI2A_5MHz_2A_FDD_t *)dci_pdu)->rballoc       = rel8->resource_block_coding;
        ((DCI2A_5MHz_2A_FDD_t *)dci_pdu)->rv1           = rel8->redundancy_version_1;
        ((DCI2A_5MHz_2A_FDD_t *)dci_pdu)->rv2           = rel8->redundancy_version_2;
        ((DCI2A_5MHz_2A_FDD_t *)dci_pdu)->TPC           = rel8->tpc;
        ((DCI2A_5MHz_2A_FDD_t *)dci_pdu)->harq_pid      = rel8->harq_process;
	((DCI2A_5MHz_2A_FDD_t *)dci_pdu)->tb_swap       = rel8->transport_block_to_codeword_swap_flag;	
	((DCI2A_5MHz_2A_FDD_t *)dci_pdu)->padding       = 0;
        //      printf("FDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
      }
      break;
    case 50:
      if (fp->frame_type == TDD) {
	dci_alloc->dci_length                        = sizeof_DCI2A_10MHz_2A_TDD_t; 
        ((DCI2A_10MHz_2A_TDD_t *)dci_pdu)->rah      = rel8->resource_allocation_type;
        ((DCI2A_10MHz_2A_TDD_t *)dci_pdu)->mcs1     = rel8->mcs_1;
        ((DCI2A_10MHz_2A_TDD_t *)dci_pdu)->mcs2     = rel8->mcs_2;
        ((DCI2A_10MHz_2A_TDD_t *)dci_pdu)->ndi1     = rel8->new_data_indicator_1;
        ((DCI2A_10MHz_2A_TDD_t *)dci_pdu)->ndi2     = rel8->new_data_indicator_2;
        ((DCI2A_10MHz_2A_TDD_t *)dci_pdu)->rballoc  = rel8->resource_block_coding;
        ((DCI2A_10MHz_2A_TDD_t *)dci_pdu)->rv1      = rel8->redundancy_version_1;
        ((DCI2A_10MHz_2A_TDD_t *)dci_pdu)->rv2      = rel8->redundancy_version_2;
        ((DCI2A_10MHz_2A_TDD_t *)dci_pdu)->TPC      = rel8->tpc;
        ((DCI2A_10MHz_2A_TDD_t *)dci_pdu)->harq_pid = rel8->harq_process;
	((DCI2A_10MHz_2A_TDD_t *)dci_pdu)->tb_swap  = rel8->transport_block_to_codeword_swap_flag;
        ((DCI2A_10MHz_2A_TDD_t *)dci_pdu)->dai      = rel8->downlink_assignment_index;
        ((DCI2A_10MHz_2A_TDD_t *)dci_pdu)->padding  = 0;
        //        printf("TDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
      } else {
	dci_alloc->dci_length                        = sizeof_DCI2A_10MHz_2A_FDD_t; 
        ((DCI2A_10MHz_2A_FDD_t *)dci_pdu)->rah       = rel8->resource_allocation_type;
        ((DCI2A_10MHz_2A_FDD_t *)dci_pdu)->mcs1      = rel8->mcs_1;
        ((DCI2A_10MHz_2A_FDD_t *)dci_pdu)->mcs2      = rel8->mcs_2;
        ((DCI2A_10MHz_2A_FDD_t *)dci_pdu)->ndi1      = rel8->new_data_indicator_1;
        ((DCI2A_10MHz_2A_FDD_t *)dci_pdu)->ndi2      = rel8->new_data_indicator_2;
        ((DCI2A_10MHz_2A_FDD_t *)dci_pdu)->rballoc   = rel8->resource_block_coding;
        ((DCI2A_10MHz_2A_FDD_t *)dci_pdu)->rv1       = rel8->redundancy_version_1;
        ((DCI2A_10MHz_2A_FDD_t *)dci_pdu)->rv2       = rel8->redundancy_version_2;
        ((DCI2A_10MHz_2A_FDD_t *)dci_pdu)->TPC       = rel8->tpc;
        ((DCI2A_10MHz_2A_FDD_t *)dci_pdu)->harq_pid  = rel8->harq_process;
	((DCI2A_10MHz_2A_FDD_t *)dci_pdu)->tb_swap   = rel8->transport_block_to_codeword_swap_flag;
	((DCI2A_10MHz_2A_FDD_t *)dci_pdu)->padding   = 0;
      }
      break;
    case 100:
      if (fp->frame_type == TDD) {
	dci_alloc->dci_length                        = sizeof_DCI2A_20MHz_2A_TDD_t; 
        ((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->rah       = rel8->resource_allocation_type;
        ((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->mcs1      = rel8->mcs_1;
        ((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->mcs2      = rel8->mcs_2;
        ((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->ndi1      = rel8->new_data_indicator_1;
        ((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->ndi2      = rel8->new_data_indicator_2;
        ((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->rballoc   = rel8->resource_block_coding;
        ((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->rv1       = rel8->redundancy_version_1;
        ((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->rv2       = rel8->redundancy_version_2;
        ((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->TPC       = rel8->tpc;
        ((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->harq_pid  = rel8->harq_process;
	((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->tb_swap   = rel8->transport_block_to_codeword_swap_flag;
        ((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->dai       = rel8->downlink_assignment_index;
        ((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->padding   = 0;
        //        printf("TDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
      } else {
	dci_alloc->dci_length                           = sizeof_DCI2A_20MHz_2A_FDD_t; 
        ((DCI2A_20MHz_2A_FDD_t *)dci_pdu)->rah          = rel8->resource_allocation_type;
        ((DCI2A_20MHz_2A_FDD_t *)dci_pdu)->mcs1         = rel8->mcs_1;
        ((DCI2A_20MHz_2A_FDD_t *)dci_pdu)->mcs2         = rel8->mcs_2;
        ((DCI2A_20MHz_2A_FDD_t *)dci_pdu)->ndi1         = rel8->new_data_indicator_1;
        ((DCI2A_20MHz_2A_FDD_t *)dci_pdu)->ndi2         = rel8->new_data_indicator_2;
        ((DCI2A_20MHz_2A_FDD_t *)dci_pdu)->rballoc      = rel8->resource_block_coding;
        ((DCI2A_20MHz_2A_FDD_t *)dci_pdu)->rv1          = rel8->redundancy_version_1;
        ((DCI2A_20MHz_2A_FDD_t *)dci_pdu)->rv2          = rel8->redundancy_version_2;
        ((DCI2A_20MHz_2A_FDD_t *)dci_pdu)->TPC          = rel8->tpc;
        ((DCI2A_20MHz_2A_FDD_t *)dci_pdu)->harq_pid     = rel8->harq_process;
	((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->tb_swap      = rel8->transport_block_to_codeword_swap_flag;
	((DCI2A_20MHz_2A_TDD_t *)dci_pdu)->padding      = 0;
      }
      break;

    }

    AssertFatal(rel8->harq_process<8,"Format 2_2A: harq_pid=%d >= 8\n", rel8->harq_process);


    // Flip the TB to codeword mapping as described in 5.3.3.1.5 of 36-212 V11.3.0
    // note that we must set tbswap=0 in eNB scheduler if one TB is deactivated

    // This must be set as in TM4, does not work properly now.
    if (rel8->transport_block_to_codeword_swap_flag == 1) {
      dlsch0 = eNB->dlsch[UE_id][1];
      dlsch1 = eNB->dlsch[UE_id][0];
    }

    dlsch0_harq = dlsch0->harq_processes[rel8->harq_process];
    dlsch1_harq = dlsch1->harq_processes[rel8->harq_process];

    dlsch0->subframe_tx[subframe] = 1;

    dlsch0->harq_ids[frame%2][subframe] = rel8->harq_process;
    dlsch1->harq_ids[frame%2][subframe] = rel8->harq_process;
    //    printf("Setting DLSCH harq id %d to subframe %d\n",harq_pid,subframe);


    conv_rballoc(rel8->resource_allocation_type,
                 rel8->resource_block_coding,
                 fp->N_RB_DL,
                 dlsch0_harq->rb_alloc);

    dlsch1_harq->rb_alloc[0]                         = dlsch0_harq->rb_alloc[0];
    dlsch0_harq->nb_rb                               = conv_nprb(rel8->resource_allocation_type,
								 rel8->resource_block_coding,
								 fp->N_RB_DL);
    dlsch1_harq->nb_rb                               = dlsch0_harq->nb_rb;

    AssertFatal(dlsch0_harq->nb_rb > 0,"nb_rb=0\n");

    dlsch0_harq->mcs       = rel8->mcs_1;
    dlsch1_harq->mcs       = rel8->mcs_2;
    dlsch0_harq->Qm        = get_Qm(rel8->mcs_1);
    dlsch1_harq->Qm        = get_Qm(rel8->mcs_2);
    dlsch0_harq->rvidx     = rel8->redundancy_version_1;
    dlsch1_harq->rvidx     = rel8->redundancy_version_2;

    // assume both TBs are active
    dlsch0_harq->Nl        = 1;
    dlsch1_harq->Nl        = 1;
#ifdef PHY_TX_THREAD
    dlsch0->active[subframe] = 1;
    dlsch1->active[subframe] = 1;
#else
    dlsch0->active = 1;
    dlsch1->active = 1;
#endif
    dlsch0->harq_mask                         |= (1<<rel8->harq_process);
    dlsch1->harq_mask                         |= (1<<rel8->harq_process);

    // check if either TB is disabled (see 36-213 V11.3 Section )
    if ((dlsch0_harq->rvidx == 1) && (dlsch0_harq->mcs == 0)) {
#ifdef PHY_TX_THREAD
      dlsch0->active[subframe] = 0;
#else
      dlsch0->active = 0;
#endif
      dlsch0->harq_mask                         &= ~(1<<rel8->harq_process);
    }

    if ((dlsch1_harq->rvidx == 1) && (dlsch1_harq->mcs == 0)) {
#ifdef PHY_TX_THREAD
      dlsch1->active[subframe]= 0;
#else
      dlsch1->active = 0;
#endif
      dlsch1->harq_mask                         &= ~(1<<rel8->harq_process);
    }

   // dlsch0_harq->dl_power_off = 0;
   // dlsch1_harq->dl_power_off = 0;


    if (fp->nb_antenna_ports_eNB == 2) {
      dlsch0_harq->TBS         = TBStable[get_I_TBS(dlsch0_harq->mcs)][dlsch0_harq->nb_rb-1];
      dlsch1_harq->TBS         = TBStable[get_I_TBS(dlsch1_harq->mcs)][dlsch0_harq->nb_rb-1];

#ifdef PHY_TX_THREAD
      if ((dlsch0->active[subframe]==1) && (dlsch1->active[subframe]==1)) {
#else
      if ((dlsch0->active==1) && (dlsch1->active==1)) {
#endif
        dlsch0_harq->mimo_mode = LARGE_CDD;
        dlsch1_harq->mimo_mode = LARGE_CDD;
        dlsch0_harq->dl_power_off = 1;
        dlsch1_harq->dl_power_off = 1;
      } else {
        dlsch0_harq->mimo_mode   = ALAMOUTI;
        dlsch1_harq->mimo_mode   = ALAMOUTI;
      }
    } else if (fp->nb_antenna_ports_eNB == 4) { // 4 antenna case
#ifdef PHY_TX_THREAD
      if ((dlsch0->active[subframe]==1) && (dlsch1->active[subframe]==1)) {
#else
      if ((dlsch0->active==1) && (dlsch1->active==1)) {
#endif
        switch (rel8->precoding_information) {
        case 0: // one layer per transport block
          dlsch0_harq->mimo_mode   = LARGE_CDD;
          dlsch1_harq->mimo_mode   = LARGE_CDD;
          dlsch0_harq->TBS         = TBStable[get_I_TBS(dlsch0_harq->mcs)][dlsch0_harq->nb_rb-1];
          dlsch0_harq->TBS         = TBStable[get_I_TBS(dlsch0_harq->mcs)][dlsch0_harq->nb_rb-1];
          dlsch0_harq->dl_power_off = 1;
          dlsch1_harq->dl_power_off = 1;
          break;

        case 1: // one-layers on TB 0, two on TB 1
          dlsch0_harq->mimo_mode   = LARGE_CDD;
          dlsch1_harq->mimo_mode   = LARGE_CDD;
          dlsch1_harq->Nl          = 2;
          dlsch1_harq->TBS         = TBStable[get_I_TBS(dlsch1_harq->mcs)][(dlsch1_harq->nb_rb<<1)-1];
          dlsch0_harq->dl_power_off = 1;
          dlsch1_harq->dl_power_off = 1;
          break;

        case 2: // two-layers on TB 0, two on TB 1
          dlsch0_harq->mimo_mode   = LARGE_CDD;
          dlsch1_harq->mimo_mode   = LARGE_CDD;
          dlsch0_harq->Nl          = 2;
          dlsch0_harq->dl_power_off = 1;
          dlsch1_harq->dl_power_off = 1;

          if (fp->N_RB_DL <= 56) {
            dlsch0_harq->TBS         = TBStable[get_I_TBS(dlsch0_harq->mcs)][(dlsch0_harq->nb_rb<<1)-1];
            dlsch1_harq->TBS         = TBStable[get_I_TBS(dlsch1_harq->mcs)][(dlsch1_harq->nb_rb<<1)-1];
          } else {
            LOG_E(PHY,"Add implementation of Table 7.1.7.2.2-1 for two-layer TBS conversion with N_RB_DL > 56\n");
          }

          break;

        case 3: //
          LOG_E(PHY,"Illegal value (3) for TPMI in Format 2A DCI\n");
          break;
        }
#ifdef PHY_TX_THREAD
      } else if (dlsch0->active[subframe] == 1) {
#else
      } else if (dlsch0->active == 1) {
#endif
        switch (rel8->precoding_information) {
        case 0: // one layer per transport block
          dlsch0_harq->mimo_mode   = ALAMOUTI;
          dlsch1_harq->mimo_mode   = ALAMOUTI;
          dlsch0_harq->TBS         = TBStable[get_I_TBS(dlsch0_harq->mcs)][dlsch0_harq->nb_rb-1];
          break;

        case 1: // two-layers on TB 0
          dlsch0_harq->mimo_mode   = LARGE_CDD;
          dlsch0_harq->Nl          = 2;
          dlsch0_harq->dl_power_off = 1;
          dlsch0_harq->TBS         = TBStable[get_I_TBS(dlsch0_harq->mcs)][(dlsch0_harq->nb_rb<<1)-1];
          break;

        case 2: // two-layers on TB 0, two on TB 1
        case 3: //
          LOG_E(PHY,"Illegal value %d for TPMI in Format 2A DCI with one transport block enabled\n",rel8->precoding_information);
          break;
        }
#ifdef PHY_TX_THREAD
      } else if (dlsch1->active[subframe] == 1) {
#else
      } else if (dlsch1->active == 1) {
#endif
        switch (rel8->precoding_information) {
        case 0: // one layer per transport block
          dlsch0_harq->mimo_mode   = ALAMOUTI;
          dlsch1_harq->mimo_mode   = ALAMOUTI;
          dlsch1_harq->TBS         = TBStable[get_I_TBS(dlsch1_harq->mcs)][dlsch1_harq->nb_rb-1];
          break;

        case 1: // two-layers on TB 0
          dlsch1_harq->mimo_mode   = LARGE_CDD;
          dlsch1_harq->Nl          = 2;
          dlsch1_harq->dl_power_off = 1;
          dlsch1_harq->TBS         = TBStable[get_I_TBS(dlsch1_harq->mcs)][(dlsch1_harq->nb_rb<<1)-1];
          break;

        case 2: // two-layers on TB 0, two on TB 1
        case 3: //
          LOG_E(PHY,"Illegal value %d for TPMI in Format 2A DCI with one transport block enabled\n",rel8->precoding_information);
          break;
        }
      }
    } else {
      LOG_E(PHY,"Illegal number of antennas for eNB %d\n",fp->nb_antenna_ports_eNB);
    }

    // reset HARQ process if this is the first transmission
#ifdef PHY_TX_THREAD
    if ((dlsch0->active[subframe]==1) && (dlsch0_harq->round == 0))
#else
    if ((dlsch0->active==1) && (dlsch0_harq->round == 0))
#endif
      dlsch0_harq->status = ACTIVE;

#ifdef PHY_TX_THREAD
    if ((dlsch1->active[subframe]==1) && (dlsch1_harq->round == 0))
#else
    if ((dlsch1->active==1) && (dlsch1_harq->round == 0))
#endif
      dlsch1_harq->status = ACTIVE;

    dlsch0->rnti = rel8->rnti;
    dlsch1->rnti = rel8->rnti;


    break;
      
  case NFAPI_DL_DCI_FORMAT_2:

    dci_alloc->format     = format2;
    switch (fp->N_RB_DL) {
    case 6:
      if (fp->frame_type == TDD) {
	dci_alloc->dci_length                       = sizeof_DCI2_1_5MHz_2A_TDD_t; 
        ((DCI2_1_5MHz_2A_TDD_t *)dci_pdu)->mcs1     = rel8->mcs_1;
        ((DCI2_1_5MHz_2A_TDD_t *)dci_pdu)->mcs2     = rel8->mcs_2;
        ((DCI2_1_5MHz_2A_TDD_t *)dci_pdu)->ndi1     = rel8->new_data_indicator_1;
        ((DCI2_1_5MHz_2A_TDD_t *)dci_pdu)->ndi2     = rel8->new_data_indicator_2;
        ((DCI2_1_5MHz_2A_TDD_t *)dci_pdu)->rballoc  = rel8->resource_block_coding;
        ((DCI2_1_5MHz_2A_TDD_t *)dci_pdu)->rv1      = rel8->redundancy_version_1;
        ((DCI2_1_5MHz_2A_TDD_t *)dci_pdu)->rv2      = rel8->redundancy_version_2;
        ((DCI2_1_5MHz_2A_TDD_t *)dci_pdu)->TPC      = rel8->tpc;
        ((DCI2_1_5MHz_2A_TDD_t *)dci_pdu)->harq_pid = rel8->harq_process;
	((DCI2_1_5MHz_2A_TDD_t *)dci_pdu)->tb_swap  = rel8->transport_block_to_codeword_swap_flag;
        ((DCI2_1_5MHz_2A_TDD_t *)dci_pdu)->dai      = rel8->downlink_assignment_index;
        ((DCI2_1_5MHz_2A_TDD_t *)dci_pdu)->tpmi     = rel8->precoding_information;
        ((DCI2_1_5MHz_2A_TDD_t *)dci_pdu)->padding  = 0;
        //        printf("TDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
      } else {
	dci_alloc->dci_length                         = sizeof_DCI2_1_5MHz_2A_FDD_t; 
        ((DCI2_1_5MHz_2A_FDD_t *)dci_pdu)->mcs1         = rel8->mcs_1;
        ((DCI2_1_5MHz_2A_FDD_t *)dci_pdu)->mcs2         = rel8->mcs_2;
        ((DCI2_1_5MHz_2A_FDD_t *)dci_pdu)->ndi1         = rel8->new_data_indicator_1;
        ((DCI2_1_5MHz_2A_FDD_t *)dci_pdu)->ndi2         = rel8->new_data_indicator_2;
        ((DCI2_1_5MHz_2A_FDD_t *)dci_pdu)->rballoc      = rel8->resource_block_coding;
        ((DCI2_1_5MHz_2A_FDD_t *)dci_pdu)->rv1          = rel8->redundancy_version_1;
        ((DCI2_1_5MHz_2A_FDD_t *)dci_pdu)->rv2          = rel8->redundancy_version_2;
        ((DCI2_1_5MHz_2A_FDD_t *)dci_pdu)->TPC          = rel8->tpc;
        ((DCI2_1_5MHz_2A_FDD_t *)dci_pdu)->harq_pid     = rel8->harq_process;
	((DCI2_1_5MHz_2A_FDD_t *)dci_pdu)->tb_swap      = rel8->transport_block_to_codeword_swap_flag;
        ((DCI2_1_5MHz_2A_FDD_t *)dci_pdu)->tpmi         = rel8->precoding_information;
        ((DCI2_1_5MHz_2A_FDD_t *)dci_pdu)->padding      = 0;
        //      printf("FDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
      }
      break;
    case 25:
      if (fp->frame_type == TDD) {
	dci_alloc->dci_length                        = sizeof_DCI2_5MHz_2A_TDD_t; 
        ((DCI2_5MHz_2A_TDD_t *)dci_pdu)->rah       = rel8->resource_allocation_type;
        ((DCI2_5MHz_2A_TDD_t *)dci_pdu)->mcs1      = rel8->mcs_1;
        ((DCI2_5MHz_2A_TDD_t *)dci_pdu)->mcs2      = rel8->mcs_2;
        ((DCI2_5MHz_2A_TDD_t *)dci_pdu)->ndi1      = rel8->new_data_indicator_1;
        ((DCI2_5MHz_2A_TDD_t *)dci_pdu)->ndi2      = rel8->new_data_indicator_2;
        ((DCI2_5MHz_2A_TDD_t *)dci_pdu)->rballoc   = rel8->resource_block_coding;
        ((DCI2_5MHz_2A_TDD_t *)dci_pdu)->rv1       = rel8->redundancy_version_1;
        ((DCI2_5MHz_2A_TDD_t *)dci_pdu)->rv2       = rel8->redundancy_version_2;
        ((DCI2_5MHz_2A_TDD_t *)dci_pdu)->TPC       = rel8->tpc;
        ((DCI2_5MHz_2A_TDD_t *)dci_pdu)->harq_pid  = rel8->harq_process;
	((DCI2_5MHz_2A_TDD_t *)dci_pdu)->tb_swap   = rel8->transport_block_to_codeword_swap_flag;	
        ((DCI2_5MHz_2A_TDD_t *)dci_pdu)->dai       = rel8->downlink_assignment_index;	
        ((DCI2_5MHz_2A_TDD_t *)dci_pdu)->tpmi      = rel8->precoding_information;
        ((DCI2_5MHz_2A_TDD_t *)dci_pdu)->padding   = 0;
        //        printf("TDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
      } else {
	dci_alloc->dci_length                           = sizeof_DCI2_5MHz_2A_FDD_t; 
        ((DCI2_5MHz_2A_FDD_t *)dci_pdu)->rah           = rel8->resource_allocation_type;
        ((DCI2_5MHz_2A_FDD_t *)dci_pdu)->mcs1          = rel8->mcs_1;
        ((DCI2_5MHz_2A_FDD_t *)dci_pdu)->mcs2          = rel8->mcs_2;
        ((DCI2_5MHz_2A_FDD_t *)dci_pdu)->ndi1          = rel8->new_data_indicator_1;
        ((DCI2_5MHz_2A_FDD_t *)dci_pdu)->ndi2          = rel8->new_data_indicator_2;
        ((DCI2_5MHz_2A_FDD_t *)dci_pdu)->rballoc       = rel8->resource_block_coding;
        ((DCI2_5MHz_2A_FDD_t *)dci_pdu)->rv1           = rel8->redundancy_version_1;
        ((DCI2_5MHz_2A_FDD_t *)dci_pdu)->rv2           = rel8->redundancy_version_2;
        ((DCI2_5MHz_2A_FDD_t *)dci_pdu)->TPC           = rel8->tpc;
        ((DCI2_5MHz_2A_FDD_t *)dci_pdu)->harq_pid      = rel8->harq_process;
	((DCI2_5MHz_2A_FDD_t *)dci_pdu)->tb_swap       = rel8->transport_block_to_codeword_swap_flag;
        ((DCI2_5MHz_2A_FDD_t *)dci_pdu)->tpmi          = rel8->precoding_information;
        ((DCI2_5MHz_2A_FDD_t *)dci_pdu)->padding       = 0;
        //      printf("FDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
      }
      break;
    case 50:
      if (fp->frame_type == TDD) {
	dci_alloc->dci_length                        = sizeof_DCI2_10MHz_2A_TDD_t; 
        ((DCI2_10MHz_2A_TDD_t *)dci_pdu)->rah      = rel8->resource_allocation_type;
        ((DCI2_10MHz_2A_TDD_t *)dci_pdu)->mcs1     = rel8->mcs_1;
        ((DCI2_10MHz_2A_TDD_t *)dci_pdu)->mcs2     = rel8->mcs_2;
        ((DCI2_10MHz_2A_TDD_t *)dci_pdu)->ndi1     = rel8->new_data_indicator_1;
        ((DCI2_10MHz_2A_TDD_t *)dci_pdu)->ndi2     = rel8->new_data_indicator_2;
        ((DCI2_10MHz_2A_TDD_t *)dci_pdu)->rballoc  = rel8->resource_block_coding;
        ((DCI2_10MHz_2A_TDD_t *)dci_pdu)->rv1      = rel8->redundancy_version_1;
        ((DCI2_10MHz_2A_TDD_t *)dci_pdu)->rv2      = rel8->redundancy_version_2;
        ((DCI2_10MHz_2A_TDD_t *)dci_pdu)->TPC      = rel8->tpc;
        ((DCI2_10MHz_2A_TDD_t *)dci_pdu)->harq_pid = rel8->harq_process;
	((DCI2_10MHz_2A_TDD_t *)dci_pdu)->tb_swap  = rel8->transport_block_to_codeword_swap_flag;	
        ((DCI2_10MHz_2A_TDD_t *)dci_pdu)->dai      = rel8->downlink_assignment_index;	
        ((DCI2_10MHz_2A_TDD_t *)dci_pdu)->tpmi     = rel8->precoding_information;
        ((DCI2_10MHz_2A_TDD_t *)dci_pdu)->padding  = 0;
        //        printf("TDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
      } else {
	dci_alloc->dci_length                        = sizeof_DCI2_10MHz_2A_FDD_t; 
        ((DCI2_10MHz_2A_FDD_t *)dci_pdu)->rah       = rel8->resource_allocation_type;
        ((DCI2_10MHz_2A_FDD_t *)dci_pdu)->mcs1      = rel8->mcs_1;
        ((DCI2_10MHz_2A_FDD_t *)dci_pdu)->mcs2      = rel8->mcs_2;
        ((DCI2_10MHz_2A_FDD_t *)dci_pdu)->ndi1      = rel8->new_data_indicator_1;
        ((DCI2_10MHz_2A_FDD_t *)dci_pdu)->ndi2      = rel8->new_data_indicator_2;
        ((DCI2_10MHz_2A_FDD_t *)dci_pdu)->rballoc   = rel8->resource_block_coding;
        ((DCI2_10MHz_2A_FDD_t *)dci_pdu)->rv1       = rel8->redundancy_version_1;
        ((DCI2_10MHz_2A_FDD_t *)dci_pdu)->rv2       = rel8->redundancy_version_2;
        ((DCI2_10MHz_2A_FDD_t *)dci_pdu)->TPC       = rel8->tpc;
        ((DCI2_10MHz_2A_FDD_t *)dci_pdu)->harq_pid  = rel8->harq_process;
	((DCI2_10MHz_2A_FDD_t *)dci_pdu)->tb_swap   = rel8->transport_block_to_codeword_swap_flag;
        ((DCI2_10MHz_2A_TDD_t *)dci_pdu)->tpmi      = rel8->precoding_information;
        ((DCI2_10MHz_2A_TDD_t *)dci_pdu)->padding   = 0;
      }
      break;
    case 100:
      if (fp->frame_type == TDD) {
	dci_alloc->dci_length                        = sizeof_DCI2_20MHz_2A_TDD_t;
        ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->rah       = rel8->resource_allocation_type;
        ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->mcs1      = rel8->mcs_1;
        ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->mcs2      = rel8->mcs_2;
        ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->ndi1      = rel8->new_data_indicator_1;
        ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->ndi2      = rel8->new_data_indicator_2;
        ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->rballoc   = rel8->resource_block_coding;
        ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->rv1       = rel8->redundancy_version_1;
        ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->rv2       = rel8->redundancy_version_2;
        ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->TPC       = rel8->tpc;
        ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->harq_pid  = rel8->harq_process;
	((DCI2_20MHz_2A_TDD_t *)dci_pdu)->tb_swap   = rel8->transport_block_to_codeword_swap_flag;
        ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->dai       = rel8->downlink_assignment_index;
        ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->tpmi      = rel8->precoding_information;
        ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->padding   = 0;
        //        printf("TDD 1: mcs %d, rballoc %x,rv %d, NPRB %d\n",mcs,rballoc,rv,NPRB);
      } else {
	dci_alloc->dci_length                           = sizeof_DCI2_20MHz_2A_FDD_t;
        ((DCI2_20MHz_2A_FDD_t *)dci_pdu)->rah          = rel8->resource_allocation_type;
        ((DCI2_20MHz_2A_FDD_t *)dci_pdu)->mcs1         = rel8->mcs_1;
        ((DCI2_20MHz_2A_FDD_t *)dci_pdu)->mcs2         = rel8->mcs_2;
        ((DCI2_20MHz_2A_FDD_t *)dci_pdu)->ndi1         = rel8->new_data_indicator_1;
        ((DCI2_20MHz_2A_FDD_t *)dci_pdu)->ndi2         = rel8->new_data_indicator_2;
        ((DCI2_20MHz_2A_FDD_t *)dci_pdu)->rballoc      = rel8->resource_block_coding;
        ((DCI2_20MHz_2A_FDD_t *)dci_pdu)->rv1          = rel8->redundancy_version_1;
        ((DCI2_20MHz_2A_FDD_t *)dci_pdu)->rv2          = rel8->redundancy_version_2;
        ((DCI2_20MHz_2A_FDD_t *)dci_pdu)->TPC          = rel8->tpc;
        ((DCI2_20MHz_2A_FDD_t *)dci_pdu)->harq_pid     = rel8->harq_process;
	((DCI2_20MHz_2A_FDD_t *)dci_pdu)->tb_swap      = rel8->transport_block_to_codeword_swap_flag;
        ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->tpmi         = rel8->precoding_information;
        ((DCI2_20MHz_2A_TDD_t *)dci_pdu)->padding      = 0;
      }
      break;

    }

    AssertFatal(rel8->harq_process>=8, "Format 2_2A: harq_pid=%d >= 8\n", rel8->harq_process);


    // Flip the TB to codeword mapping as described in 5.3.3.1.5 of 36-212 V11.3.0
    // note that we must set tbswap=0 in eNB scheduler if one TB is deactivated
    TB0_active = 1;
    TB1_active = 1;

    if ((rel8->redundancy_version_1 == 1) && (rel8->mcs_1 == 0)) {
      TB0_active=0;
    }
    if ((rel8->redundancy_version_2 == 1) && (rel8->mcs_2 == 0)) {
      TB1_active=0;
    }
#ifdef DEBUG_HARQ
    printf("RV0 = %d, RV1 = %d. MCS0 = %d, MCS1=%d\n", rel8->redundancy_version_1, rel8->redundancy_version_2, rel8->mcs_1, rel8->mcs_2);
#endif
    if (TB0_active && TB1_active && rel8->transport_block_to_codeword_swap_flag==0) {
#ifdef PHY_TX_THREAD
      dlsch0->active[subframe] = 1;
      dlsch1->active[subframe] = 1;
#else
      dlsch0->active = 1;
      dlsch1->active = 1;
#endif
      dlsch0->harq_mask                         |= (1<<rel8->harq_process);
      dlsch1->harq_mask                         |= (1<<rel8->harq_process);
      dlsch0_harq = dlsch0->harq_processes[rel8->harq_process];
      dlsch1_harq = dlsch1->harq_processes[rel8->harq_process];
      dlsch0_harq->mcs = rel8->mcs_1;
      dlsch1_harq->mcs = rel8->mcs_2;
      dlsch0_harq->Qm  = get_Qm(rel8->mcs_1);
      dlsch1_harq->Qm  = get_Qm(rel8->mcs_2);
      dlsch0_harq->rvidx = rel8->redundancy_version_1;
      dlsch1_harq->rvidx = rel8->redundancy_version_2;
      dlsch0_harq->status = ACTIVE;
      dlsch1_harq->status = ACTIVE;
      dlsch0_harq->codeword=0;
      dlsch1_harq->codeword=1;
#ifdef DEBUG_HARQ
      printf("\n ENB: BOTH ACTIVE\n");
#endif
    }
    else if (TB0_active && TB1_active && rel8->transport_block_to_codeword_swap_flag==1) {
      dlsch0 = eNB->dlsch[UE_id][1];
      dlsch1 = eNB->dlsch[UE_id][0];
#ifdef PHY_TX_THREAD
      dlsch0->active[subframe] = 1;
      dlsch1->active[subframe] = 1;
#else
      dlsch0->active = 1;
      dlsch1->active = 1;
#endif

      dlsch0->harq_mask                         |= (1<<rel8->harq_process);
      dlsch1->harq_mask                         |= (1<<rel8->harq_process);

      dlsch1_harq = dlsch1->harq_processes[rel8->harq_process];
      dlsch0_harq->mcs = rel8->mcs_1;
      dlsch1_harq->mcs = rel8->mcs_2;
      dlsch0_harq->Qm  = get_Qm(rel8->mcs_1);
      dlsch1_harq->Qm  = get_Qm(rel8->mcs_2);
      dlsch0_harq->rvidx = rel8->redundancy_version_1;
      dlsch1_harq->rvidx = rel8->redundancy_version_2;
      dlsch0_harq->status = ACTIVE;
      dlsch1_harq->status = ACTIVE;
      dlsch0_harq->codeword=1;
      dlsch1_harq->codeword=0;
    }
    else if (TB0_active && (TB1_active==0)) {
#ifdef PHY_TX_THREAD
      dlsch0->active[subframe] = 1;
#else
      dlsch0->active = 1;
#endif
      dlsch0->harq_mask                         |= (1<<rel8->harq_process);
      dlsch0_harq = dlsch0->harq_processes[rel8->harq_process];
      dlsch0_harq->mcs = rel8->mcs_1;
      dlsch0_harq->Qm  = get_Qm(rel8->mcs_1);
      dlsch0_harq->rvidx = rel8->redundancy_version_1;
      dlsch0_harq->status = ACTIVE;
      dlsch0_harq->codeword = 0;
      dlsch1=NULL;
      dlsch1_harq = NULL;
#ifdef DEBUG_HARQ
      printf("\n ENB: TB1 is deactivated, retransmit TB0 transmit in TM6\n");
#endif
    }
    else if ((TB0_active==0) && TB1_active) {
#ifdef PHY_TX_THREAD
      dlsch1->active[subframe] = 1;
#else
      dlsch1->active = 1;
#endif
      dlsch1->harq_mask                         |= (1<<rel8->harq_process);
      dlsch1_harq = dlsch1->harq_processes[rel8->harq_process];
      dlsch1_harq->mcs = rel8->mcs_2;
      dlsch1_harq->Qm  = get_Qm(rel8->mcs_2);
      dlsch1_harq->rvidx = rel8->redundancy_version_2;
      dlsch1_harq->status = ACTIVE;
      dlsch1_harq->codeword = 0;
      dlsch0=NULL;
      dlsch0_harq = NULL;
#ifdef DEBUG_HARQ
      printf("\n ENB: TB0 is deactivated, retransmit TB1 transmit in TM6\n");
#endif
    }

    if (dlsch0 != NULL){
      dlsch0->subframe_tx[subframe] = 1;

      dlsch0->harq_ids[frame%2][subframe] = rel8->harq_process;
    }

    if (dlsch1_harq != NULL){
      dlsch1->harq_ids[frame%2][subframe] = rel8->harq_process;
    }


    if (dlsch0 != NULL ){
      conv_rballoc(rel8->resource_allocation_type,
                   rel8->resource_block_coding,
                   fp->N_RB_DL,
                   dlsch0_harq->rb_alloc);

      dlsch0_harq->nb_rb = conv_nprb(rel8->resource_allocation_type, rel8->resource_block_coding, fp->N_RB_DL);

      if (dlsch1 != NULL){
        dlsch1_harq->rb_alloc[0] = dlsch0_harq->rb_alloc[0];
        dlsch1_harq->nb_rb = dlsch0_harq->nb_rb;
      }
    } else if ((dlsch0 == NULL ) && (dlsch1 != NULL )){
        conv_rballoc(rel8->resource_allocation_type,
                     rel8->resource_block_coding,
                     fp->N_RB_DL,
                     dlsch1_harq->rb_alloc);

        dlsch1_harq->nb_rb = conv_nprb(rel8->resource_allocation_type, rel8->resource_block_coding, fp->N_RB_DL);
    }


    // assume both TBs are active
    if (dlsch0_harq != NULL)
      dlsch0_harq->Nl        = 1;
    if (dlsch1_harq != NULL)
      dlsch1_harq->Nl        = 1;


    // check if either TB is disabled (see 36-213 V11.3 Section )

    if (fp->nb_antenna_ports_eNB == 2) {
      if ((dlsch0 != NULL) && (dlsch1 != NULL)) {  //two CW active

        dlsch0_harq->dl_power_off = 1;
        dlsch1_harq->dl_power_off = 1;
        dlsch0_harq->TBS = TBStable[get_I_TBS(dlsch0_harq->mcs)][dlsch0_harq->nb_rb-1];
        dlsch1_harq->TBS = TBStable[get_I_TBS(dlsch1_harq->mcs)][dlsch1_harq->nb_rb-1];
        switch (rel8->precoding_information) {
        case 0:
          dlsch0_harq->mimo_mode   = DUALSTREAM_UNIFORM_PRECODING1;
          dlsch1_harq->mimo_mode   = DUALSTREAM_UNIFORM_PRECODING1;
          dlsch0_harq->pmi_alloc   = pmi_extend(fp,0,1);
          dlsch1_harq->pmi_alloc   = pmi_extend(fp,0,1);
          break;
        case 1:
          dlsch0_harq->mimo_mode   = DUALSTREAM_UNIFORM_PRECODINGj;
          dlsch1_harq->mimo_mode   = DUALSTREAM_UNIFORM_PRECODINGj;
          dlsch0_harq->pmi_alloc   = pmi_extend(fp,1,1);
          dlsch0_harq->pmi_alloc   = pmi_extend(fp,1,1);

          break;
        case 2: // PUSCH precoding
          dlsch0_harq->mimo_mode   = DUALSTREAM_PUSCH_PRECODING;
          dlsch0_harq->pmi_alloc   = DL_pmi_single;
          dlsch1_harq->mimo_mode   = DUALSTREAM_PUSCH_PRECODING;
          dlsch1_harq->pmi_alloc   = DL_pmi_single;
          break;
        default:
          break;
        }
      } else if ((dlsch0 != NULL) && (dlsch1 == NULL))  { // only CW 0 active
        dlsch0_harq->dl_power_off = 1;
        dlsch0_harq->TBS= TBStable[get_I_TBS(dlsch0_harq->mcs)][dlsch0_harq->nb_rb-1];
        switch (rel8->precoding_information) {
        case 0 :
          dlsch0_harq->mimo_mode   = ALAMOUTI;
          break;
        case 1:
          dlsch0_harq->mimo_mode   = UNIFORM_PRECODING11;
          dlsch0_harq->pmi_alloc   = pmi_extend(fp,0,0);
          break;
        case 2:
          dlsch0_harq->mimo_mode   = UNIFORM_PRECODING1m1;
          dlsch0_harq->pmi_alloc   = pmi_extend(fp,1,0);
          break;
        case 3:
          dlsch0_harq->mimo_mode   = UNIFORM_PRECODING1j;
          dlsch0_harq->pmi_alloc   = pmi_extend(fp,2,0);
          break;
        case 4:
          dlsch0_harq->mimo_mode   = UNIFORM_PRECODING1mj;
          dlsch0_harq->pmi_alloc   = pmi_extend(fp,3,0);
          break;
        case 5:
          dlsch0_harq->mimo_mode   = PUSCH_PRECODING0;
          dlsch0_harq->pmi_alloc   = DL_pmi_single;
          break;
        case 6:
          dlsch0_harq->mimo_mode   = PUSCH_PRECODING1;
          dlsch0_harq->pmi_alloc   = DL_pmi_single;
          break;
        }
      } else if ((dlsch0 == NULL) && (dlsch1 != NULL))  {
          dlsch1_harq->dl_power_off = 1;
          dlsch1_harq->TBS= TBStable[get_I_TBS(dlsch1_harq->mcs)][dlsch1_harq->nb_rb-1];
          switch (rel8->precoding_information) {
          case 0 :
            dlsch1_harq->mimo_mode   = ALAMOUTI;
            break;
          case 1:
            dlsch1_harq->mimo_mode   = UNIFORM_PRECODING11;
            dlsch1_harq->pmi_alloc   = pmi_extend(fp,0,0);
            break;
          case 2:
            dlsch1_harq->mimo_mode   = UNIFORM_PRECODING1m1;
            dlsch1_harq->pmi_alloc   = pmi_extend(fp,1,0);
            break;
          case 3:
            dlsch1_harq->mimo_mode   = UNIFORM_PRECODING1j;
            dlsch1_harq->pmi_alloc   = pmi_extend(fp,2,0);
            break;
          case 4:
            dlsch1_harq->mimo_mode   = UNIFORM_PRECODING1mj;
            dlsch1_harq->pmi_alloc   = pmi_extend(fp,3,0);
            break;
          case 5:
            dlsch1_harq->mimo_mode   = PUSCH_PRECODING0;
            dlsch1_harq->pmi_alloc   = DL_pmi_single;
            break;
          case 6:
            dlsch1_harq->mimo_mode   = PUSCH_PRECODING1;
            dlsch1_harq->pmi_alloc   = DL_pmi_single;
            break;
          }
        }

    } else if (fp->nb_antenna_ports_eNB == 4) {
      // fill in later
    }

    // reset HARQ process if this is the first transmission
   /* if (dlsch0_harq->round == 0)
      dlsch0_harq->status = ACTIVE;

    if (dlsch1_harq->round == 0)
      dlsch1_harq->status = ACTIVE;*/
    if (dlsch0_harq != NULL)
      dlsch0->rnti = rel8->rnti;
    if (dlsch1 != NULL)
      dlsch1->rnti = rel8->rnti;

    break;
  }

  if (dlsch0_harq) {
    dlsch0_harq->frame    = frame;
    dlsch0_harq->subframe = subframe;
  }
  if (dlsch1_harq) {
    dlsch1_harq->frame    = frame;
    dlsch1_harq->subframe = subframe;
  }

#ifdef DEBUG_DCI

  if (dlsch0) {
    printf("dlsch0 eNB: dlsch0   %p\n",dlsch0);
    printf("dlsch0 eNB: rnti     %x\n",dlsch0->rnti);
    printf("dlsch0 eNB: NBRB     %d\n",dlsch0_harq->nb_rb);
    printf("dlsch0 eNB: rballoc  %x\n",dlsch0_harq->rb_alloc[0]);
    printf("dlsch0 eNB: harq_pid %d\n",harq_pid);
    printf("dlsch0 eNB: round    %d\n",dlsch0_harq->round);
    printf("dlsch0 eNB: rvidx    %d\n",dlsch0_harq->rvidx);
    printf("dlsch0 eNB: TBS      %d (NPRB %d)\n",dlsch0_harq->TBS,NPRB);
    printf("dlsch0 eNB: mcs      %d\n",dlsch0_harq->mcs);
    printf("dlsch0 eNB: tpmi %d\n",rel8->precoding_information);
    printf("dlsch0 eNB: mimo_mode %d\n",dlsch0_harq->mimo_mode);
  }

    if (dlsch1) {
    printf("dlsch1 eNB: dlsch1   %p\n",dlsch1);
    printf("dlsch1 eNB: rnti     %x\n",dlsch1->rnti);
    printf("dlsch1 eNB: NBRB     %d\n",dlsch1_harq->nb_rb);
    printf("dlsch1 eNB: rballoc  %x\n",dlsch1_harq->rb_alloc[0]);
    printf("dlsch1 eNB: harq_pid %d\n",harq_pid);
    printf("dlsch1 eNB: round    %d\n",dlsch1_harq->round);
    printf("dlsch1 eNB: rvidx    %d\n",dlsch1_harq->rvidx);
    printf("dlsch1 eNB: TBS      %d (NPRB %d)\n",dlsch1_harq->TBS,NPRB);
    printf("dlsch1 eNB: mcs      %d\n",dlsch1_harq->mcs);
    printf("dlsch1 eNB: tpmi %d\n",rel8->precoding_information);
    printf("dlsch1 eNB: mimo_mode %d\n",dlsch1_harq->mimo_mode);
  }

#endif
    
//printf("DCI %d.%d rnti %d harq %d TBS %d\n", frame, subframe, rel8->rnti, rel8->harq_process, dlsch0_harq->TBS);
#if T_TRACER
  if (dlsch0->active)
    T(T_ENB_PHY_DLSCH_UE_DCI, T_INT(0), T_INT(frame), T_INT(subframe),
      T_INT(rel8->rnti), T_INT(rel8->dci_format), T_INT(rel8->harq_process),
      T_INT(rel8->mcs_1), T_INT(dlsch0_harq->TBS));
#endif

}

void fill_mdci_and_dlsch(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,mDCI_ALLOC_t *dci_alloc,nfapi_dl_config_mpdcch_pdu *pdu) {

  LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;

  uint8_t *dci_pdu = &dci_alloc->dci_pdu[0];
  nfapi_dl_config_mpdcch_pdu_rel13_t *rel13 = &pdu->mpdcch_pdu_rel13;

  LTE_eNB_DLSCH_t *dlsch0=NULL;
  LTE_DL_eNB_HARQ_t *dlsch0_harq=NULL;
  int UE_id;
  int subframe = proc->subframe_tx;
  int frame = proc->frame_tx;

  dci_alloc->firstCCE                   = rel13->ecce_index;
  dci_alloc->L                          = rel13->aggregation_level;
  dci_alloc->rnti                       = rel13->rnti;
  dci_alloc->harq_pid                   = rel13->harq_process;
  dci_alloc->narrowband                  = rel13->mpdcch_narrow_band;
  dci_alloc->number_of_prb_pairs        = rel13->number_of_prb_pairs;
  dci_alloc->resource_block_assignment  = rel13->resource_block_assignment;
  dci_alloc->transmission_type          = rel13->mpdcch_tansmission_type;
  dci_alloc->start_symbol               = rel13->start_symbol;
  dci_alloc->ce_mode                    = rel13->ce_mode;
  dci_alloc->dmrs_scrambling_init       = rel13->drms_scrambling_init;
  dci_alloc->i0                         = rel13->initial_transmission_sf_io;

  dci_alloc->ra_flag  = 0;
  if (rel13->rnti_type == 2 ) dci_alloc->ra_flag = 1;

  UE_id = find_dlsch(rel13->rnti,eNB,SEARCH_EXIST_OR_FREE);
  if( (UE_id<0) || (UE_id>=NUMBER_OF_UE_MAX) ){
    LOG_E(PHY,"illegal UE_id found!!! rnti %04x UE_id %d\n",rel13->rnti,UE_id);
    return;
  }
  //AssertFatal(UE_id!=-1,"no free or exiting dlsch_context\n");
  //AssertFatal(UE_id<NUMBER_OF_UE_MAX,"returned UE_id %d >= %d(NUMBER_OF_UE_MAX)\n",UE_id,NUMBER_OF_UE_MAX);
  dlsch0 = eNB->dlsch[UE_id][0];
  dlsch0_harq                               = dlsch0->harq_processes[rel13->harq_process];

  AssertFatal(fp->frame_type==FDD,"TDD is not supported yet for eMTC\n");
  AssertFatal(fp->N_RB_DL==25 || fp->N_RB_DL==50 ||fp->N_RB_DL==100,
	      "eMTC only with N_RB_DL = 25,50,100\n");

  switch (rel13->dci_format) {

  case 10:  // Format 6-1A
    dci_alloc->format     = format6_1A;
#ifdef PHY_TX_THREAD
    dlsch0->active[subframe]       = 1;
#else
    dlsch0->active       = 1;
#endif
    switch (fp->N_RB_DL) {

    case 25:
      dci_alloc->dci_length                     = sizeof_DCI6_1A_5MHz_t; 
      ((DCI6_1A_5MHz_t *)dci_pdu)->type         = 1;
      ((DCI6_1A_5MHz_t *)dci_pdu)->hopping      = rel13->frequency_hopping_enabled_flag;
      ((DCI6_1A_5MHz_t *)dci_pdu)->rballoc      = rel13->resource_block_coding;
      ((DCI6_1A_5MHz_t *)dci_pdu)->mcs          = rel13->mcs;
      ((DCI6_1A_5MHz_t *)dci_pdu)->rep          = (rel13->pdsch_reptition_levels-1);
      ((DCI6_1A_5MHz_t *)dci_pdu)->harq_pid     = rel13->harq_process;
      ((DCI6_1A_5MHz_t *)dci_pdu)->ndi          = rel13->new_data_indicator;
      ((DCI6_1A_5MHz_t *)dci_pdu)->rv           = rel13->redundancy_version;
      ((DCI6_1A_5MHz_t *)dci_pdu)->TPC          = rel13->tpc;
      ((DCI6_1A_5MHz_t *)dci_pdu)->srs_req      = rel13->srs_request;
      ((DCI6_1A_5MHz_t *)dci_pdu)->harq_ack_off = rel13->harq_resource_offset;
      ((DCI6_1A_5MHz_t *)dci_pdu)->dci_rep      = rel13->dci_subframe_repetition_number-1;
      ((DCI6_1A_5MHz_t *)dci_pdu)->padding      = 0;
    
      break;
    case 50:
      dci_alloc->dci_length                     = sizeof_DCI6_1A_10MHz_t; 
      ((DCI6_1A_10MHz_t *)dci_pdu)->type         = 1;
      ((DCI6_1A_10MHz_t *)dci_pdu)->hopping      = rel13->frequency_hopping_enabled_flag;
      ((DCI6_1A_10MHz_t *)dci_pdu)->rballoc      = rel13->resource_block_coding;
      ((DCI6_1A_10MHz_t *)dci_pdu)->mcs          = rel13->mcs;
      ((DCI6_1A_10MHz_t *)dci_pdu)->rep          = (rel13->pdsch_reptition_levels-1);
      ((DCI6_1A_10MHz_t *)dci_pdu)->harq_pid     = rel13->harq_process;
      ((DCI6_1A_10MHz_t *)dci_pdu)->ndi          = rel13->new_data_indicator;
      ((DCI6_1A_10MHz_t *)dci_pdu)->rv           = rel13->redundancy_version;
      ((DCI6_1A_10MHz_t *)dci_pdu)->TPC          = rel13->tpc;
      ((DCI6_1A_10MHz_t *)dci_pdu)->srs_req      = rel13->srs_request;
      ((DCI6_1A_10MHz_t *)dci_pdu)->harq_ack_off = rel13->harq_resource_offset;
      ((DCI6_1A_10MHz_t *)dci_pdu)->dci_rep      = rel13->dci_subframe_repetition_number-1;
      ((DCI6_1A_10MHz_t *)dci_pdu)->padding      = 0;
      break;
    case 100:
      dci_alloc->dci_length                     = sizeof_DCI6_1A_20MHz_t; 
      ((DCI6_1A_20MHz_t *)dci_pdu)->type         = 1;
      ((DCI6_1A_20MHz_t *)dci_pdu)->hopping      = rel13->frequency_hopping_enabled_flag;
      ((DCI6_1A_20MHz_t *)dci_pdu)->rballoc      = rel13->resource_block_coding;
      ((DCI6_1A_20MHz_t *)dci_pdu)->mcs          = rel13->mcs;
      ((DCI6_1A_20MHz_t *)dci_pdu)->rep          = (rel13->pdsch_reptition_levels-1);
      ((DCI6_1A_20MHz_t *)dci_pdu)->harq_pid     = rel13->harq_process;
      ((DCI6_1A_20MHz_t *)dci_pdu)->ndi          = rel13->new_data_indicator;
      ((DCI6_1A_20MHz_t *)dci_pdu)->rv           = rel13->redundancy_version;
      ((DCI6_1A_20MHz_t *)dci_pdu)->TPC          = rel13->tpc;
      ((DCI6_1A_20MHz_t *)dci_pdu)->srs_req      = rel13->srs_request;
      ((DCI6_1A_20MHz_t *)dci_pdu)->harq_ack_off = rel13->harq_resource_offset;
      ((DCI6_1A_20MHz_t *)dci_pdu)->dci_rep      = rel13->dci_subframe_repetition_number-1;
      ((DCI6_1A_20MHz_t *)dci_pdu)->padding      = 0;
      break;
    }
    break;
  case 11:  // Format 6-1B
    dci_alloc->format     = format6_1B;
#ifdef PHY_TX_THREAD
    dlsch0->active[subframe]       = 1;
#else
    dlsch0->active       = 1;
#endif
    switch (fp->N_RB_DL) {

    case 25:
      dci_alloc->dci_length                     = sizeof_DCI6_1B_5MHz_t; 
      ((DCI6_1B_5MHz_t *)dci_pdu)->type         = 1;
      ((DCI6_1B_5MHz_t *)dci_pdu)->rballoc      = rel13->resource_block_coding;
      ((DCI6_1B_5MHz_t *)dci_pdu)->mcs          = rel13->mcs;
      ((DCI6_1B_5MHz_t *)dci_pdu)->rep          = (rel13->pdsch_reptition_levels-1);
      ((DCI6_1B_5MHz_t *)dci_pdu)->harq_pid     = rel13->harq_process;
      ((DCI6_1B_5MHz_t *)dci_pdu)->ndi          = rel13->new_data_indicator;
      ((DCI6_1B_5MHz_t *)dci_pdu)->harq_ack_off = rel13->harq_resource_offset;
      ((DCI6_1B_5MHz_t *)dci_pdu)->dci_rep      = rel13->dci_subframe_repetition_number-1;
      ((DCI6_1B_5MHz_t *)dci_pdu)->padding      = 0;
  
      break;
    case 50:
      dci_alloc->dci_length                      = sizeof_DCI6_1B_10MHz_t; 
      ((DCI6_1B_10MHz_t *)dci_pdu)->type         = 1;
      ((DCI6_1B_10MHz_t *)dci_pdu)->rballoc      = rel13->resource_block_coding;
      ((DCI6_1B_10MHz_t *)dci_pdu)->mcs          = rel13->mcs;
      ((DCI6_1B_10MHz_t *)dci_pdu)->rep          = (rel13->pdsch_reptition_levels-1);
      ((DCI6_1B_10MHz_t *)dci_pdu)->harq_pid     = rel13->harq_process;
      ((DCI6_1B_10MHz_t *)dci_pdu)->ndi          = rel13->new_data_indicator;
      ((DCI6_1B_10MHz_t *)dci_pdu)->harq_ack_off = rel13->harq_resource_offset;
      ((DCI6_1B_10MHz_t *)dci_pdu)->dci_rep      = rel13->dci_subframe_repetition_number-1;
      ((DCI6_1B_10MHz_t *)dci_pdu)->padding      = 0;
      break;
    case 100:
      dci_alloc->dci_length                      = sizeof_DCI6_1B_20MHz_t; 
      ((DCI6_1B_20MHz_t *)dci_pdu)->type         = 1;
      ((DCI6_1B_20MHz_t *)dci_pdu)->rballoc      = rel13->resource_block_coding;
      ((DCI6_1B_20MHz_t *)dci_pdu)->mcs          = rel13->mcs;
      ((DCI6_1B_20MHz_t *)dci_pdu)->rep          = (rel13->pdsch_reptition_levels-1);
      ((DCI6_1B_20MHz_t *)dci_pdu)->harq_pid     = rel13->harq_process;
      ((DCI6_1B_20MHz_t *)dci_pdu)->ndi          = rel13->new_data_indicator;
      ((DCI6_1B_20MHz_t *)dci_pdu)->harq_ack_off = rel13->harq_resource_offset;
      ((DCI6_1B_20MHz_t *)dci_pdu)->dci_rep      = rel13->dci_subframe_repetition_number-1;
      ((DCI6_1B_20MHz_t *)dci_pdu)->padding      = 0;
      break;
    }
  case 12: // Format 6-2
    dci_alloc->format     = format6_2;
#ifdef PHY_TX_THREAD
    dlsch0->active[subframe]       = 1;
#else
    dlsch0->active       = 1;
#endif
    switch (fp->N_RB_DL) {
    case 25:
      dci_alloc->dci_length                 = sizeof_DCI6_2_5MHz_t; 
      if (rel13->paging_direct_indication_differentiation_flag==0) {
	((DCI6_2_di_5MHz_t *)dci_pdu)->type    = 0;
	((DCI6_2_di_5MHz_t *)dci_pdu)->di_info = rel13->direct_indication;
	((DCI6_2_di_5MHz_t *)dci_pdu)->padding = 0;
      }
      else {
	((DCI6_2_paging_5MHz_t *)dci_pdu)->type    = 1;
	((DCI6_2_paging_5MHz_t *)dci_pdu)->rballoc = rel13->resource_block_coding;
	((DCI6_2_paging_5MHz_t *)dci_pdu)->mcs     = rel13->mcs;
	((DCI6_2_paging_5MHz_t *)dci_pdu)->rep     = (rel13->pdsch_reptition_levels-1);
	((DCI6_2_paging_5MHz_t *)dci_pdu)->dci_rep = rel13->dci_subframe_repetition_number-1;
	((DCI6_2_paging_5MHz_t *)dci_pdu)->padding = 0;
      }

    break;
    case 50:
      dci_alloc->dci_length                 = sizeof_DCI6_2_10MHz_t; 
      if (rel13->paging_direct_indication_differentiation_flag==0) {
	((DCI6_2_di_10MHz_t *)dci_pdu)->type    = 0;
	((DCI6_2_di_10MHz_t *)dci_pdu)->di_info = rel13->direct_indication;
	((DCI6_2_di_10MHz_t *)dci_pdu)->padding = 0;
      }
      else {
	((DCI6_2_paging_10MHz_t *)dci_pdu)->type    = 1;
	((DCI6_2_paging_10MHz_t *)dci_pdu)->rballoc = rel13->resource_block_coding;
	((DCI6_2_paging_10MHz_t *)dci_pdu)->mcs     = rel13->mcs;
	((DCI6_2_paging_10MHz_t *)dci_pdu)->rep     = (rel13->pdsch_reptition_levels-1);
	((DCI6_2_paging_10MHz_t *)dci_pdu)->dci_rep = rel13->dci_subframe_repetition_number-1;
	((DCI6_2_paging_10MHz_t *)dci_pdu)->padding = 0;
      }

    break;
    case 100:
      dci_alloc->dci_length                 = sizeof_DCI6_2_20MHz_t; 
      if (rel13->paging_direct_indication_differentiation_flag==0) {
	((DCI6_2_di_20MHz_t *)dci_pdu)->type    = 0;
	((DCI6_2_di_20MHz_t *)dci_pdu)->di_info = rel13->direct_indication;
	((DCI6_2_di_20MHz_t *)dci_pdu)->padding = 0;
      }
      else {
	((DCI6_2_paging_20MHz_t *)dci_pdu)->type    = 1;
	((DCI6_2_paging_20MHz_t *)dci_pdu)->rballoc = rel13->resource_block_coding;
	((DCI6_2_paging_20MHz_t *)dci_pdu)->mcs     = rel13->mcs;
	((DCI6_2_paging_20MHz_t *)dci_pdu)->rep     = (rel13->pdsch_reptition_levels-1);
	((DCI6_2_paging_20MHz_t *)dci_pdu)->dci_rep = rel13->dci_subframe_repetition_number-1;
	((DCI6_2_paging_20MHz_t *)dci_pdu)->padding = 0;
      }

      break;
    }
  }
  AssertFatal(rel13->harq_process<8,
	      "ERROR: Format 6_1A: harq_pid=%d >= 8\n", rel13->harq_process);
  
  dlsch0_harq = dlsch0->harq_processes[rel13->harq_process];
  dlsch0_harq->codeword=0;
  
  // printf("DCI: Setting subframe_tx for subframe %d\n",subframe);
  dlsch0->subframe_tx[subframe] = 1;
  
  conv_eMTC_rballoc(rel13->resource_block_coding,
		    fp->N_RB_DL,
		    dlsch0_harq->rb_alloc);
  
  dlsch0_harq->nb_rb = RIV2nb_rb_LUT6[rel13->resource_block_coding&31]; // this is the 6PRB RIV
  
  
  dlsch0_harq->rvidx       = rel13->redundancy_version;
  
  dlsch0_harq->Nl          = 1;
  //    dlsch[0]->layer_index = 0;
  //  if (beamforming_mode == 0)
  dlsch0_harq->mimo_mode = (fp->nb_antenna_ports_eNB == 1) ? SISO : ALAMOUTI;
    //else if (beamforming_mode == 7)
    //  dlsch0_harq->mimo_mode = TM7;
    //else
    //LOG_E(PHY,"Invalid beamforming mode %dL\n", beamforming_mode);
  
  dlsch0_harq->dl_power_off = 1;

#ifdef PHY_TX_THREAD
  dlsch0->active[subframe] = 1;
#else
  dlsch0->active = 1;
#endif
  dlsch0->harq_mask                         |= (1<<rel13->harq_process);  
  
  
  if (dlsch0_harq->round == 0) {
    dlsch0_harq->status = ACTIVE;
    //            printf("Setting DLSCH process %d to ACTIVE\n",rel8->harq_process);
    // MCS and TBS don't change across HARQ rounds
    dlsch0_harq->mcs         = rel13->mcs;
    dlsch0_harq->TBS         = TBStable[get_I_TBS(dlsch0_harq->mcs)][dlsch0_harq->nb_rb-1];
    
  }
  
  dlsch0->harq_ids[frame%2][subframe] = rel13->harq_process;
  
  
  
  dlsch0->rnti = rel13->rnti;







}

void fill_dci0(PHY_VARS_eNB *eNB,int frame,int subframe,eNB_rxtx_proc_t *proc,
    DCI_ALLOC_t *dci_alloc,nfapi_hi_dci0_dci_pdu *pdu)
{
  LTE_DL_FRAME_PARMS *frame_parms = &eNB->frame_parms;

  uint32_t cqi_req = pdu->dci_pdu_rel8.cqi_csi_request;
  uint32_t dai     = pdu->dci_pdu_rel8.dl_assignment_index;
  uint32_t cshift  = pdu->dci_pdu_rel8.cyclic_shift_2_for_drms;
  uint32_t TPC     = pdu->dci_pdu_rel8.tpc;
  uint32_t mcs     = pdu->dci_pdu_rel8.mcs_1;
  uint32_t hopping = pdu->dci_pdu_rel8.frequency_hopping_enabled_flag;
  uint32_t rballoc = computeRIV(frame_parms->N_RB_DL,
				pdu->dci_pdu_rel8.resource_block_start,
				pdu->dci_pdu_rel8.number_of_resource_block);

  uint32_t ndi     = pdu->dci_pdu_rel8.new_data_indication_1;

  uint16_t UE_id   = -1;

#ifdef T_TRACER
  T(T_ENB_PHY_ULSCH_UE_DCI, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe),
    T_INT(pdu->dci_pdu_rel8.rnti), T_INT(((frame*10+subframe+4) % 8) /* TODO: correct harq pid */),
    T_INT(mcs), T_INT(-1 /* TODO: remove round? */),
    T_INT(pdu->dci_pdu_rel8.resource_block_start),
    T_INT(pdu->dci_pdu_rel8.number_of_resource_block),
    T_INT(get_TBS_UL(mcs, pdu->dci_pdu_rel8.number_of_resource_block) * 8),
    T_INT(pdu->dci_pdu_rel8.aggregation_level),
    T_INT(pdu->dci_pdu_rel8.cce_index));
#endif

  void *dci_pdu = (void*)dci_alloc->dci_pdu;

  LOG_D(PHY,"SFN/SF:%04d%d DCI0[rnti %x cqi %d mcs %d hopping %d rballoc %x (%d,%d) ndi %d TPC %d cshift %d]\n",
        frame,subframe,
        pdu->dci_pdu_rel8.rnti,cqi_req, mcs,hopping,rballoc,
        pdu->dci_pdu_rel8.resource_block_start,
        pdu->dci_pdu_rel8.number_of_resource_block, ndi,TPC,cshift);

  dci_alloc->format   = format0;
  dci_alloc->firstCCE = pdu->dci_pdu_rel8.cce_index;
  dci_alloc->L        = pdu->dci_pdu_rel8.aggregation_level;
  dci_alloc->rnti     = pdu->dci_pdu_rel8.rnti;
  dci_alloc->ra_flag  = 0;

  switch (frame_parms->N_RB_DL) {
  case 6:
    if (frame_parms->frame_type == TDD) {
      ((DCI0_1_5MHz_TDD_1_6_t *)dci_pdu)->cqi_req = cqi_req;
      ((DCI0_1_5MHz_TDD_1_6_t *)dci_pdu)->dai     = dai;
      ((DCI0_1_5MHz_TDD_1_6_t *)dci_pdu)->cshift  = cshift;
      ((DCI0_1_5MHz_TDD_1_6_t *)dci_pdu)->TPC     = TPC;
      ((DCI0_1_5MHz_TDD_1_6_t *)dci_pdu)->mcs     = mcs;
      ((DCI0_1_5MHz_TDD_1_6_t *)dci_pdu)->ndi     = ndi;
      ((DCI0_1_5MHz_TDD_1_6_t *)dci_pdu)->rballoc = rballoc;
      ((DCI0_1_5MHz_TDD_1_6_t *)dci_pdu)->hopping = hopping;
      ((DCI0_1_5MHz_TDD_1_6_t *)dci_pdu)->type    = 0;
      ((DCI0_1_5MHz_TDD_1_6_t *)dci_pdu)->padding = 0;
      dci_alloc->dci_length                       = sizeof_DCI0_1_5MHz_TDD_1_6_t; 
    } else {
      ((DCI0_1_5MHz_FDD_t *)dci_pdu)->cqi_req     = cqi_req;
      ((DCI0_1_5MHz_FDD_t *)dci_pdu)->cshift      = cshift;
      ((DCI0_1_5MHz_FDD_t *)dci_pdu)->TPC         = TPC;
      ((DCI0_1_5MHz_FDD_t *)dci_pdu)->mcs         = mcs;
      ((DCI0_1_5MHz_FDD_t *)dci_pdu)->ndi         = ndi;
      ((DCI0_1_5MHz_FDD_t *)dci_pdu)->rballoc     = rballoc;
      ((DCI0_1_5MHz_FDD_t *)dci_pdu)->hopping     = hopping;
      ((DCI0_1_5MHz_FDD_t *)dci_pdu)->type        = 0;
      ((DCI0_1_5MHz_FDD_t *)dci_pdu)->padding     = 0;
      dci_alloc->dci_length                       = sizeof_DCI0_1_5MHz_FDD_t; 
    }
    
    break;
    
  case 25:
    if (frame_parms->frame_type == TDD) {
      ((DCI0_5MHz_TDD_1_6_t *)dci_pdu)->cqi_req = cqi_req;
      ((DCI0_5MHz_TDD_1_6_t *)dci_pdu)->dai     = dai;
      ((DCI0_5MHz_TDD_1_6_t *)dci_pdu)->cshift  = cshift;
      ((DCI0_5MHz_TDD_1_6_t *)dci_pdu)->TPC     = TPC;
      ((DCI0_5MHz_TDD_1_6_t *)dci_pdu)->mcs     = mcs;
      ((DCI0_5MHz_TDD_1_6_t *)dci_pdu)->ndi     = ndi;
      ((DCI0_5MHz_TDD_1_6_t *)dci_pdu)->rballoc = rballoc;
      ((DCI0_5MHz_TDD_1_6_t *)dci_pdu)->hopping = hopping;
      ((DCI0_5MHz_TDD_1_6_t *)dci_pdu)->type    = 0;
      ((DCI0_5MHz_TDD_1_6_t *)dci_pdu)->padding = 0;
      dci_alloc->dci_length                     = sizeof_DCI0_5MHz_TDD_1_6_t; 
    } else {
      ((DCI0_5MHz_FDD_t *)dci_pdu)->cqi_req     = cqi_req;
      ((DCI0_5MHz_FDD_t *)dci_pdu)->cshift      = cshift;
      ((DCI0_5MHz_FDD_t *)dci_pdu)->TPC         = TPC;
      ((DCI0_5MHz_FDD_t *)dci_pdu)->mcs         = mcs;
      ((DCI0_5MHz_FDD_t *)dci_pdu)->ndi         = ndi;
      ((DCI0_5MHz_FDD_t *)dci_pdu)->rballoc     = rballoc;
      ((DCI0_5MHz_FDD_t *)dci_pdu)->hopping     = hopping;
      ((DCI0_5MHz_FDD_t *)dci_pdu)->type        = 0;
      ((DCI0_5MHz_FDD_t *)dci_pdu)->padding     = 0;
      dci_alloc->dci_length                     = sizeof_DCI0_5MHz_FDD_t; 
    }
    
    break;
    
  case 50:
    if (frame_parms->frame_type == TDD) {
      ((DCI0_10MHz_TDD_1_6_t *)dci_pdu)->cqi_req = cqi_req;
      ((DCI0_10MHz_TDD_1_6_t *)dci_pdu)->dai     = dai;
      ((DCI0_10MHz_TDD_1_6_t *)dci_pdu)->cshift  = cshift;
      ((DCI0_10MHz_TDD_1_6_t *)dci_pdu)->TPC     = TPC;
      ((DCI0_10MHz_TDD_1_6_t *)dci_pdu)->mcs     = mcs;
      ((DCI0_10MHz_TDD_1_6_t *)dci_pdu)->ndi     = ndi;
      ((DCI0_10MHz_TDD_1_6_t *)dci_pdu)->rballoc = rballoc;
      ((DCI0_10MHz_TDD_1_6_t *)dci_pdu)->hopping = hopping;
      ((DCI0_10MHz_TDD_1_6_t *)dci_pdu)->type    = 0;
      ((DCI0_10MHz_TDD_1_6_t *)dci_pdu)->padding = 0;
      dci_alloc->dci_length                      = sizeof_DCI0_10MHz_TDD_1_6_t; 
    } else {
      ((DCI0_10MHz_FDD_t *)dci_pdu)->cqi_req     = cqi_req;
      ((DCI0_10MHz_FDD_t *)dci_pdu)->cshift      = cshift;
      ((DCI0_10MHz_FDD_t *)dci_pdu)->TPC         = TPC;
      ((DCI0_10MHz_FDD_t *)dci_pdu)->mcs         = mcs;
      ((DCI0_10MHz_FDD_t *)dci_pdu)->ndi         = ndi;
      ((DCI0_10MHz_FDD_t *)dci_pdu)->rballoc     = rballoc;
      ((DCI0_10MHz_FDD_t *)dci_pdu)->hopping     = hopping;
      ((DCI0_10MHz_FDD_t *)dci_pdu)->type        = 0;
      ((DCI0_10MHz_FDD_t *)dci_pdu)->padding     = 0;
      dci_alloc->dci_length                      = sizeof_DCI0_10MHz_FDD_t; 
    }
    
    break;
    
  case 100:
    if (frame_parms->frame_type == TDD) {
      ((DCI0_20MHz_TDD_1_6_t *)dci_pdu)->cqi_req = cqi_req;
      ((DCI0_20MHz_TDD_1_6_t *)dci_pdu)->dai     = dai;
      ((DCI0_20MHz_TDD_1_6_t *)dci_pdu)->cshift  = cshift;
      ((DCI0_20MHz_TDD_1_6_t *)dci_pdu)->TPC     = TPC;
      ((DCI0_20MHz_TDD_1_6_t *)dci_pdu)->mcs     = mcs;
      ((DCI0_20MHz_TDD_1_6_t *)dci_pdu)->ndi     = ndi;
      ((DCI0_20MHz_TDD_1_6_t *)dci_pdu)->rballoc = rballoc;
      ((DCI0_20MHz_TDD_1_6_t *)dci_pdu)->hopping = hopping;
      ((DCI0_20MHz_TDD_1_6_t *)dci_pdu)->type    = 0;
      ((DCI0_20MHz_TDD_1_6_t *)dci_pdu)->padding = 0;

      dci_alloc->dci_length                      = sizeof_DCI0_20MHz_TDD_1_6_t; 
    } else {
      ((DCI0_20MHz_FDD_t *)dci_pdu)->cqi_req     = cqi_req;
      ((DCI0_20MHz_FDD_t *)dci_pdu)->cshift      = cshift;
      ((DCI0_20MHz_FDD_t *)dci_pdu)->TPC         = TPC;
      ((DCI0_20MHz_FDD_t *)dci_pdu)->mcs         = mcs;
      ((DCI0_20MHz_FDD_t *)dci_pdu)->ndi         = ndi;
      ((DCI0_20MHz_FDD_t *)dci_pdu)->rballoc     = rballoc;
      ((DCI0_20MHz_FDD_t *)dci_pdu)->hopping     = hopping;
      ((DCI0_20MHz_FDD_t *)dci_pdu)->type        = 0;
      ((DCI0_20MHz_FDD_t *)dci_pdu)->padding     = 0;
      dci_alloc->dci_length                      = sizeof_DCI0_20MHz_FDD_t; 
    }
    
      //printf("eNB: rb_alloc (20 MHz dci) %d\n",rballoc);
      break;
      
  default:
    LOG_E(PHY,"Invalid N_RB_DL %d\n", frame_parms->N_RB_DL);
    DevParam (frame_parms->N_RB_DL, 0, 0);
    break;
  }

  if(frame_parms->frame_type == TDD){
     UE_id = find_ulsch(pdu->dci_pdu_rel8.rnti, eNB,SEARCH_EXIST_OR_FREE);
     if(UE_id != -1){
       eNB->ulsch[UE_id]->harq_processes[pdu->dci_pdu_rel8.harq_pid]->V_UL_DAI = dai +1;
     }
  }
}

void fill_ulsch(PHY_VARS_eNB *eNB,int UE_id,nfapi_ul_config_ulsch_pdu *ulsch_pdu,int frame,int subframe)
{
  uint8_t harq_pid;
  //uint8_t UE_id;
  boolean_t new_ulsch = (find_ulsch(ulsch_pdu->ulsch_pdu_rel8.rnti,eNB,SEARCH_EXIST)==-1) ? TRUE : FALSE;

  //AssertFatal((UE_id=find_ulsch(ulsch_pdu->ulsch_pdu_rel8.rnti,eNB,SEARCH_EXIST_OR_FREE))>=0,
  //        "No existing/free UE ULSCH for rnti %x\n",ulsch_pdu->ulsch_pdu_rel8.rnti);

  LTE_eNB_ULSCH_t *ulsch=eNB->ulsch[UE_id];
  LTE_DL_FRAME_PARMS *frame_parms = &eNB->frame_parms;

  int use_srs = 0;

  harq_pid = ulsch_pdu->ulsch_pdu_rel8.harq_process_number;

  ulsch->harq_mask |= 1 << harq_pid;

  ulsch->harq_processes[harq_pid]->frame                                 = frame;
  ulsch->harq_processes[harq_pid]->subframe                              = subframe;
  ulsch->harq_processes[harq_pid]->handled                               = 0;

  ulsch->harq_processes[harq_pid]->first_rb                              = ulsch_pdu->ulsch_pdu_rel8.resource_block_start;
  ulsch->harq_processes[harq_pid]->nb_rb                                 = ulsch_pdu->ulsch_pdu_rel8.number_of_resource_blocks;

  //AssertFatal(ulsch->harq_processes[harq_pid]->nb_rb>0,"nb_rb = 0\n");
  if(ulsch->harq_processes[harq_pid]->nb_rb == 0){
    LOG_E(PHY, "fill_ulsch UE_id %d nb_rb = 0\n", UE_id);
  }

  ulsch->harq_processes[harq_pid]->dci_alloc                             = 1;
  ulsch->harq_processes[harq_pid]->rar_alloc                             = 0;
  ulsch->harq_processes[harq_pid]->n_DMRS                                = ulsch_pdu->ulsch_pdu_rel8.cyclic_shift_2_for_drms;
  
  ulsch->harq_processes[harq_pid]->Nsymb_pusch                           = 12-(frame_parms->Ncp<<1)-(use_srs==0?0:1);
  ulsch->harq_processes[harq_pid]->srs_active                            = use_srs;
  
  //Mapping of cyclic shift field in DCI format0 to n_DMRS2 (3GPP 36.211, Table 5.5.2.1.1-1)
  if(ulsch->harq_processes[harq_pid]->n_DMRS == 0)
    ulsch->harq_processes[harq_pid]->n_DMRS2 = 0;
  else if(ulsch->harq_processes[harq_pid]->n_DMRS == 1)
    ulsch->harq_processes[harq_pid]->n_DMRS2 = 6;
  else if(ulsch->harq_processes[harq_pid]->n_DMRS == 2)
    ulsch->harq_processes[harq_pid]->n_DMRS2 = 3;
  else if(ulsch->harq_processes[harq_pid]->n_DMRS == 3)
    ulsch->harq_processes[harq_pid]->n_DMRS2 = 4;
  else if(ulsch->harq_processes[harq_pid]->n_DMRS == 4)
    ulsch->harq_processes[harq_pid]->n_DMRS2 = 2;
  else if(ulsch->harq_processes[harq_pid]->n_DMRS == 5)
    ulsch->harq_processes[harq_pid]->n_DMRS2 = 8;
  else if(ulsch->harq_processes[harq_pid]->n_DMRS == 6)
    ulsch->harq_processes[harq_pid]->n_DMRS2 = 10;
  else if(ulsch->harq_processes[harq_pid]->n_DMRS == 7)
    ulsch->harq_processes[harq_pid]->n_DMRS2 = 9;
  
  LOG_D(PHY,"[eNB %d][PUSCH %d] Frame %d, Subframe %d Programming PUSCH with n_DMRS2 %d (cshift %d) ulsch:ndi:%d ulsch_pdu:ndi:%d new_ulsch:%d status:%d ulsch_pdu:rvidx:%d\n",
	eNB->Mod_id,harq_pid,frame,subframe,
        ulsch->harq_processes[harq_pid]->n_DMRS2,
        ulsch->harq_processes[harq_pid]->n_DMRS,
	ulsch->harq_processes[harq_pid]->ndi, ulsch_pdu->ulsch_pdu_rel8.new_data_indication, new_ulsch, ulsch->harq_processes[harq_pid]->status,
	ulsch_pdu->ulsch_pdu_rel8.redundancy_version);
  
  ulsch->harq_processes[harq_pid]->rvidx = ulsch_pdu->ulsch_pdu_rel8.redundancy_version;
  if(ulsch_pdu->ulsch_pdu_rel8.modulation_type!=0)
  ulsch->harq_processes[harq_pid]->Qm    = ulsch_pdu->ulsch_pdu_rel8.modulation_type;
  // Set O_ACK to 0 by default, will be set of DLSCH is scheduled and needs to be 
  ulsch->harq_processes[harq_pid]->O_ACK         = 0;

  if ((ulsch->harq_processes[harq_pid]->status == SCH_IDLE) ||
      (ulsch->harq_processes[harq_pid]->ndi    != ulsch_pdu->ulsch_pdu_rel8.new_data_indication) ||
	  (new_ulsch == TRUE)){
    ulsch->harq_processes[harq_pid]->status        = ACTIVE;
    
    ulsch->harq_processes[harq_pid]->TBS           = ulsch_pdu->ulsch_pdu_rel8.size<<3;
    
    ulsch->harq_processes[harq_pid]->Msc_initial   = 12*ulsch_pdu->ulsch_pdu_rel8.number_of_resource_blocks;
    ulsch->harq_processes[harq_pid]->Nsymb_initial = ulsch->harq_processes[harq_pid]->Nsymb_pusch;
    ulsch->harq_processes[harq_pid]->round         = 0;
    ulsch->harq_processes[harq_pid]->ndi           = ulsch_pdu->ulsch_pdu_rel8.new_data_indication;
    // note here, the CQI bits need to be kept constant as in initial transmission
    // set to 0 in initial transmission, and don't touch them during retransmissions
    // will be set if MAC has activated ULSCH_CQI_RI_PDU or ULSCH_CQI_HARQ_RI_PDU
    ulsch->harq_processes[harq_pid]->Or1           = 0;
    ulsch->harq_processes[harq_pid]->Or2           = 0;
  }
  else {
      ulsch->harq_processes[harq_pid]->round++;
      ulsch->harq_processes[harq_pid]->TBS           = ulsch_pdu->ulsch_pdu_rel8.size<<3;
      ulsch->harq_processes[harq_pid]->Msc_initial   = 12*ulsch_pdu->ulsch_pdu_rel8.number_of_resource_blocks;
  }
  ulsch->rnti = ulsch_pdu->ulsch_pdu_rel8.rnti;
  LOG_D(PHY,"Filling ULSCH %x (UE_id %d) (new_ulsch %d) for Frame %d, Subframe %d : harq_pid %d, status %d, handled %d, first_rb %d, nb_rb %d, rvidx %d, Qm %d, TBS %d, round %d \n",
	ulsch->rnti,
        UE_id,
        new_ulsch,
	frame,
	subframe,
	harq_pid,
	ulsch->harq_processes[harq_pid]->status,
	ulsch->harq_processes[harq_pid]->handled,
	ulsch->harq_processes[harq_pid]->first_rb,
	ulsch->harq_processes[harq_pid]->nb_rb,
	ulsch->harq_processes[harq_pid]->rvidx,
	ulsch->harq_processes[harq_pid]->Qm,
	ulsch->harq_processes[harq_pid]->TBS,
	ulsch->harq_processes[harq_pid]->round);  
}


