#include "PHY/defs.h"
#include "PHY/defs_nb_iot.h"
#include "PHY/extern.h"
#include "SCHED/defs.h"
#include "SCHED/extern.h"
#include "PHY/LTE_TRANSPORT/if4_tools.h"
#include "PHY/LTE_TRANSPORT/if5_tools.h"

#ifdef EMOS
#include "SCHED/phy_procedures_emos.h"
#endif

// for NB-IoT
#include "SCHED/defs_nb_iot.h"

//#define DEBUG_PHY_PROC (Already defined in cmake)
//#define DEBUG_ULSCH

#include "LAYER2/MAC/extern.h"
#include "LAYER2/MAC/defs.h"
#include "UTIL/LOG/log.h"
#include "UTIL/LOG/vcd_signal_dumper.h"

#include "T.h"

#include "assertions.h"
#include "msc.h"

#include <time.h>

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


#if defined(FLEXRAN_AGENT_SB_IF)
//Agent-related headers
#include "ENB_APP/flexran_agent_extern.h"
#include "ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h"
#include "LAYER2/MAC/flexran_agent_mac_proto.h"
#endif

//#define DIAG_PHY

#define NS_PER_SLOT 500000

#define PUCCH 1

//DCI_ALLOC_t dci_alloc[8];

#ifdef EMOS
fifo_dump_emos_eNB emos_dump_eNB;
#endif

#if defined(SMBV) 
extern const char smbv_fname[];
extern unsigned short config_frames[4];
extern uint8_t smbv_frame_cnt;
#endif

#ifdef DIAG_PHY
extern int rx_sig_fifo;
#endif



/* For NB-IoT, we put NPBCH in later part, since it would be scheduled by MAC scheduler
* It generates NRS/NPSS/NSSS
*
*/
void NB_common_signal_procedures (PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) 
{
  LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
  int **txdataF = eNB->common_vars.txdataF[0];
  int subframe = proc->subframe_tx;
  int frame = proc->frame_tx;
  uint16_t Ntti = 10;//ntti = 10
  int RB_IoT_ID;// RB reserved for NB-IoT, PRB index
  int With_NSSS;// With_NSSS = 1; if the frame include a sub-Frame with NSSS signal
  
  /*NSSS only happened in the even frame*/
  if(frame%2==0)
    {
      With_NSSS = 1;
    }
  else
    {
      With_NSSS = 0;
    }
    
  /*NPSS when subframe 5*/
  if(subframe == 5)
    {
      generate_npss_NB_IoT(txdataF,
                 AMP,
                 fp,
                 3,
                 0,
                 RB_IoT_ID);
    }
    
  /*NSSS when subframe 9 on even frame*/
  else if((subframe == 9)&&(With_NSSS == 1))
    {
      generate_sss_NB_IoT(txdataF,
                          AMP,
                          fp,
                          3,
                          0,
                          frame,
                          RB_IoT_ID);
    }

  else
  {
    /*NRS*/
    generate_pilots_NB_IoT(eNB,
               txdataF,
               AMP,
               Ntti,
               RB_IoT_ID,
               With_NSSS);
  }
  
}

void NB_phy_procedures_eNB_uespec_RX(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc)
{
  //RX processing for ue-specific resources (i

  uint32_t ret=0,i,j,k;
  uint32_t harq_pid,round;
  int sync_pos;
  uint16_t rnti=0;
  uint8_t access_mode;
  LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;

  const int subframe = proc->subframe_rx;
  const int frame    = proc->frame_rx;
  
  /*NB-IoT IF module Common setting*/
  
  UL_IND_t UL_INFO;

  UL_INFO.module_id = eNB->Mod_id;
  UL_INFO.CC_id = eNB->CC_id;
  UL_INFO.frame =  frame;
  UL_INFO.subframe = subframe;


  T(T_ENB_PHY_UL_TICK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe));

  T(T_ENB_PHY_INPUT_SIGNAL, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(0),
    T_BUFFER(&eNB->common_vars.rxdata[0][0][subframe*eNB->frame_parms.samples_per_tti],
             eNB->frame_parms.samples_per_tti * 4));

  //if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)!=SF_UL)) return;


  //check if any RB using in this UL subframe
  eNB->rb_mask_ul[0]=0;
  eNB->rb_mask_ul[1]=0;
  eNB->rb_mask_ul[2]=0;
  eNB->rb_mask_ul[3]=0;

  // Check for active processes in current subframe
  // NB-IoT subframe2harq_pid is in dci_tools, always set the frame type to FDD, this would become simpler.
  harq_pid = subframe2harq_pid(fp,frame,subframe);

  // delete the cba
  // delete the srs
  
  /*Loop over the UE, i is the UE ID */
  for (i=0; i<NUMBER_OF_UE_MAX; i++) 
    {

      // delete srs 
      // delete Pucch procedure

      // check for Msg3
      if (eNB->mac_enabled==1) 
        {
          if (eNB->UE_stats[i].mode == RA_RESPONSE) 
            {
	             /*Process Msg3 TODO*/
              //process_Msg3(eNB,proc,i,harq_pid);
            }
        }

      eNB->pusch_stats_rb[i][(frame*10)+subframe] = -63;
      eNB->pusch_stats_round[i][(frame*10)+subframe] = 0;
      eNB->pusch_stats_mcs[i][(frame*10)+subframe] = -63;

      /*Check if this UE is has ULSCH scheduling*/
      if ((eNB->ulsch[i]) &&
          (eNB->ulsch[i]->rnti>0) &&
          (eNB->ulsch[i]->harq_processes[harq_pid]->subframe_scheduling_flag==1)) 
        {
          // UE is has ULSCH scheduling
          round = eNB->ulsch[i]->harq_processes[harq_pid]->round;
          /*NB-IoT The nb_rb always set to 1 */
          for (int rb=0;rb<=eNB->ulsch[i]->harq_processes[harq_pid]->nb_rb;rb++) 
            {
	           int rb2 = rb+eNB->ulsch[i]->harq_processes[harq_pid]->first_rb;
              eNB->rb_mask_ul[rb2>>5] |= (1<<(rb2&31));
            }

          /*Log for what kind of the ULSCH Reception*/

          /*Calculate for LTE C-RS*/
          //nPRS = fp->pusch_config_common.ul_ReferenceSignalsPUSCH.nPRS[subframe<<1];

          //eNB->ulsch[i]->cyclicShift = (eNB->ulsch[i]->harq_processes[harq_pid]->n_DMRS2 + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift +nPRS)%12;

          if (fp->frame_type == FDD ) 
            {
              int sf = (subframe<4) ? (subframe+6) : (subframe-4);
              /*After Downlink Data transmission, simply have a notice to received ACK from PUCCH, I think it's not use for now */
              if (eNB->dlsch[i][0]->subframe_tx[sf]>0) // we have downlink transmission
                { 
                  eNB->ulsch[i]->harq_processes[harq_pid]->O_ACK = 1;
                } 
              else 
                {
                  eNB->ulsch[i]->harq_processes[harq_pid]->O_ACK = 0;
                }
            }

          eNB->pusch_stats_rb[i][(frame*10)+subframe] = eNB->ulsch[i]->harq_processes[harq_pid]->nb_rb;
          eNB->pusch_stats_round[i][(frame*10)+subframe] = eNB->ulsch[i]->harq_processes[harq_pid]->round;
          eNB->pusch_stats_mcs[i][(frame*10)+subframe] = eNB->ulsch[i]->harq_processes[harq_pid]->mcs;

          rx_ulsch(eNB,proc,
                  eNB->UE_stats[i].sector,  // this is the effective sector id
                  i,
                  eNB->ulsch,
                  0);

          ret = ulsch_decoding(eNB,proc,
                             i,
                             0, // control_only_flag
                             eNB->ulsch[i]->harq_processes[harq_pid]->V_UL_DAI,
			                       eNB->ulsch[i]->harq_processes[harq_pid]->nb_rb>20 ? 1 : 0);

          //compute the expected ULSCH RX power (for the stats)
          eNB->ulsch[(uint32_t)i]->harq_processes[harq_pid]->delta_TF = get_hundred_times_delta_IF_eNB(eNB,i,harq_pid, 0); // 0 means bw_factor is not considered
          eNB->UE_stats[i].ulsch_decoding_attempts[harq_pid][eNB->ulsch[i]->harq_processes[harq_pid]->round]++;
          eNB->ulsch[i]->harq_processes[harq_pid]->subframe_scheduling_flag=0;
          if (eNB->ulsch[i]->harq_processes[harq_pid]->cqi_crc_status == 1) 
            {
              extract_CQI(eNB->ulsch[i]->harq_processes[harq_pid]->o,
                        eNB->ulsch[i]->harq_processes[harq_pid]->uci_format,
                        &eNB->UE_stats[i],
                      fp->N_RB_DL,
                      &rnti, &access_mode);
              eNB->UE_stats[i].rank = eNB->ulsch[i]->harq_processes[harq_pid]->o_RI[0];
            }

          if (ret == (1+MAX_TURBO_ITERATIONS)) 
            {
              T(T_ENB_PHY_ULSCH_UE_NACK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(i), T_INT(eNB->ulsch[i]->rnti),
                T_INT(harq_pid));

              eNB->UE_stats[i].ulsch_round_errors[harq_pid][eNB->ulsch[i]->harq_processes[harq_pid]->round]++;
              eNB->ulsch[i]->harq_processes[harq_pid]->phich_active = 1;
              eNB->ulsch[i]->harq_processes[harq_pid]->phich_ACK = 0;
              eNB->ulsch[i]->harq_processes[harq_pid]->round++;

              LOG_D(PHY,"[eNB][PUSCH %d] Increasing to round %d\n",harq_pid,eNB->ulsch[i]->harq_processes[harq_pid]->round);

          if (eNB->ulsch[i]->Msg3_flag == 1) 
            {
	           /*dump_ulsch(eNB,proc,i);
	             exit(-1);*/

            /*In NB-IoT MSG3 */
            // activate retransmission for Msg3 (signalled to UE PHY by DCI
            eNB->ulsch[(uint32_t)i]->Msg3_active = 1;
            /* Need to check the procedure for NB-IoT (MSG3) retransmission
            get_Msg3_alloc_ret(fp,subframe,frame,&eNB->ulsch[i]->Msg3_frame,&eNB->ulsch[i]->Msg3_subframe);
            mac_xface->set_msg3_subframe(eNB->Mod_id, eNB->CC_id, frame, subframe, eNB->ulsch[i]->rnti,eNB->ulsch[i]->Msg3_frame, eNB->ulsch[i]->Msg3_subframe);
            */
            T(T_ENB_PHY_MSG3_ALLOCATION, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe),
                  T_INT(i), T_INT(eNB->ulsch[i]->rnti), T_INT(0 /* 0 is for retransmission*/),
                  T_INT(eNB->ulsch[i]->Msg3_frame), T_INT(eNB->ulsch[i]->Msg3_subframe));     
            } // This is Msg3 error
          else 
            { //normal ULSCH
              if (eNB->ulsch[i]->harq_processes[harq_pid]->round== eNB->ulsch[i]->Mlimit) 
                {
                  eNB->ulsch[i]->harq_processes[harq_pid]->round=0;
                  eNB->ulsch[i]->harq_processes[harq_pid]->phich_active=0;
                  eNB->UE_stats[i].ulsch_errors[harq_pid]++;
                  eNB->UE_stats[i].ulsch_consecutive_errors++; 
                  /*if (eNB->ulsch[i]->harq_processes[harq_pid]->nb_rb > 20) {
		                dump_ulsch(eNB,proc,i);
	 	              exit(-1);
                  }*/
	                // indicate error to MAC
	                if (eNB->mac_enabled == 1)
                    {
                      //instead rx_sdu to report The Uplink data not received successfully to MAC
                      (UL_INFO.crc_ind.crc_pdu_list+i)->crc_indication_rel8.crc_flag= 1;
                       UL_INFO.crc_ind.number_of_crcs++;
                      (UL_INFO.RX_NPUSCH.rx_pdu_list+i)->rx_ue_information.rnti= eNB->ulsch[i]->rnti;
                      (UL_INFO.RX_NPUSCH.rx_pdu_list+i)->data= NULL;
                      (UL_INFO.RX_NPUSCH.rx_pdu_list+i)->rx_indication_rel8.length = 0;
                      (UL_INFO.RX_NPUSCH.rx_pdu_list+i)->rx_ue_information.harq_pid = harq_pid;
                       UL_INFO.RX_NPUSCH.number_of_pdus++;
                    }
                }
            }
        }  // ulsch in error
        else 
          {
            T(T_ENB_PHY_ULSCH_UE_ACK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(i), T_INT(eNB->ulsch[i]->rnti),
              T_INT(harq_pid));

          // Delete MSG3  log for the PHICH 

          for (j=0; j<fp->nb_antennas_rx; j++)
          //this is the RSSI per RB
          eNB->UE_stats[i].UL_rssi[j] =
            dB_fixed(eNB->pusch_vars[i]->ulsch_power[j]*
                     (eNB->ulsch[i]->harq_processes[harq_pid]->nb_rb*12)/
                     fp->ofdm_symbol_size) -
            eNB->rx_total_gain_dB -
            hundred_times_log10_NPRB[eNB->ulsch[i]->harq_processes[harq_pid]->nb_rb-1]/100 -
            get_hundred_times_delta_IF_eNB(eNB,i,harq_pid, 0)/100;
          //for NB-IoT PHICH not work
	        /*eNB->ulsch[i]->harq_processes[harq_pid]->phich_active = 1;
          eNB->ulsch[i]->harq_processes[harq_pid]->phich_ACK = 1;*/
          eNB->ulsch[i]->harq_processes[harq_pid]->round = 0;
          eNB->UE_stats[i].ulsch_consecutive_errors = 0;

          if (eNB->ulsch[i]->Msg3_flag == 1) 
            {
	            if (eNB->mac_enabled==1) 
                {
	                LOG_I(PHY,"[eNB %d][RAPROC] Frame %d Terminating ra_proc for harq %d, UE %d\n",
		                    eNB->Mod_id,frame,harq_pid,i);
	                if (eNB->mac_enabled)
                    {
                      // store successful MSG3 in UL_Info instead rx_sdu
                      (UL_INFO.crc_ind.crc_pdu_list+i)->crc_indication_rel8.crc_flag= 0;
                      UL_INFO.crc_ind.number_of_crcs++;
                      (UL_INFO.RX_NPUSCH.rx_pdu_list+i)->rx_ue_information.rnti= eNB->ulsch[i]->rnti;
                      (UL_INFO.RX_NPUSCH.rx_pdu_list+i)->data = eNB->ulsch[i]->harq_processes[harq_pid]->b;
                      (UL_INFO.RX_NPUSCH.rx_pdu_list+i)->rx_indication_rel8.length = eNB->ulsch[i]->harq_processes[harq_pid]->TBS>>3;
                      (UL_INFO.RX_NPUSCH.rx_pdu_list+i)->rx_ue_information.harq_pid = harq_pid;
                      UL_INFO.RX_NPUSCH.number_of_pdus++;
                    }

	                /* Need check if this needed in NB-IoT
	                // one-shot msg3 detection by MAC: empty PDU (e.g. CRNTI)
	                if (eNB->ulsch[i]->Msg3_flag == 0 ) {
	               eNB->UE_stats[i].mode = PRACH;
	               mac_xface->cancel_ra_proc(eNB->Mod_id,
					       eNB->CC_id,
					       frame,
					       eNB->UE_stats[i].crnti);
	               mac_phy_remove_ue(eNB->Mod_id,eNB->UE_stats[i].crnti);
	               eNB->ulsch[(uint32_t)i]->Msg3_active = 0;
	               } // Msg3_flag == 0*/
	    
	            } // mac_enabled==1

            eNB->UE_stats[i].mode = PUSCH;
            eNB->ulsch[i]->Msg3_flag = 0;

	          LOG_D(PHY,"[eNB %d][RAPROC] Frame %d : RX Subframe %d Setting UE %d mode to PUSCH\n",eNB->Mod_id,frame,subframe,i);

            /*Init HARQ parameters, need to check*/
            for (k=0; k<8; k++) 
              { //harq_processes
                for (j=0; j<eNB->dlsch[i][0]->Mlimit; j++) 
                  {
                    eNB->UE_stats[i].dlsch_NAK[k][j]=0;
                    eNB->UE_stats[i].dlsch_ACK[k][j]=0;
                    eNB->UE_stats[i].dlsch_trials[k][j]=0;
                  }

                eNB->UE_stats[i].dlsch_l2_errors[k]=0;
                eNB->UE_stats[i].ulsch_errors[k]=0;
                eNB->UE_stats[i].ulsch_consecutive_errors=0;

                for (j=0; j<eNB->ulsch[i]->Mlimit; j++) 
                  {
                    eNB->UE_stats[i].ulsch_decoding_attempts[k][j]=0;
                    eNB->UE_stats[i].ulsch_decoding_attempts_last[k][j]=0;
                    eNB->UE_stats[i].ulsch_round_errors[k][j]=0;
                    eNB->UE_stats[i].ulsch_round_fer[k][j]=0;
                  }
              }

            eNB->UE_stats[i].dlsch_sliding_cnt=0;
            eNB->UE_stats[i].dlsch_NAK_round0=0;
            eNB->UE_stats[i].dlsch_mcs_offset=0;
          } // Msg3_flag==1
	       else 
          {  // Msg3_flag == 0
	          if (eNB->mac_enabled==1) 
              {
                  // store successful Uplink data in UL_Info instead rx_sdu
                  (UL_INFO.crc_ind.crc_pdu_list+i)->crc_indication_rel8.crc_flag= 0;
                  UL_INFO.crc_ind.number_of_crcs++;
                  (UL_INFO.RX_NPUSCH.rx_pdu_list+i)->rx_ue_information.rnti= eNB->ulsch[i]->rnti;
                  (UL_INFO.RX_NPUSCH.rx_pdu_list+i)->data = eNB->ulsch[i]->harq_processes[harq_pid]->b;
                  (UL_INFO.RX_NPUSCH.rx_pdu_list+i)->rx_indication_rel8.length = eNB->ulsch[i]->harq_processes[harq_pid]->TBS>>3;
                  (UL_INFO.RX_NPUSCH.rx_pdu_list+i)->rx_ue_information.harq_pid  = harq_pid;
                  UL_INFO.RX_NPUSCH.number_of_pdus++;
	    
	            } // mac_enabled==1
          } // Msg3_flag == 0

            // estimate timing advance for MAC
              sync_pos = lte_est_timing_advance_pusch(eNB,i);
              eNB->UE_stats[i].timing_advance_update = sync_pos - fp->nb_prefix_samples/4; //to check

      }  // ulsch not in error


      // Process HARQ only in NPUSCH
      /*process_HARQ_feedback(i,
                            eNB,proc,
                            1, // pusch_flag
                            0,
                            0,
                            0);*/


      

    } // ulsch[0] && ulsch[0]->rnti>0 && ulsch[0]->subframe_scheduling_flag == 1


    // update ULSCH statistics for tracing




  } // loop i=0 ... NUMBER_OF_UE_MAX-1



  /*Exact not here, but use to debug*/
  if_inst->UL_indication(UL_INFO);

}

#undef DEBUG_PHY_PROC

/*Generate eNB dlsch params for NB-IoT, modify the input to the Sched Rsp variable*/

void NB_generate_eNB_dlsch_params(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t * proc,Sched_Rsp_t *Sched_Rsp,const int UE_id) 
{
  LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
  int frame = proc->frame_tx;
  int subframe = proc->subframe_tx;
  DCI_CONTENT DCI_Content[2]; //max number of DCI in a single subframe = 2 (may put this as a global variable)

  //DCI_Content = (DCI_CONTENT*) malloc(sizeof(DCI_CONTENT));

  // In NB-IoT, there is no DCI for SI, we might use the scheduling infomation from SIB1-NB to get the phyical layer configuration.

  //mapping the fapi parameters to the oai parameters

  for (int i = 0; i< Sched_Rsp->NB_DL.NB_DCI.DL_DCI.number_dci; i++){
  switch (Sched_Rsp->NB_DL.NB_DCI.DCI_Format){
    case DCIFormatN1_RAR:
      //DCI format N1 to RAR
      DCI_Content[i]->DCIN1_RAR.type = 1;
      //check if this work
      DCI_Content[i]->DCIN1_RAR.orderIndicator = Sched_Rsp->NB_DL.NB_DCI.DL_DCI.dl_config_pdu_list[i]->npdcch_pdu.npdcch_pdu_rel13.npdcch_order_indication;
      DCI_Content[i]->DCIN1_RAR.Scheddly = Sched_Rsp->NB_DL.NB_DCI.DL_DCI.dl_config_pdu_list->npdcch_pdu.npdcch_pdu_rel13.scheduling_delay;
      DCI_Content[i]->DCIN1_RAR.ResAssign = Sched_Rsp->NB_DL.NB_DCI.DL_DCI.dl_config_pdu_list->npdcch_pdu.npdcch_pdu_rel13.resource_assignment;
      DCI_Content[i]->DCIN1_RAR.mcs = Sched_Rsp->NB_DL.NB_DCI.DL_DCI.dl_config_pdu_list->npdcch_pdu.npdcch_pdu_rel13.mcs;
      DCI_Content[i]->DCIN1_RAR.ndi = Sched_Rsp->NB_DL.NB_DCI.DL_DCI.dl_config_pdu_list->npdcch_pdu.npdcch_pdu_rel13.new_data_indicator;
      DCI_Content[i]->DCIN1_RAR.HARQackRes = Sched_Rsp->NB_DL.NB_DCI.DL_DCI.dl_config_pdu_list->npdcch_pdu.npdcch_pdu_rel13.harq_ack_resource;
      DCI_Content[i]->DCIN1_RAR.DCIRep = Sched_Rsp->NB_DL.NB_DCI.DL_DCI.dl_config_pdu_list->npdcch_pdu.npdcch_pdu_rel13.dci_subframe_repetition_number;

      // configure dlsch parameters and CCE index
      LOG_D(PHY,"Generating dlsch params for RA_RNTI\n");

      NB_generate_eNB_dlsch_params_from_dci(frame,
                                            subframe,
											DCI_Content[i],
                                            Sched_Rsp->NB_DL.NB_DCI.DL_DCI.dl_config_pdu_list->npdcch_pdu.npdcch_pdu_rel13.rnti,
                                            DCIFormatN1_RAR,
                                            &eNB->dlsch_ra,
                                            fp,
                                            Sched_Rsp->NB_DL.NB_DCI.DL_DCI.dl_config_pdu_list->npdcch_pdu.npdcch_pdu_rel13.aggregation_level,
											Sched_Rsp->NB_DL.NB_DCI.DL_DCI.number_dci
                                            );
      break;
    case DCIFormatN1:
      //DCI format N1 to DLSCH
    	 DCI_Content[i]->DCIN1_RAR.type = 1;
    	 DCI_Content[i]->DCIN1_RAR.orderIndicator = Sched_Rsp->NB_DL.NB_DCI.DL_DCI.dl_config_pdu_list->npdcch_pdu.npdcch_pdu_rel13.npdcch_order_indication;
    	 DCI_Content[i]->DCIN1_RAR.Scheddly = Sched_Rsp->NB_DL.NB_DCI.DL_DCI.dl_config_pdu_list->npdcch_pdu.npdcch_pdu_rel13.scheduling_delay;
    	 DCI_Content[i]->DCIN1_RAR.ResAssign = Sched_Rsp->NB_DL.NB_DCI.DL_DCI.dl_config_pdu_list->npdcch_pdu.npdcch_pdu_rel13.resource_assignment;
    	 DCI_Content[i]->DCIN1_RAR.mcs = Sched_Rsp->NB_DL.NB_DCI.DL_DCI.dl_config_pdu_list->npdcch_pdu.npdcch_pdu_rel13.mcs;
    	 DCI_Content[i]->DCIN1_RAR.ndi = Sched_Rsp->NB_DL.NB_DCI.DL_DCI.dl_config_pdu_list->npdcch_pdu.npdcch_pdu_rel13.new_data_indicator;
    	 DCI_Content[i]->DCIN1_RAR.HARQackRes = Sched_Rsp->NB_DL.NB_DCI.DL_DCI.dl_config_pdu_list->npdcch_pdu.npdcch_pdu_rel13.harq_ack_resource;
    	 DCI_Content[i]->DCIN1_RAR.DCIRep = Sched_Rsp->NB_DL.NB_DCI.DL_DCI.dl_config_pdu_list->npdcch_pdu.npdcch_pdu_rel13.dci_subframe_repetition_number;

      NB_generate_eNB_dlsch_params_from_dci(frame,
                                            subframe,
											DCI_Content[i],
                                            Sched_Rsp->NB_DL.NB_DCI.DL_DCI.dl_config_pdu_list->npdcch_pdu.npdcch_pdu_rel13.rnti,
                                            DCIFormatN0,
                                            eNB->dlsch[(uint8_t)UE_id],
                                            fp,
                                            Sched_Rsp->NB_DL.NB_DCI.DL_DCI.dl_config_pdu_list->npdcch_pdu.npdcch_pdu_rel13.aggregation_level,
                                            Sched_Rsp->NB_DL.NB_DCI.DL_DCI.number_dci
                                            );
      break;
    /*TODO reserve for the N2 DCI*/
    case DCIFormatN2_Pag:
    	LOG_I(PHY, "Paging is not implemented, DCIFormatN2_Pag cannot be elaborated\n");
    	break;

  }

  }



  
}

void NB_generate_eNB_ulsch_params(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,Sched_Rsp_t *Sched_Rsp,const int UE_id) {

  int harq_pid = 0;

  DCI_CONTENT DCI_Content[2]; //max number of DCI in a single subframe = 2 (may put this as a global variable)

  for(int i = 0; i<Sched_Rsp->NB_DL.NB_DCI.UL_DCI.number_of_dci; i++)
  {

  //mapping the fapi parameters to the OAI parameters
  DCI_Content[i]->DCIN0.type = 0;
  DCI_Content[i]->DCIN0.scind = Sched_Rsp->NB_DL.NB_DCI.UL_DCI.hi_dci0_pdu_list->npdcch_dci_pdu.npdcch_dci_pdu_rel13.subcarrier_indication;
  DCI_Content[i]->DCIN0.ResAssign = Sched_Rsp->NB_DL.NB_DCI.UL_DCI.hi_dci0_pdu_list->npdcch_dci_pdu.npdcch_dci_pdu_rel13.subcarrier_indication;
  DCI_Content[i]->DCIN0.mcs = Sched_Rsp->NB_DL.NB_DCI.UL_DCI.hi_dci0_pdu_list->npdcch_dci_pdu.npdcch_dci_pdu_rel13.mcs;
  DCI_Content[i]->DCIN0.ndi = Sched_Rsp->NB_DL.NB_DCI.UL_DCI.hi_dci0_pdu_list->npdcch_dci_pdu.npdcch_dci_pdu_rel13.new_data_indicator;
  DCI_Content[i]->DCIN0.Scheddly = Sched_Rsp->NB_DL.NB_DCI.UL_DCI.hi_dci0_pdu_list->npdcch_dci_pdu.npdcch_dci_pdu_rel13.scheduling_delay;
  DCI_Content[i]->DCIN0.RepNum = Sched_Rsp->NB_DL.NB_DCI.UL_DCI.hi_dci0_pdu_list->npdcch_dci_pdu.npdcch_dci_pdu_rel13.repetition_number;
  DCI_Content[i]->DCIN0.rv = Sched_Rsp->NB_DL.NB_DCI.UL_DCI.hi_dci0_pdu_list->npdcch_dci_pdu.npdcch_dci_pdu_rel13.redudancy_version;
  DCI_Content[i]->DCIN0.DCIRep = Sched_Rsp->NB_DL.NB_DCI.UL_DCI.hi_dci0_pdu_list->npdcch_dci_pdu.npdcch_dci_pdu_rel13.dci_subframe_repetition_number;


  /*Log for generate ULSCH DCI*/

  NB_generate_eNB_ulsch_params_from_dci(eNB,
                                        proc,
                                        DCI_Content[i],
                                        Sched_Rsp->NB_DL.NB_DCI.UL_DCI.hi_dci0_pdu_list->npdcch_dci_pdu.npdcch_dci_pdu_rel13.rnti,
                                        DCIFormatN0,
                                        UE_id,
                                        Sched_Rsp->NB_DL.NB_DCI.UL_DCI.hi_dci0_pdu_list->npdcch_dci_pdu.npdcch_dci_pdu_rel13.aggregation_level,
										Sched_Rsp->NB_DL.NB_DCI.UL_DCI.number_of_dci
                                        );  

  
  //LOG for ULSCH DCI Resource allocation
  
  //CBA is not used in NB-IoT
//  if ((Sched_Rsp->NB_DL.NB_DCI.UL_DCI.npdcch_dci_pdu_rel13.rnti  >= CBA_RNTI) && (Sched_Rsp->NB_DL.NB_DCI.UL_DCI.npdcch_dci_pdu_rel13.rnti < P_RNTI))
//    eNB->ulsch[(uint32_t)UE_id]->harq_processes[harq_pid]->subframe_cba_scheduling_flag = 1;
//  else
    eNB->ulsch[(uint32_t)UE_id]->harq_processes[harq_pid]->subframe_scheduling_flag = 1;
  
  }
}

/*
 * for NB-IoT
 * this function is called by the PHy procedure TX in 3 possible occasion:
 * 1) we manage BCCH pdu
 * 2) we manage RA dlsch pdu (to be checked if needed in our case)
 * 3) UE specific dlsch pdu
 * ** we need to know if exist and which value has the eutracontrolRegionSize (TS 36.213 ch 16.4.1.4) whenever we are in In-band mode
 * ** CQI and PMI are not present in NB-IoT
 * ** redundancy version exist only in UL for NB-IoT and not in DL
 */
void pdsch_procedures_NB(PHY_VARS_eNB *eNB,
						eNB_rxtx_proc_t *proc, //Context data structure for RX/TX portion of subframe processing
						NB_IoT_eNB_DLSCH_t *dlsch,
						NB_IoT_eNB_DLSCH_t *dlsch1,//this is the second colum of the UE specific LTE_eNB_DLSCH_t (see the PHY/defs.h line 471)
						LTE_eNB_UE_stats *ue_stats,
						int ra_flag,// set to 1 only in case of RA
						int num_pdcch_symbols,
						uint32_t segment_length, //lenght of the  DLSCH PDU from the Sched_rsp (FAPI nomenclature)
						uint8_t* segment_data // the DLSCH PDU itself from the Sched_rsp (FAPI nomenclature)
							)
{

  int frame=proc->frame_tx;
  int subframe=proc->subframe_tx;
  //int harq_pid = dlsch->current_harq_pid;
  LTE_DL_eNB_HARQ_t dlsch_harq=dlsch->harq_process; //TODO: review the HARQ process for NB_IoT
  int input_buffer_length = dlsch_harq->TBS/8; // get in byte //to be changed for NB_IoT????
  NB_DL_FRAME_PARMS *fp=&eNB->frame_parms_nb_iot;
  uint8_t *DLSCH_pdu=NULL;
  uint8_t DLSCH_pdu_tmp[input_buffer_length+4]; //[768*8];
  uint8_t DLSCH_pdu_rar[256];
  int i;



  LOG_D(PHY,
	"[eNB %"PRIu8"][PDSCH rnti%"PRIx16"/HARQ proc%"PRIu8"] Frame %d, subframe %d: Generating PDSCH/DLSCH with input size = %"PRIu16", G %d, nb_rb %"PRIu16", mcs %"PRIu8"(round %"PRIu8")\n",
	eNB->Mod_id,
	dlsch->rnti,
	harq_pid,
	frame, subframe, input_buffer_length,
	get_G(fp,dlsch_harq->nb_rb,dlsch_harq->rb_alloc,get_Qm(dlsch_harq->mcs),dlsch_harq->Nl, num_pdcch_symbols, frame, subframe, dlsch_harq->mimo_mode==TM7?7:0),
	dlsch_harq->nb_rb, //in NB_IoT we not need it???
	dlsch_harq->mcs, //why MCS is inside the harq???
	dlsch_harq->round);

#if defined(MESSAGE_CHART_GENERATOR_PHY)
  MSC_LOG_TX_MESSAGE(
		     MSC_PHY_ENB,MSC_PHY_UE,
		     NULL,0,
		     "%05u:%02u PDSCH/DLSCH input size = %"PRIu16", G %d, nb_rb %"PRIu16", mcs %"PRIu8", pmi_alloc %"PRIx16", rv %"PRIu8" (round %"PRIu8")",
		     frame, subframe,
		     input_buffer_length,
		     get_G(fp,
			   dlsch_harq->nb_rb,
			   dlsch_harq->rb_alloc,
			   get_Qm(dlsch_harq->mcs),
			   dlsch_harq->Nl,
			   num_pdcch_symbols,
			   frame,
			   subframe,
			   dlsch_harq->mimo_mode==TM7?7:0),
		     dlsch_harq->nb_rb,
		     dlsch_harq->mcs,
		     pmi2hex_2Ar1(dlsch_harq->pmi_alloc),
		     dlsch_harq->rvidx,
		     dlsch_harq->round);
#endif

  if (ue_stats) ue_stats->dlsch_sliding_cnt++;

  if (dlsch_harq->round == 0) {

    if (ue_stats)
      ue_stats->dlsch_trials[harq_pid][0]++;

    if (eNB->mac_enabled==1) { // set in lte-softmodem - main line 1646
      if (ra_flag == 0)  {
    	  DLSCH_pdu =segment_data;

      }
    else { // XXX decide what should be done for NB-IoT

  	  /*
  	   * In FAPI style we don-t need to process the RAR because we have all the parameters for getting the MSG3 given by the
  	   * UL_CONFIG.request
  	   * 1) this data are given at the same time with the DLSCH PDU containing the RAR???
  	   * 2) wee need to do a mapping of this parameters OAI->FAPI
  	   */

    	  int16_t crnti = mac_xface->fill_rar(eNB->Mod_id,
					    eNB->CC_id,
					    frame,
					    DLSCH_pdu_rar,
					    fp->N_RB_UL,
					    input_buffer_length);
    	  DLSCH_pdu = DLSCH_pdu_rar;

    	  int UE_id;

    	  if (crnti!=0)
    		  UE_id = add_ue(crnti,eNB);
    	  else
	 	UE_id = -1;

    	  if (UE_id==-1) {
    		  LOG_W(PHY,"[eNB] Max user count reached.\n");
    		  mac_xface->cancel_ra_proc(eNB->Mod_id,
    				  	  	  	  	  eNB->CC_id,
									  frame,
									  crnti);
    	  } else {
    		  eNB->UE_stats[(uint32_t)UE_id].mode = RA_RESPONSE;
    		  // Initialize indicator for first SR (to be cleared after ConnectionSetup is acknowledged)
    		  eNB->first_sr[(uint32_t)UE_id] = 1;





    		  generate_eNB_ulsch_params_from_rar(DLSCH_pdu,
					     	 	 	 	 	 	 frame,
												 subframe,
												 eNB->ulsch[(uint32_t)UE_id],
												 fp);

    		  LOG_D(PHY,"[eNB][RAPROC] Frame %d subframe %d, Activated Msg3 demodulation for UE %"PRId8" in frame %"PRIu32", subframe %"PRIu8"\n",
    				  frame,
					  subframe,
					  UE_id,
					  eNB->ulsch[(uint32_t)UE_id]->Msg3_frame,
					  eNB->ulsch[(uint32_t)UE_id]->Msg3_subframe);

    		  /* TODO: get rid of this hack. The problem is that the eNodeB may
    		   * sometimes wrongly generate PHICH because somewhere 'phich_active' was
    		   * not reset to 0, due to an unidentified reason. When adding this
    		   * resetting here the problem seems to disappear completely.
    		   */
    		  LOG_D(PHY, "hack: set phich_active to 0 for UE %d fsf %d %d all HARQs\n", UE_id, frame, subframe);
    		  for (i = 0; i < 8; i++)
    			  eNB->ulsch[(uint32_t)UE_id]->harq_processes[i]->phich_active = 0;

    		  mac_xface->set_msg3_subframe(eNB->Mod_id, eNB->CC_id, frame, subframe, (uint16_t)crnti,
                                       eNB->ulsch[UE_id]->Msg3_frame, eNB->ulsch[UE_id]->Msg3_subframe);

    		  T(T_ENB_PHY_MSG3_ALLOCATION, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe),
    				  T_INT(UE_id), T_INT((uint16_t)crnti), T_INT(1 /* 1 is for initial transmission*/),
					  T_INT(eNB->ulsch[UE_id]->Msg3_frame), T_INT(eNB->ulsch[UE_id]->Msg3_subframe));
    	  }
    	  if (ue_stats) ue_stats->total_TBS_MAC += dlsch_harq->TBS;

      }// ra_flag = 1

    } //mac_eabled = 1
    else {  //XXX we should change taus function???
      DLSCH_pdu = DLSCH_pdu_tmp;

      for (i=0; i<input_buffer_length; i++)
	DLSCH_pdu[i] = (unsigned char)(taus()&0xff);
    }

#if defined(SMBV)

    // Configures the data source of allocation (allocation is configured by DCI)
    if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4)) {
      LOG_D(PHY,"[SMBV] Frame %3d, Configuring PDSCH payload in SF %d alloc %"PRIu8"\n",frame,(smbv_frame_cnt*10) + (subframe),smbv_alloc_cnt);
      //          smbv_configure_datalist_for_user(smbv_fname, find_ue(dlsch->rnti,eNB)+1, DLSCH_pdu, input_buffer_length);
    }

#endif



#ifdef DEBUG_PHY_PROC
#ifdef DEBUG_DLSCH
    LOG_T(PHY,"eNB DLSCH SDU: \n");

    //eNB->dlsch[(uint8_t)UE_id][0]->nCCE[subframe] = DCI_pdu->dci_alloc[i].firstCCE;

    LOG_D(PHY,"[eNB %"PRIu8"] Frame %d subframe %d : CCE resource for ue DCI (PDSCH %"PRIx16")  => %"PRIu8"/%u\n",eNB->Mod_id,eNB->proc[sched_subframe].frame_tx,subframe,
	  DCI_pdu->dci_alloc[i].rnti,eNB->dlsch[(uint8_t)UE_id][0]->nCCE[subframe],DCI_pdu->dci_alloc[i].firstCCE);


    for (i=0; i<dlsch_harq->TBS>>3; i++)
      LOG_T(PHY,"%"PRIx8".",DLSCH_pdu[i]);

    LOG_T(PHY,"\n");
#endif
#endif
  } //harq round == 0
  else {
	  //We are doing a retransmission

    ue_stats->dlsch_trials[harq_pid][dlsch_harq->round]++;

#ifdef DEBUG_PHY_PROC
#ifdef DEBUG_DLSCH
    LOG_D(PHY,"[eNB] This DLSCH is a retransmission\n");
#endif
#endif
  }

  if (eNB->abstraction_flag==0) { // used for simulation of the PHY??

    LOG_D(PHY,"Generating NDLSCH/NPDSCH %d\n",ra_flag);


    // 36-212
    //encoding---------------------------
    start_meas(&eNB->dlsch_encoding_stats);

    LOG_I(PHY, "NB-IoT Encoding step\n");

    eNB->te(eNB,
	    DLSCH_pdu,
	    num_pdcch_symbols,
	    dlsch,
	    frame,subframe,
	    &eNB->dlsch_rate_matching_stats,
	    &eNB->dlsch_turbo_encoding_stats,
	    &eNB->dlsch_interleaving_stats);

    stop_meas(&eNB->dlsch_encoding_stats);
    //scrambling-------------------------------------------
    // 36-211
    start_meas(&eNB->dlsch_scrambling_stats);
    LOG_I(PHY, "NB-IoT Scrambling step\n");

    dlsch_scrambling(fp,
		     0,
		     dlsch,
		     get_G(fp,
			   dlsch_harq->nb_rb,
			   dlsch_harq->rb_alloc,
			   get_Qm(dlsch_harq->mcs),
			   dlsch_harq->Nl,
			   num_pdcch_symbols,
			   frame,subframe,
			   0),
		     0,
		     subframe<<1);

    stop_meas(&eNB->dlsch_scrambling_stats);


    //modulation-------------------------------------------
    start_meas(&eNB->dlsch_modulation_stats);
    LOG_I(PHY, "NB-IoT Modulation step\n");

    dlsch_modulation(eNB,
		     eNB->common_vars.txdataF[0],
		     AMP,
		     subframe,
		     num_pdcch_symbols,
		     dlsch,
		     dlsch1);

    stop_meas(&eNB->dlsch_modulation_stats);
  }


#ifdef PHY_ABSTRACTION
  else {
    start_meas(&eNB->dlsch_encoding_stats);
    dlsch_encoding_emul(eNB,
			DLSCH_pdu,
			dlsch);
    stop_meas(&eNB->dlsch_encoding_stats);
  }

#endif
  dlsch->active = 0;
}



extern int oai_exit;

/*
r_type, rn is only used in PMCH procedure so I remove it.
*/
void NB_phy_procedures_eNB_TX(PHY_VARS_eNB *eNB,
         eNB_rxtx_proc_NB_t *proc,
         int do_meas)
{
  int frame = proc->frame_tx;
  int subframe = proc->subframe_tx;
  uint32_t i,aa;
  uint8_t harq_pid;
  //DCI_PDU_NB *DCI_pdu;
  //DCI_PDU_NB DCI_pdu_tmp;
  LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;
  // DCI_ALLOC_t *dci_alloc = (DCI_ALLOC_t *)NULL;
  int8_t UE_id = 0;
  uint8_t ul_subframe;
  uint32_t ul_frame;

  int **txdataF = eNB->common_vars.txdataF[0];

  //uint8_t num_npdcch_symbols = 0;

  //for NB-IoT

  Sched_Rsp_t *Sched_Rsp;

  if(do_meas == 1)
    start_meas(&eNB->phy_proc_tx);

  for(i = 0;i<NUMBER_OF_UE_MAX;i++)
    {
      if((frame==0)&&(subframe==0))
        {
          if(eNB->UE_stats[i].crnti > 0)
              LOG_I(PHY,"UE%d : rnti %x\n",i,eNB->UE_stats[i].crnti);
        }
    }

  // Original scheduler 

  // clear the transmit data array for the current subframe

  for (aa=0; aa<fp->nb_antenna_ports_eNB; aa++) 
    {      
      memset(&eNB->common_vars.txdataF[0][aa][subframe*fp->ofdm_symbol_size*(fp->symbols_per_tti)],
                  0,fp->ofdm_symbol_size*(fp->symbols_per_tti)*sizeof(int32_t));
    } 


  while(!oai_exit)
    {
	  //ignore the PMCH part only do the generate PSS/SSS, note: Seperate MIB from here
	  NB_common_signal_procedures(eNB,proc);

        //Not test yet , mutex_l2, cond_l2, instance_cnt_l2
        //cond_l2 should be given by sched_rsp after the scheduling
        if(wait_on_condition(&proc->mutex_l2,&proc->cond_l2,&proc->instance_cnt_l2,"eNB_L2_thread") < 0) 
        break;

      /*Take the structures from the shared structures*/
      //Sched_Rsp = ;

      /*
      broadcast channel for n-FAPI style
      pdu length - 14 (bytes)
      pdu index - 1 
      num segments -1
      segment length 5 bytes
      segment data  34 bits (5 bytes)
      */

      if((subframe==0) && (Sched_Rsp->NB_DL.NB_BCH.MIB_pdu.segments[0].segment_data)!=NULL)
        {
          generate_npbch(&eNB->npbch,
                         txdataF,
                         AMP,
                         fp,
                         &Sched_Rsp->NB_DL.NB_BCH.MIB_pdu.segments[0].segment_data,
                         frame%64==0?0:1,
                         fp->NB_IoT_RB_ID // iD of the resource block may be passed by the config request (phy config structure)
                         );
        }

      /*clear the existing ulsch dci allocations before applying info from MAC*/
      ul_subframe = (subframe+4)%10;
      ul_frame = frame+(ul_subframe >= 6 ? 1 :0);
      harq_pid = ((ul_frame<<1)+ul_subframe)&7;


      // check for BCCH
      //rnti_type = 0 BCCH information
      //rnti_type = 1 Other
      if(Sched_Rsp->NB_DL.NB_DLSCH.ndlsch.rnti_type == 0)
        {
            /*TODO: NPDSCH procedures for BCCH for NB-IoT*/
            //npdsch_procedures();
        }

      /*clear the DCI allocation maps for new subframe*/
      for(i=0;i<NUMBER_OF_UE_MAX;i++)
        {
          if(eNB->ulsch[i])
            {
              eNB->ulsch[i]->harq_processes[harq_pid]->dci_alloc = 0;
              eNB->ulsch[i]->harq_processes[harq_pid]->rar_alloc = 0;
            }
        }

      /*clear previous allocation information for all UEs*/
      for(i=0;i<NUMBER_OF_UE_MAX;i++)
        {
          if(eNB->dlsch[i][0])
            eNB->dlsch[i][0]->subframe_tx[subframe]=0;
        }

   if(Sched_Rsp->NB_DL.NB_DCI != NULL)
    {

      /*Loop over all the dci to generate DLSCH allocation, there is only 1 or 2 DCIs for NB-IoT in the same time*/
      // Add dci fapi structure for contain two dcis
      /*Also Packed the DCI here*/
      for(int i= 0; i< Sched_Rsp->NB_DL.NB_DCI.DL_DCI.number_dci; i++)
      {
      if (Sched_Rsp->NB_DL.NB_DCI.DL_DCI.dl_config_pdu_list->npdcch_pdu.npdcch_pdu_rel13.rnti<= P_RNTI)
        {
    	  //is not system iformation but cound be paging
    	  //in any case we generate dlsch for not system information
          UE_id = find_ue((int16_t)Sched_Rsp->NB_DL.NB_DCI.DL_DCI.npdcch_pdu_rel13.rnti,eNB);
        }
      else 
        UE_id=0;
    
      //inside we have nFAPI to OAI parameters
      NB_generate_eNB_dlsch_params(eNB,proc,Sched_Rsp,UE_id);
      
      }

      /* Apply physicalConfigDedicated if needed, don't know if needed in NB-IoT or not
       This is for UEs that have received this IE, which changes these DL and UL configuration, we apply after a delay for the eNodeB UL parameters
      phy_config_dedicated_eNB_step2(eNB);*/

      for (int i = 0; Sched_Rsp->NB_DL.NB_DCI.UL_DCI.number_of_dci; i ++)
      {

      if (Sched_Rsp->NB_DL.NB_DCI.DCI_Format == DCIFormatN0) // this is a ULSCH allocation
        {  
          UE_id = find_ue((int16_t)Sched_Rsp->NB_DL.NB_DCI.UL_DCI.npdcch_dci_pdu_rel13.rnti,eNB);
          NB_generate_eNB_ulsch_params(eNB,proc,Sched_Rsp,UE_id);
        }

      }

      /*If we have DCI to generate do it now TODO : have a generate dci top for NB_IoT */
      //to be modified but inside we have the nuew function for dci transmission
      generate_dci_top();

    }

      //now we should check if Sched_Rsp contains data
      //rnti_type = 0 BCCH information
      //rnti_type = 1 Other
      if(Sched_Rsp->NB_DL.NB_DLSCH.ndlsch.rnti_type != 0)
      {

    	  //we not need between RAR PDUS
              /*TODO: NPDSCH procedures for BCCH for NB-IoT*/
              //npdsch_procedures();
      }





    }
}