/*
 * 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_procedures_lte_ue.c
 * \brief Implementation of UE procedures from 36.213 LTE specifications
 * \author R. Knopp, F. Kaltenberger, N. Nikaein
 * \date 2011
 * \version 0.1
 * \company Eurecom
 * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr, navid.nikaein@eurecom.fr
 * \note
 * \warning
 */

#define _GNU_SOURCE

#include "assertions.h"
#include "PHY/defs_UE.h"
#include "PHY/phy_extern_ue.h"
#include <sched.h>
#include "targets/RT/USER/lte-softmodem.h"

#include "PHY/LTE_UE_TRANSPORT/transport_proto_ue.h"
#include "SCHED_UE/sched_UE.h"
#include "PHY/MODULATION/modulation_UE.h"
#include "PHY/LTE_ESTIMATION/lte_estimation.h"


#ifndef PUCCH
#define PUCCH
#endif

#include "LAYER2/MAC/mac.h"
#include "common/utils/LOG/log.h"

#include "common/utils/LOG/vcd_signal_dumper.h"
#include "UTIL/OPT/opt.h"

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

#include "PHY/defs_UE.h"

#include "PHY/CODING/coding_extern.h"

#include "T.h"

#include "PHY/TOOLS/tools_defs.h"

#define DLSCH_RB_ALLOC 0x1fbf  // skip DC RB (total 23/25 RBs)
#define DLSCH_RB_ALLOC_12 0x0aaa  // skip DC RB (total 23/25 RBs)

#define NS_PER_SLOT 500000

extern double cpuf;

void Msg1_transmitted(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id);
void Msg3_transmitted(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id);

#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
extern uint32_t downlink_frequency[MAX_NUM_CCs][4];
#endif

void get_dumpparam(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id, uint8_t nb_rb,
                   uint32_t *alloc_even, uint8_t subframe,uint32_t Qm, uint32_t Nl, uint32_t tm,
                   uint8_t *nsymb, uint32_t *coded_bits_per_codeword) {

  *nsymb = (ue->frame_parms.Ncp == 0) ? 14 : 12;

  *coded_bits_per_codeword = get_G(&ue->frame_parms,
                                  nb_rb,
                                  alloc_even,
                                  Qm,
                                  Nl,
                                  ue->pdcch_vars[0%RX_NB_TH][eNB_id]->num_pdcch_symbols,
                                  proc->frame_rx,
                                  subframe,
                                  tm);
}

void dump_dlsch(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t subframe,uint8_t harq_pid)
{
LOG_M_BEGIN(DEBUG_UE_PHYPROC)
  unsigned int coded_bits_per_codeword;
  uint8_t nsymb ;

  get_dumpparam(ue, proc, eNB_id, 
                ue->dlsch[ue->current_thread_id[subframe]][eNB_id][0]->harq_processes[harq_pid]->nb_rb ,
                ue->dlsch[ue->current_thread_id[subframe]][eNB_id][0]->harq_processes[harq_pid]->rb_alloc_even,
                subframe,
                ue->dlsch[ue->current_thread_id[subframe]][eNB_id][0]->harq_processes[harq_pid]->Qm,
                ue->dlsch[ue->current_thread_id[subframe]][eNB_id][0]->harq_processes[harq_pid]->Nl,                
                ue->transmission_mode[eNB_id]<7?0:ue->transmission_mode[eNB_id],
                &nsymb, &coded_bits_per_codeword);

  LOG_M("rxsigF0.m","rxsF0", ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].rxdataF[0],2*nsymb*ue->frame_parms.ofdm_symbol_size,2,1);
  LOG_M("rxsigF0_ext.m","rxsF0_ext", ue->pdsch_vars[ue->current_thread_id[subframe]][0]->rxdataF_ext[0],2*nsymb*ue->frame_parms.ofdm_symbol_size,1,1);
  LOG_M("dlsch00_ch0_ext.m","dl00_ch0_ext", ue->pdsch_vars[ue->current_thread_id[subframe]][0]->dl_ch_estimates_ext[0],300*nsymb,1,1);
  /*
    LOG_M("dlsch01_ch0_ext.m","dl01_ch0_ext",pdsch_vars[0]->dl_ch_estimates_ext[1],300*12,1,1);
    LOG_M("dlsch10_ch0_ext.m","dl10_ch0_ext",pdsch_vars[0]->dl_ch_estimates_ext[2],300*12,1,1);
    LOG_M("dlsch11_ch0_ext.m","dl11_ch0_ext",pdsch_vars[0]->dl_ch_estimates_ext[3],300*12,1,1);
    LOG_M("dlsch_rho.m","dl_rho",pdsch_vars[0]->rho[0],300*12,1,1);
  */
  LOG_M("dlsch_rxF_comp0.m","dlsch0_rxF_comp0", ue->pdsch_vars[ue->current_thread_id[subframe]][0]->rxdataF_comp0[0],300*12,1,1);
  LOG_M("dlsch_rxF_llr.m","dlsch_llr", ue->pdsch_vars[ue->current_thread_id[subframe]][0]->llr[0],coded_bits_per_codeword,1,0);

  LOG_M("dlsch_mag1.m","dlschmag1",ue->pdsch_vars[ue->current_thread_id[subframe]][0]->dl_ch_mag0,300*12,1,1);
  LOG_M("dlsch_mag2.m","dlschmag2",ue->pdsch_vars[ue->current_thread_id[subframe]][0]->dl_ch_magb0,300*12,1,1);
LOG_M_END
}

void dump_dlsch_SI(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t subframe)
{
LOG_M_BEGIN(DEBUG_UE_PHYPROC)
  unsigned int coded_bits_per_codeword;
  uint8_t nsymb;

  get_dumpparam(ue, proc, eNB_id,
                ue->dlsch_SI[eNB_id]->harq_processes[0]->nb_rb,
                ue->dlsch_SI[eNB_id]->harq_processes[0]->rb_alloc_even,
                subframe,2,1,0,
                &nsymb, &coded_bits_per_codeword);

  LOG_D(PHY,"[UE %d] Dumping dlsch_SI : ofdm_symbol_size %d, nsymb %d, nb_rb %d, mcs %d, nb_rb %d, num_pdcch_symbols %d,G %d\n",
        ue->Mod_id,
        ue->frame_parms.ofdm_symbol_size,
        nsymb,
        ue->dlsch_SI[eNB_id]->harq_processes[0]->nb_rb,
        ue->dlsch_SI[eNB_id]->harq_processes[0]->mcs,
        ue->dlsch_SI[eNB_id]->harq_processes[0]->nb_rb,
        ue->pdcch_vars[0%RX_NB_TH][eNB_id]->num_pdcch_symbols,
        coded_bits_per_codeword);

  LOG_M("rxsig0.m","rxs0", &ue->common_vars.rxdata[0][subframe*ue->frame_parms.samples_per_tti],ue->frame_parms.samples_per_tti,1,1);

  LOG_M("rxsigF0.m","rxsF0", ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].rxdataF[0],nsymb*ue->frame_parms.ofdm_symbol_size,1,1);
  LOG_M("rxsigF0_ext.m","rxsF0_ext", ue->pdsch_vars_SI[0]->rxdataF_ext[0],2*nsymb*ue->frame_parms.ofdm_symbol_size,1,1);
  LOG_M("dlsch00_ch0_ext.m","dl00_ch0_ext", ue->pdsch_vars_SI[0]->dl_ch_estimates_ext[0],ue->frame_parms.N_RB_DL*12*nsymb,1,1);
  /*
    LOG_M("dlsch01_ch0_ext.m","dl01_ch0_ext",pdsch_vars[0]->dl_ch_estimates_ext[1],300*12,1,1);
    LOG_M("dlsch10_ch0_ext.m","dl10_ch0_ext",pdsch_vars[0]->dl_ch_estimates_ext[2],300*12,1,1);
    LOG_M("dlsch11_ch0_ext.m","dl11_ch0_ext",pdsch_vars[0]->dl_ch_estimates_ext[3],300*12,1,1);
    LOG_M("dlsch_rho.m","dl_rho",pdsch_vars[0]->rho[0],300*12,1,1);
  */
  LOG_M("dlsch_rxF_comp0.m","dlsch0_rxF_comp0", ue->pdsch_vars_SI[0]->rxdataF_comp0[0],ue->frame_parms.N_RB_DL*12*nsymb,1,1);
  LOG_M("dlsch_rxF_llr.m","dlsch_llr", ue->pdsch_vars_SI[0]->llr[0],coded_bits_per_codeword,1,0);

  LOG_M("dlsch_mag1.m","dlschmag1",ue->pdsch_vars_SI[0]->dl_ch_mag0,300*nsymb,1,1);
  LOG_M("dlsch_mag2.m","dlschmag2",ue->pdsch_vars_SI[0]->dl_ch_magb0,300*nsymb,1,1);
  sleep(1);
  exit(-1);
LOG_M_END
}

#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
//unsigned int gain_table[31] = {100,112,126,141,158,178,200,224,251,282,316,359,398,447,501,562,631,708,794,891,1000,1122,1258,1412,1585,1778,1995,2239,2512,2818,3162};
/*
  unsigned int get_tx_amp_prach(int power_dBm, int power_max_dBm, int N_RB_UL)
  {

  int gain_dB = power_dBm - power_max_dBm;
  int amp_x_100;

  switch (N_RB_UL) {
  case 6:
  amp_x_100 = AMP;      // PRACH is 6 PRBS so no scale
  break;
  case 15:
  amp_x_100 = 158*AMP;  // 158 = 100*sqrt(15/6)
  break;
  case 25:
  amp_x_100 = 204*AMP;  // 204 = 100*sqrt(25/6)
  break;
  case 50:
  amp_x_100 = 286*AMP;  // 286 = 100*sqrt(50/6)
  break;
  case 75:
  amp_x_100 = 354*AMP;  // 354 = 100*sqrt(75/6)
  break;
  case 100:
  amp_x_100 = 408*AMP;  // 408 = 100*sqrt(100/6)
  break;
  default:
  LOG_E(PHY,"Unknown PRB size %d\n",N_RB_UL);
  mac_xface->macphy_exit("");
  break;
  }
  if (gain_dB < -30) {
  return(amp_x_100/3162);
  } else if (gain_dB>0)
  return(amp_x_100);
  else
  return(amp_x_100/gain_table[-gain_dB]);  // 245 corresponds to the factor sqrt(25/6)
  }
*/

unsigned int get_tx_amp(int power_dBm, int power_max_dBm, int N_RB_UL, int nb_rb)
{

  int gain_dB;
  double gain_lin;

  if (power_dBm<=power_max_dBm)
    gain_dB = power_dBm - power_max_dBm;
  else
    gain_dB = 0;

  gain_lin = pow(10,.1*gain_dB);
  AssertFatal((nb_rb >0) && (nb_rb <= N_RB_UL),"Illegal nb_rb/N_RB_UL combination (%d/%d)\n",nb_rb,N_RB_UL);
  return((int)(AMP*sqrt(gain_lin*N_RB_UL/(double)nb_rb)));
}

#endif

void dump_dlsch_ra(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t subframe)
{
LOG_M_BEGIN(DEBUG_UE_PHYPROC)
  unsigned int coded_bits_per_codeword;
  uint8_t nsymb ;


  get_dumpparam(ue, proc, eNB_id,
                ue->dlsch_SI[eNB_id]->harq_processes[0]->nb_rb,
                ue->dlsch_SI[eNB_id]->harq_processes[0]->rb_alloc_even, 
                subframe,2,1,0,
                &nsymb, &coded_bits_per_codeword);

  LOG_D(PHY,"[UE %d] Dumping dlsch_ra : nb_rb %d, mcs %d, nb_rb %d, num_pdcch_symbols %d,G %d\n",
        ue->Mod_id,
        ue->dlsch_ra[eNB_id]->harq_processes[0]->nb_rb,
        ue->dlsch_ra[eNB_id]->harq_processes[0]->mcs,
        ue->dlsch_ra[eNB_id]->harq_processes[0]->nb_rb,
        ue->pdcch_vars[0%RX_NB_TH][eNB_id]->num_pdcch_symbols,
        coded_bits_per_codeword);

  LOG_M("rxsigF0.m","rxsF0", ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].rxdataF[0],2*12*ue->frame_parms.ofdm_symbol_size,2,1);
  LOG_M("rxsigF0_ext.m","rxsF0_ext", ue->pdsch_vars_ra[0]->rxdataF_ext[0],2*12*ue->frame_parms.ofdm_symbol_size,1,1);
  LOG_M("dlsch00_ch0_ext.m","dl00_ch0_ext", ue->pdsch_vars_ra[0]->dl_ch_estimates_ext[0],300*nsymb,1,1);
  /*
    LOG_M("dlsch01_ch0_ext.m","dl01_ch0_ext",pdsch_vars[0]->dl_ch_estimates_ext[1],300*12,1,1);
    LOG_M("dlsch10_ch0_ext.m","dl10_ch0_ext",pdsch_vars[0]->dl_ch_estimates_ext[2],300*12,1,1);
    LOG_M("dlsch11_ch0_ext.m","dl11_ch0_ext",pdsch_vars[0]->dl_ch_estimates_ext[3],300*12,1,1);
    LOG_M("dlsch_rho.m","dl_rho",pdsch_vars[0]->rho[0],300*12,1,1);
  */
  LOG_M("dlsch_rxF_comp0.m","dlsch0_rxF_comp0", ue->pdsch_vars_ra[0]->rxdataF_comp0[0],300*nsymb,1,1);
  LOG_M("dlsch_rxF_llr.m","dlsch_llr", ue->pdsch_vars_ra[0]->llr[0],coded_bits_per_codeword,1,0);

  LOG_M("dlsch_mag1.m","dlschmag1",ue->pdsch_vars_ra[0]->dl_ch_mag0,300*nsymb,1,1);
  LOG_M("dlsch_mag2.m","dlschmag2",ue->pdsch_vars_ra[0]->dl_ch_magb0,300*nsymb,1,1);
LOG_M_END
}

void phy_reset_ue(module_id_t Mod_id,uint8_t CC_id,uint8_t eNB_index)
{

  // This flushes ALL DLSCH and ULSCH harq buffers of ALL connected eNBs...add the eNB_index later
  // for more flexibility

  uint8_t i,j,k,s;
  PHY_VARS_UE *ue = PHY_vars_UE_g[Mod_id][CC_id];

  //[NUMBER_OF_RX_THREAD=2][NUMBER_OF_CONNECTED_eNB_MAX][2];
  for(int l=0; l<RX_NB_TH; l++) {
      for(i=0; i<NUMBER_OF_CONNECTED_eNB_MAX; i++) {
          for(j=0; j<2; j++) {
              //DL HARQ
              if(ue->dlsch[l][i][j]) {
                  for(k=0; k<NUMBER_OF_HARQ_PID_MAX && ue->dlsch[l][i][j]->harq_processes[k]; k++) {
                      ue->dlsch[l][i][j]->harq_processes[k]->status = SCH_IDLE;
                      for (s=0; s<10; s++) {
                          // reset ACK/NACK bit to DTX for all subframes s = 0..9
                          ue->dlsch[l][i][j]->harq_ack[s].ack = 2;
                          ue->dlsch[l][i][j]->harq_ack[s].send_harq_status = 0;
                          ue->dlsch[l][i][j]->harq_ack[s].vDAI_UL = 0xff;
                          ue->dlsch[l][i][j]->harq_ack[s].vDAI_DL = 0xff;
                      }
                  }
              }
          }

          //UL HARQ
          if(ue->ulsch[i]) {
              for(k=0; k<NUMBER_OF_HARQ_PID_MAX && ue->ulsch[i]->harq_processes[k]; k++) {
                  ue->ulsch[i]->harq_processes[k]->status = SCH_IDLE;
                  //Set NDIs for all UL HARQs to 0
                  //  ue->ulsch[i]->harq_processes[k]->Ndi = 0;

              }
          }

          // flush Msg3 buffer
          ue->ulsch_Msg3_active[i] = 0;

      }
  }
}

void ra_failed(uint8_t Mod_id,uint8_t CC_id,uint8_t eNB_index)
{

  // if contention resolution fails, go back to PRACH
  PHY_vars_UE_g[Mod_id][CC_id]->UE_mode[eNB_index] = PRACH;
  PHY_vars_UE_g[Mod_id][CC_id]->pdcch_vars[0][eNB_index]->crnti_is_temporary = 0;
  PHY_vars_UE_g[Mod_id][CC_id]->pdcch_vars[0][eNB_index]->crnti = 0;
  PHY_vars_UE_g[Mod_id][CC_id]->pdcch_vars[1][eNB_index]->crnti_is_temporary = 0;
  PHY_vars_UE_g[Mod_id][CC_id]->pdcch_vars[1][eNB_index]->crnti = 0;
  LOG_E(PHY,"[UE %d] Random-access procedure fails, going back to PRACH, setting SIStatus = 0, discard temporary C-RNTI and State RRC_IDLE\n",Mod_id);
}

void ra_succeeded(uint8_t Mod_id,uint8_t CC_id,uint8_t eNB_index)
{

  int i;

  LOG_I(PHY,"[UE %d][RAPROC] Random-access procedure succeeded. Set C-RNTI = Temporary C-RNTI\n",Mod_id);

  PHY_vars_UE_g[Mod_id][CC_id]->pdcch_vars[0][eNB_index]->crnti_is_temporary = 0;
  PHY_vars_UE_g[Mod_id][CC_id]->pdcch_vars[1][eNB_index]->crnti_is_temporary = 0;
  PHY_vars_UE_g[Mod_id][CC_id]->ulsch_Msg3_active[eNB_index] = 0;
  PHY_vars_UE_g[Mod_id][CC_id]->UE_mode[eNB_index] = PUSCH;

  for (i=0; i<8; i++) {
    if (PHY_vars_UE_g[Mod_id][CC_id]->ulsch[eNB_index]->harq_processes[i]) {
      PHY_vars_UE_g[Mod_id][CC_id]->ulsch[eNB_index]->harq_processes[i]->status=SCH_IDLE;
      PHY_vars_UE_g[Mod_id][CC_id]->dlsch[0][eNB_index][0]->harq_processes[i]->round=0;
      PHY_vars_UE_g[Mod_id][CC_id]->dlsch[1][eNB_index][0]->harq_processes[i]->round=0;
      PHY_vars_UE_g[Mod_id][CC_id]->ulsch[eNB_index]->harq_processes[i]->subframe_scheduling_flag=0;
    }
  }


}

UE_MODE_t get_ue_mode(uint8_t Mod_id,uint8_t CC_id,uint8_t eNB_index)
{

  return(PHY_vars_UE_g[Mod_id][CC_id]->UE_mode[eNB_index]);

}
void process_timing_advance_rar(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint16_t timing_advance) {

  ue->timing_advance = timing_advance*4;


LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
  /* TODO: fix this log, what is 'HW timing advance'? */
  /*LOG_I(PHY,"[UE %d] AbsoluteSubFrame %d.%d, received (rar) timing_advance %d, HW timing advance %d\n",ue->Mod_id,proc->frame_rx, proc->subframe_rx, ue->timing_advance);*/
  LOG_I(PHY,"[UE %d] AbsoluteSubFrame %d.%d, received (rar) timing_advance %d\n",ue->Mod_id,proc->frame_rx, proc->subframe_rx, ue->timing_advance);
LOG_DEBUG_END

}

void process_timing_advance(module_id_t Mod_id,uint8_t CC_id,int16_t timing_advance)
{

  //  uint32_t frame = PHY_vars_UE_g[Mod_id]->frame;

  // timing advance has Q1.5 format
  timing_advance = timing_advance - 31;

  PHY_vars_UE_g[Mod_id][CC_id]->timing_advance = PHY_vars_UE_g[Mod_id][CC_id]->timing_advance+timing_advance*4; //this is for 25RB only!!!


  LOG_D(PHY,"[UE %d] Got timing advance %d from MAC, new value %d\n",Mod_id, timing_advance, PHY_vars_UE_g[Mod_id][CC_id]->timing_advance);


}

uint8_t is_SR_TXOp(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id)
{

  int subframe=proc->subframe_tx;

  LOG_D(PHY,"[UE %d][SR %x] Frame %d subframe %d Checking for SR TXOp (sr_ConfigIndex %d)\n",
        ue->Mod_id,ue->pdcch_vars[ue->current_thread_id[proc->subframe_rx]][eNB_id]->crnti,proc->frame_tx,subframe,
        ue->scheduling_request_config[eNB_id].sr_ConfigIndex);

  if (ue->scheduling_request_config[eNB_id].sr_ConfigIndex <= 4) {        // 5 ms SR period
    if ((subframe%5) == ue->scheduling_request_config[eNB_id].sr_ConfigIndex)
      return(1);
  } else if (ue->scheduling_request_config[eNB_id].sr_ConfigIndex <= 14) { // 10 ms SR period
    if (subframe==(ue->scheduling_request_config[eNB_id].sr_ConfigIndex-5))
      return(1);
  } else if (ue->scheduling_request_config[eNB_id].sr_ConfigIndex <= 34) { // 20 ms SR period
    if ((10*(proc->frame_tx&1)+subframe) == (ue->scheduling_request_config[eNB_id].sr_ConfigIndex-15))
      return(1);
  } else if (ue->scheduling_request_config[eNB_id].sr_ConfigIndex <= 74) { // 40 ms SR period
    if ((10*(proc->frame_tx&3)+subframe) == (ue->scheduling_request_config[eNB_id].sr_ConfigIndex-35))
      return(1);
  } else if (ue->scheduling_request_config[eNB_id].sr_ConfigIndex <= 154) { // 80 ms SR period
    if ((10*(proc->frame_tx&7)+subframe) == (ue->scheduling_request_config[eNB_id].sr_ConfigIndex-75))
      return(1);
  }

  return(0);
}

uint8_t is_cqi_TXOp(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id)
{
  int subframe = proc->subframe_tx;
  int frame    = proc->frame_tx;
  CQI_REPORTPERIODIC *cqirep = &ue->cqi_report_config[eNB_id].CQI_ReportPeriodic;

  //LOG_I(PHY,"[UE %d][CRNTI %x] AbsSubFrame %d.%d Checking for CQI TXOp (cqi_ConfigIndex %d) isCQIOp %d\n",
  //      ue->Mod_id,ue->pdcch_vars[eNB_id]->crnti,frame,subframe,
  //      cqirep->cqi_PMI_ConfigIndex,
  //      (((10*frame + subframe) % cqirep->Npd) == cqirep->N_OFFSET_CQI));

  if (cqirep->cqi_PMI_ConfigIndex==-1)
    return(0);
  else if (((10*frame + subframe) % cqirep->Npd) == cqirep->N_OFFSET_CQI)
    return(1);
  else
    return(0);
}
uint8_t is_ri_TXOp(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id)
{


  int subframe = proc->subframe_tx;
  int frame    = proc->frame_tx;
  CQI_REPORTPERIODIC *cqirep = &ue->cqi_report_config[eNB_id].CQI_ReportPeriodic;
  int log2Mri = cqirep->ri_ConfigIndex/161;
  int N_OFFSET_RI = cqirep->ri_ConfigIndex % 161;

  //LOG_I(PHY,"[UE %d][CRNTI %x] AbsSubFrame %d.%d Checking for RI TXOp (ri_ConfigIndex %d) isRIOp %d\n",
  //      ue->Mod_id,ue->pdcch_vars[eNB_id]->crnti,frame,subframe,
  //      cqirep->ri_ConfigIndex,
  //      (((10*frame + subframe + cqirep->N_OFFSET_CQI - N_OFFSET_RI) % (cqirep->Npd<<log2Mri)) == 0));
  if (cqirep->ri_ConfigIndex==-1)
    return(0);
  else if (((10*frame + subframe + cqirep->N_OFFSET_CQI - N_OFFSET_RI) % (cqirep->Npd<<log2Mri)) == 0)
    return(1);
  else
    return(0);
}

void compute_cqi_ri_resources(PHY_VARS_UE *ue,
                              LTE_UE_ULSCH_t *ulsch,
                              uint8_t eNB_id,
                              uint16_t rnti,
                              uint16_t p_rnti,
                              uint16_t cba_rnti,
                              uint8_t cqi_status,
                              uint8_t ri_status)
{
    //PHY_MEASUREMENTS *meas = &ue->measurements;
    //uint8_t transmission_mode = ue->transmission_mode[eNB_id];


    //LOG_I(PHY,"compute_cqi_ri_resources O_RI %d O %d uci format %d \n",ulsch->O_RI,ulsch->O,ulsch->uci_format);
    if (cqi_status == 1 || ri_status == 1)
    {
        ulsch->O = 4;
    }
}

void ue_compute_srs_occasion(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t isSubframeSRS)
{

  LTE_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
  int frame_tx    = proc->frame_tx;
  int subframe_tx = proc->subframe_tx;
  SOUNDINGRS_UL_CONFIG_DEDICATED *pSoundingrs_ul_config_dedicated=&ue->soundingrs_ul_config_dedicated[eNB_id];
  uint16_t srsPeriodicity;
  uint16_t srsOffset;
  uint8_t is_pucch2_subframe = 0;
  uint8_t is_sr_an_subframe  = 0;

  // check for SRS opportunity
  pSoundingrs_ul_config_dedicated->srsUeSubframe   = 0;
  pSoundingrs_ul_config_dedicated->srsCellSubframe = isSubframeSRS;

  if (isSubframeSRS) {
    LOG_D(PHY," SrsDedicatedSetup: %d \n",pSoundingrs_ul_config_dedicated->srsConfigDedicatedSetup);
      if(pSoundingrs_ul_config_dedicated->srsConfigDedicatedSetup)
      {
          compute_srs_pos(frame_parms->frame_type, pSoundingrs_ul_config_dedicated->srs_ConfigIndex, &srsPeriodicity, &srsOffset);

          LOG_D(PHY," srsPeriodicity: %d srsOffset: %d isSubframeSRS %d \n",srsPeriodicity,srsOffset,isSubframeSRS);

          // transmit SRS if the four following constraints are respected:
          // - UE is configured to transmit SRS
          // - SRS are configured in current subframe
          // - UE is configured to send SRS in this subframe

          // 36.213 8.2
          // 1- A UE shall not transmit SRS whenever SRS and PUCCH format 2/2a/2b transmissions happen to coincide in the same subframe
          // 2- A UE shall not transmit SRS whenever SRS transmit
          //    on and PUCCH transmission carrying ACK/NACK and/or
          //    positive SR happen to coincide in the same subframe if the parameter
          //    Simultaneous-AN-and-SRS is FALSE

          // check PUCCH format 2/2a/2b transmissions
          is_pucch2_subframe = is_cqi_TXOp(ue,proc,eNB_id) && (ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.cqi_PMI_ConfigIndex>0);
          is_pucch2_subframe = (is_ri_TXOp(ue,proc,eNB_id) && (ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.ri_ConfigIndex>0)) || is_pucch2_subframe;

          // check ACK/SR transmission
          if(frame_parms->soundingrs_ul_config_common.ackNackSRS_SimultaneousTransmission == FALSE)
          {
              if(is_SR_TXOp(ue,proc,eNB_id))
              {
                  uint32_t SR_payload = 0;
                  if (ue->mac_enabled==1)
                  {
                      int Mod_id = ue->Mod_id;
                      int CC_id = ue->CC_id;
                      SR_payload = ue_get_SR(Mod_id,
					     CC_id,
					     frame_tx,
					     eNB_id,
					     ue->pdcch_vars[ue->current_thread_id[proc->subframe_rx]][eNB_id]->crnti,
					     subframe_tx); // subframe used for meas gap

                      if (SR_payload > 0)
                          is_sr_an_subframe = 1;
                  }
              }

              uint8_t pucch_ack_payload[2];
              if (get_ack(&ue->frame_parms,
                      ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack,
                      subframe_tx,proc->subframe_rx,pucch_ack_payload,0) > 0)
              {
                  is_sr_an_subframe = 1;
              }
          }

          // check SRS UE opportunity
          if( isSubframeSRS  &&
                  (((10*frame_tx+subframe_tx) % srsPeriodicity) == srsOffset)
          )
          {
              if ((is_pucch2_subframe == 0) && (is_sr_an_subframe == 0))
              {
                  pSoundingrs_ul_config_dedicated->srsUeSubframe = 1;
                  ue->ulsch[eNB_id]->srs_active   = 1;
                  ue->ulsch[eNB_id]->Nsymb_pusch  = 12-(frame_parms->Ncp<<1)- ue->ulsch[eNB_id]->srs_active;
              }
              else
              {
                  LOG_I(PHY,"DROP UE-SRS-TX for this subframe %d.%d: collision with PUCCH2 or SR/AN: PUCCH2-occasion: %d, SR-AN-occasion[simSRS-SR-AN %d]: %d  \n", frame_tx, subframe_tx, is_pucch2_subframe, frame_parms->soundingrs_ul_config_common.ackNackSRS_SimultaneousTransmission, is_sr_an_subframe);
              }
          }
      }
      LOG_D(PHY," srsCellSubframe: %d, srsUeSubframe: %d, Nsymb-pusch: %d \n", pSoundingrs_ul_config_dedicated->srsCellSubframe, pSoundingrs_ul_config_dedicated->srsUeSubframe, ue->ulsch[eNB_id]->Nsymb_pusch);
  }
}


void get_cqipmiri_params(PHY_VARS_UE *ue,uint8_t eNB_id)
{

  CQI_REPORTPERIODIC *cqirep = &ue->cqi_report_config[eNB_id].CQI_ReportPeriodic;
  int cqi_PMI_ConfigIndex = cqirep->cqi_PMI_ConfigIndex;

  if (ue->frame_parms.frame_type == FDD) {
    if (cqi_PMI_ConfigIndex <= 1) {        // 2 ms CQI_PMI period
      cqirep->Npd = 2;
      cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex;
    } else if (cqi_PMI_ConfigIndex <= 6) { // 5 ms CQI_PMI period
      cqirep->Npd = 5;
      cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-2;
    } else if (cqi_PMI_ConfigIndex <=16) { // 10ms CQI_PMI period
      cqirep->Npd = 10;
      cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-7;
    } else if (cqi_PMI_ConfigIndex <= 36) { // 20 ms CQI_PMI period
      cqirep->Npd = 20;
      cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-17;
    } else if (cqi_PMI_ConfigIndex <= 76) { // 40 ms CQI_PMI period
      cqirep->Npd = 40;
      cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-37;
    } else if (cqi_PMI_ConfigIndex <= 156) { // 80 ms CQI_PMI period
      cqirep->Npd = 80;
      cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-77;
    } else if (cqi_PMI_ConfigIndex <= 316) { // 160 ms CQI_PMI period
      cqirep->Npd = 160;
      cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-157;
    }
    else if (cqi_PMI_ConfigIndex > 317) {

      if (cqi_PMI_ConfigIndex <= 349) { // 32 ms CQI_PMI period
  cqirep->Npd = 32;
      cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-318;
      }
      else if (cqi_PMI_ConfigIndex <= 413) { // 64 ms CQI_PMI period
  cqirep->Npd = 64;
  cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-350;
      }
      else if (cqi_PMI_ConfigIndex <= 541) { // 128 ms CQI_PMI period
  cqirep->Npd = 128;
  cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-414;
      }
    }
  }
  else { // TDD
   if (cqi_PMI_ConfigIndex == 0) {        // all UL subframes
     cqirep->Npd = 1;
     cqirep->N_OFFSET_CQI = 0;
   } else if (cqi_PMI_ConfigIndex <= 6) { // 5 ms CQI_PMI period
     cqirep->Npd = 5;
     cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-1;
   } else if (cqi_PMI_ConfigIndex <=16) { // 10ms CQI_PMI period
     cqirep->Npd = 10;
     cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-6;
   } else if (cqi_PMI_ConfigIndex <= 36) { // 20 ms CQI_PMI period
     cqirep->Npd = 20;
     cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-16;
   } else if (cqi_PMI_ConfigIndex <= 76) { // 40 ms CQI_PMI period
     cqirep->Npd = 40;
     cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-36;
   } else if (cqi_PMI_ConfigIndex <= 156) { // 80 ms CQI_PMI period
     cqirep->Npd = 80;
     cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-76;
   } else if (cqi_PMI_ConfigIndex <= 316) { // 160 ms CQI_PMI period
     cqirep->Npd = 160;
     cqirep->N_OFFSET_CQI = cqi_PMI_ConfigIndex-156;
   }
  }
}

PUCCH_FMT_t get_pucch_format(lte_frame_type_t frame_type,
                             lte_prefix_type_t cyclic_prefix_type,
                             uint8_t SR_payload,
                             uint8_t nb_cw,
                             uint8_t cqi_status,
                             uint8_t ri_status,
                             uint8_t bundling_flag)
{
  if((cqi_status == 0) && (ri_status==0))
  {
      // PUCCH Format 1 1a 1b
      // 1- SR only ==> PUCCH format 1
      // 2- 1bit Ack/Nack with/without SR  ==> PUCCH format 1a
      // 3- 2bits Ack/Nack with/without SR ==> PUCCH format 1b
      if((nb_cw == 1)&&(bundling_flag==bundling))
      {
          return pucch_format1a;
      }
      if((nb_cw == 1)&&(bundling_flag==multiplexing))
      {
          return pucch_format1b;
      }
      if(nb_cw == 2)
      {
          return pucch_format1b;
      }
      if(SR_payload == 1)
      {
          return pucch_format1;
          /*
          if (frame_type == FDD) {
              return pucch_format1;
          } else if (frame_type == TDD) {
              return pucch_format1b;
          } else {
              AssertFatal(1==0,"Unknown frame_type");
          }*/
      }
  }
  else
  {
      // PUCCH Format 2 2a 2b
      // 1- CQI only or RI only  ==> PUCCH format 2
      // 2- CQI or RI + 1bit Ack/Nack for normal CP  ==> PUCCH format 2a
      // 3- CQI or RI + 2bits Ack/Nack for normal CP ==> PUCCH format 2b
      // 4- CQI or RI + Ack/Nack for extended CP ==> PUCCH format 2
      if(nb_cw == 0)
      {
          return pucch_format2;
      }
      if(cyclic_prefix_type == NORMAL)
      {
          if(nb_cw == 1)
          {
              return pucch_format2a;
          }
          if(nb_cw == 2)
          {
              return pucch_format2b;
          }
      }
      else
      {
          return pucch_format2;
      }
  }
  return pucch_format1a;
}
uint16_t get_n1_pucch(PHY_VARS_UE *ue,
          UE_rxtx_proc_t *proc,
                      harq_status_t *harq_ack,
                      uint8_t eNB_id,
                      uint8_t *b,
                      uint8_t SR)
{

  LTE_DL_FRAME_PARMS *frame_parms=&ue->frame_parms;
  uint8_t nCCE0,nCCE1,nCCE2,nCCE3,harq_ack1,harq_ack0,harq_ack3,harq_ack2;
  ANFBmode_t bundling_flag;
  uint16_t n1_pucch0=0,n1_pucch1=0,n1_pucch2=0,n1_pucch3=0,n1_pucch_inter;
  static uint8_t candidate_dl[9]; // which downlink(s) the current ACK/NACK is associating to
  uint8_t last_dl=0xff; // the last downlink with valid DL-DCI. for calculating the PUCCH resource index
  int sf;
  int M;
  uint8_t ack_counter=0;
  // clear this, important for case where n1_pucch selection is not used
  int subframe=proc->subframe_tx;

  ue->pucch_sel[subframe] = 0;

  if (frame_parms->frame_type == FDD ) { // FDD
    sf = (subframe<4)? subframe+6 : subframe-4;
    LOG_D(PHY,"n1_pucch_UE: subframe %d, nCCE %d\n",sf,ue->pdcch_vars[ue->current_thread_id[proc->subframe_rx]][eNB_id]->nCCE[sf]);

    if (SR == 0)
      return(frame_parms->pucch_config_common.n1PUCCH_AN + ue->pdcch_vars[ue->current_thread_id[proc->subframe_rx]][eNB_id]->nCCE[sf]);
    else
      return(ue->scheduling_request_config[eNB_id].sr_PUCCH_ResourceIndex);
  } else {

    bundling_flag = ue->pucch_config_dedicated[eNB_id].tdd_AckNackFeedbackMode;
LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)

    if (bundling_flag==bundling) {
      LOG_D(PHY,"[UE%d] Frame %d subframe %d : get_n1_pucch, bundling, SR %d/%d\n",ue->Mod_id,proc->frame_tx,subframe,SR,
            ue->scheduling_request_config[eNB_id].sr_PUCCH_ResourceIndex);
    } else {
      LOG_D(PHY,"[UE%d] Frame %d subframe %d : get_n1_pucch, multiplexing, SR %d/%d\n",ue->Mod_id,proc->frame_tx,subframe,SR,
            ue->scheduling_request_config[eNB_id].sr_PUCCH_ResourceIndex);
    }

LOG_DEBUG_END

    switch (frame_parms->tdd_config) {
    case 1:  // DL:S:UL:UL:DL:DL:S:UL:UL:DL

      harq_ack0 = 2; // DTX
      M=1;

      // This is the offset for a particular subframe (2,3,4) => (0,2,4)
      if (subframe == 2) {  // ACK subframes 5,6
        candidate_dl[0] = 6;
        candidate_dl[1] = 5;
        M=2;
      } else if (subframe == 3) { // ACK subframe 9
        candidate_dl[0] = 9;
      } else if (subframe == 7) { // ACK subframes 0,1
        candidate_dl[0] = 1;
        candidate_dl[1] = 0;
        M=2;
      } else if (subframe == 8) { // ACK subframes 4
        candidate_dl[0] = 4;
      } else {
        LOG_E(PHY,"[UE%d] : Frame %d phy_procedures_lte.c: get_n1pucch, illegal tx-subframe %d for tdd_config %d\n",
              ue->Mod_id,proc->frame_tx,subframe,frame_parms->tdd_config);
        return(0);
      }

      // checking which downlink candidate is the last downlink with valid DL-DCI
      int k;
      for (k=0;k<M;k++) {
        if (harq_ack[candidate_dl[k]].send_harq_status>0) {
          last_dl = candidate_dl[k];
          break;
        }
      }
      if (last_dl >= 10) {
        LOG_E(PHY,"[UE%d] : Frame %d phy_procedures_lte.c: get_n1pucch, illegal rx-subframe %d (tx-subframe %d) for tdd_config %d\n",
              ue->Mod_id,proc->frame_tx,last_dl,subframe,frame_parms->tdd_config);
        return (0);
      }

      LOG_D(PHY,"SFN/SF %d/%d calculating n1_pucch0 from last_dl=%d\n",
          proc->frame_tx%1024,
          proc->subframe_tx,
          last_dl);

      // i=0
      nCCE0 = ue->pdcch_vars[ue->current_thread_id[proc->subframe_rx]][eNB_id]->nCCE[last_dl];
      n1_pucch0 = get_Np(frame_parms->N_RB_DL,nCCE0,0) + nCCE0+ frame_parms->pucch_config_common.n1PUCCH_AN;

      harq_ack0 = b[0];

      if (harq_ack0!=2) {  // DTX
        if (frame_parms->frame_type == FDD ) {
          if (SR == 0) {  // last paragraph pg 68 from 36.213 (v8.6), m=0
            b[0]=(M==2) ? 1-harq_ack0 : harq_ack0;
            b[1]=harq_ack0;   // in case we use pucch format 1b (subframes 2,7)
          ue->pucch_sel[subframe] = 0;
            return(n1_pucch0);
          } else { // SR and only 0 or 1 ACKs (first 2 entries in Table 7.3-1 of 36.213)
            b[0]=harq_ack0;
          return(ue->scheduling_request_config[eNB_id].sr_PUCCH_ResourceIndex);
          }
        } else {
          if (SR == 0) {
            b[0] = harq_ack0;
            b[1] = harq_ack0;
            ue->pucch_sel[subframe] = 0;
            return(n1_pucch0);
          } else {
            b[0] = harq_ack0;
            b[1] = harq_ack0;
            return(ue->scheduling_request_config[eNB_id].sr_PUCCH_ResourceIndex);
          }
        }
      }


      break;

    case 3:  // DL:S:UL:UL:UL:DL:DL:DL:DL:DL
      // in this configuration we have M=2 from pg 68 of 36.213 (v8.6)
      // Note: this doesn't allow using subframe 1 for PDSCH transmission!!! (i.e. SF 1 cannot be acked in SF 2)
      // set ACK/NAKs to DTX
      harq_ack1 = 2; // DTX
      harq_ack0 = 2; // DTX
      // This is the offset for a particular subframe (2,3,4) => (0,2,4)
      last_dl = (subframe-2)<<1;
      // i=0
      nCCE0 = ue->pdcch_vars[ue->current_thread_id[proc->subframe_rx]][eNB_id]->nCCE[5+last_dl];
      n1_pucch0 = get_Np(frame_parms->N_RB_DL,nCCE0,0) + nCCE0+ frame_parms->pucch_config_common.n1PUCCH_AN;
      // i=1
      nCCE1 = ue->pdcch_vars[ue->current_thread_id[proc->subframe_rx]][eNB_id]->nCCE[(6+last_dl)%10];
      n1_pucch1 = get_Np(frame_parms->N_RB_DL,nCCE1,1) + nCCE1 + frame_parms->pucch_config_common.n1PUCCH_AN;

      // set ACK/NAK to values if not DTX
      if (ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack[(6+last_dl)%10].send_harq_status>0)  // n-6 // subframe 6 is to be ACK/NAKed
        harq_ack1 = ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack[(6+last_dl)%10].ack;

      if (ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack[5+last_dl].send_harq_status>0)  // n-6 // subframe 5 is to be ACK/NAKed
        harq_ack0 = ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack[5+last_dl].ack;

      LOG_D(PHY,"SFN/SF %d/%d calculating n1_pucch cce0=%d n1_pucch0=%d cce1=%d n1_pucch1=%d\n",
                                      proc->frame_tx%1024,
                                      proc->subframe_tx,
                                      nCCE0,n1_pucch0,
                                      nCCE1,n1_pucch1);

      if (harq_ack1!=2) { // n-6 // subframe 6,8,0 and maybe 5,7,9 is to be ACK/NAKed

        if ((bundling_flag==bundling)&&(SR == 0)) {  // This is for bundling without SR,
          // n1_pucch index takes value of smallest element in set {0,1}
          // i.e. 0 if harq_ack0 is not DTX, otherwise 1
          b[0] = harq_ack1;

          if (harq_ack0!=2)
            b[0]=b[0]&harq_ack0;

          ue->pucch_sel[subframe] = 1;
          return(n1_pucch1);

        } else if ((bundling_flag==multiplexing)&&(SR==0)) { // Table 10.1
          if (harq_ack0 == 2)
            harq_ack0 = 0;

          b[1] = harq_ack0;
          b[0] = (harq_ack0!=harq_ack1)?0:1;

          if ((harq_ack0 == 1) && (harq_ack1 == 0)) {
            ue->pucch_sel[subframe] = 0;
            return(n1_pucch0);
          } else {
            ue->pucch_sel[subframe] = 1;
            return(n1_pucch1);
          }
        } else if (SR==1) { // SR and 0,1,or 2 ACKS, (first 3 entries in Table 7.3-1 of 36.213)
          // this should be number of ACKs (including
          if (harq_ack0 == 2)
            harq_ack0 = 0;

          b[0]= harq_ack1 | harq_ack0;
          b[1]= harq_ack1 ^ harq_ack0;
          return(ue->scheduling_request_config[eNB_id].sr_PUCCH_ResourceIndex);
        }
      } else if (harq_ack0!=2) { // n-7  // subframe 5,7,9 only is to be ACK/NAKed
        if ((bundling_flag==bundling)&&(SR == 0)) {  // last paragraph pg 68 from 36.213 (v8.6), m=0
          b[0]=harq_ack0;
          ue->pucch_sel[subframe] = 0;
          return(n1_pucch0);
        } else if ((bundling_flag==multiplexing)&&(SR==0)) { // Table 10.1 with i=1 set to DTX
          b[0] = harq_ack0;
          b[1] = 1-b[0];
          ue->pucch_sel[subframe] = 0;
          return(n1_pucch0);
        } else if (SR==1) { // SR and only 0 or 1 ACKs (first 2 entries in Table 7.3-1 of 36.213)
          b[0]=harq_ack0;
          b[1]=b[0];
          return(ue->scheduling_request_config[eNB_id].sr_PUCCH_ResourceIndex);
        }
      }

      break;

    case 4:  // DL:S:UL:UL:DL:DL:DL:DL:DL:DL
          // in this configuration we have M=4 from pg 68 of 36.213 (v8.6)
          // Note: this doesn't allow using subframe 1 for PDSCH transmission!!! (i.e. SF 1 cannot be acked in SF 2)
          // set ACK/NAKs to DTX
          harq_ack3 = 2; // DTX
          harq_ack2 = 2; // DTX
          harq_ack1 = 2; // DTX
          harq_ack0 = 2; // DTX
          // This is the offset for a particular subframe (2,3,4) => (0,2,4)
          //last_dl = (subframe-2)<<1;
          if (subframe == 2) {
          // i=0
          //nCCE0 = ue->pdcch_vars[ue->current_thread_id[proc->subframe_rx]][eNB_id]->nCCE[2+subframe];
          nCCE0 = ue->pdcch_vars[ue->current_thread_id[proc->subframe_rx]][eNB_id]->nCCE[(8+subframe)%10];
          n1_pucch0 = 2*get_Np(frame_parms->N_RB_DL,nCCE0,0) + nCCE0+ frame_parms->pucch_config_common.n1PUCCH_AN;
          // i=1
          nCCE1 = ue->pdcch_vars[ue->current_thread_id[proc->subframe_rx]][eNB_id]->nCCE[2+subframe];
          n1_pucch1 = get_Np(frame_parms->N_RB_DL,nCCE1,0) + get_Np(frame_parms->N_RB_DL,nCCE1,1) + nCCE1 + frame_parms->pucch_config_common.n1PUCCH_AN;
          // i=2
          nCCE2 = ue->pdcch_vars[ue->current_thread_id[proc->subframe_rx]][eNB_id]->nCCE[(8+subframe)%10];

          n1_pucch2 = 2*get_Np(frame_parms->N_RB_DL,nCCE2,1) + nCCE2+ frame_parms->pucch_config_common.n1PUCCH_AN;
          // i=3
          //nCCE3 = ue->pdcch_vars[ue->current_thread_id[proc->subframe_rx]][eNB_id]->nCCE[(9+subframe)%10];
          //n1_pucch3 = get_Np(frame_parms->N_RB_DL,nCCE3,1) + nCCE3 + frame_parms->pucch_config_common.n1PUCCH_AN;

          // set ACK/NAK to values if not DTX
          if (ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack[(8+subframe)%10].send_harq_status>0)  // n-6 // subframe 6 is to be ACK/NAKed
            harq_ack0 = ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack[(8+subframe)%10].ack;

          if (ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack[2+subframe].send_harq_status>0)  // n-6 // subframe 5 is to be ACK/NAKed
            harq_ack1 = ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack[2+subframe].ack;

          if (ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack[3+subframe].send_harq_status>0)  // n-6 // subframe 6 is to be ACK/NAKed
            harq_ack2 = ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack[3+subframe].ack;

          //if (ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack[(9+subframe)%10].send_harq_status>0)  // n-6 // subframe 5 is to be ACK/NAKed
            //harq_ack3 = ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack[(9+subframe)%10].ack;
          //LOG_I(PHY,"SFN/SF %d/%d calculating n1_pucch cce0=%d n1_pucch0=%d cce1=%d n1_pucch1=%d cce2=%d n1_pucch2=%d\n",
          //                      proc->frame_tx%1024,
          //                      proc->subframe_tx,
          //                      nCCE0,n1_pucch0,
          //                      nCCE1,n1_pucch1, nCCE2, n1_pucch2);
          }else if (subframe == 3) {
          // i=0

          nCCE0 = ue->pdcch_vars[ue->current_thread_id[proc->subframe_rx]][eNB_id]->nCCE[4+subframe];
          n1_pucch0 = 3*get_Np(frame_parms->N_RB_DL,nCCE0,0) + nCCE0+ frame_parms->pucch_config_common.n1PUCCH_AN;
          // i=1
          nCCE1 = ue->pdcch_vars[ue->current_thread_id[proc->subframe_rx]][eNB_id]->nCCE[5+subframe];
          n1_pucch1 = 2*get_Np(frame_parms->N_RB_DL,nCCE1,0) + get_Np(frame_parms->N_RB_DL,nCCE1,1) + nCCE1 + frame_parms->pucch_config_common.n1PUCCH_AN;
          // i=2
          nCCE2 = ue->pdcch_vars[ue->current_thread_id[proc->subframe_rx]][eNB_id]->nCCE[(6+subframe)];
          n1_pucch2 = get_Np(frame_parms->N_RB_DL,nCCE2,0) + 2*get_Np(frame_parms->N_RB_DL,nCCE2,1) + nCCE2+ frame_parms->pucch_config_common.n1PUCCH_AN;
          // i=3
          nCCE3 = ue->pdcch_vars[ue->current_thread_id[proc->subframe_rx]][eNB_id]->nCCE[(3+subframe)];
          n1_pucch3 = 3*get_Np(frame_parms->N_RB_DL,nCCE3,1) + nCCE3 + frame_parms->pucch_config_common.n1PUCCH_AN;

          // set ACK/NAK to values if not DTX
          if (ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack[4+subframe].send_harq_status>0)  // n-6 // subframe 6 is to be ACK/NAKed
          harq_ack0 = ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack[4+subframe].ack;

          if (ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack[5+subframe].send_harq_status>0)  // n-6 // subframe 5 is to be ACK/NAKed
          harq_ack1 = ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack[5+subframe].ack;

          if (ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack[(6+subframe)].send_harq_status>0)  // n-6 // subframe 6 is to be ACK/NAKed
          harq_ack2 = ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack[(6+subframe)].ack;

          if (ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack[(3+subframe)].send_harq_status>0)  // n-6 // subframe 5 is to be ACK/NAKed
          harq_ack3 = ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack[(3+subframe)].ack;
          }

          //LOG_I(PHY,"SFN/SF %d/%d calculating n1_pucch cce0=%d n1_pucch0=%d harq_ack0=%d cce1=%d n1_pucch1=%d harq_ack1=%d cce2=%d n1_pucch2=%d harq_ack2=%d cce3=%d n1_pucch3=%d harq_ack3=%d bundling_flag=%d\n",
          //                                proc->frame_tx%1024,
          //                                proc->subframe_tx,
          //                                nCCE0,n1_pucch0,harq_ack0,
          //                                nCCE1,n1_pucch1,harq_ack1, nCCE2, n1_pucch2, harq_ack2,
          //                                nCCE3, n1_pucch3, harq_ack3, bundling_flag);

          if ((bundling_flag==bundling)&&(SR == 0)) {  // This is for bundling without SR,
             b[0] = 1;
             ack_counter = 0;

             if ((harq_ack3!=2) ) {
                b[0] = b[0]&harq_ack3;
                n1_pucch_inter = n1_pucch3;
                ack_counter ++;
             }
             if ((harq_ack0!=2) ) {
                b[0] = b[0]&harq_ack0;
                n1_pucch_inter = n1_pucch0;
                ack_counter ++;
             }
             if ((harq_ack1!=2) ) {
                b[0] = b[0]&harq_ack1;
                n1_pucch_inter = n1_pucch1;
                ack_counter ++;
             }
             if ((harq_ack2!=2) ) {
                b[0] = b[0]&harq_ack2;
                n1_pucch_inter = n1_pucch2;
                ack_counter ++;
             }

             if (ack_counter == 0)
                 b[0] = 0;

             /*if (subframe == 3) {
                n1_pucch_inter = n1_pucch2;
             } else if (subframe == 2) {
                n1_pucch_inter = n1_pucch1;
             }*/

             //LOG_I(PHY,"SFN/SF %d/%d calculating n1_pucch n1_pucch_inter=%d  b[0]=%d b[1]=%d \n",
             //                                           proc->frame_tx%1024,
             //                                           proc->subframe_tx,n1_pucch_inter,
             //                                           b[0],b[1]);

              return(n1_pucch_inter);

            } else if ((bundling_flag==multiplexing)&&(SR==0)) { // Table 10.1

             if (subframe == 3) {
                 LOG_I(PHY, "sbuframe=%d \n",subframe);
              if ((harq_ack0 == 1) && (harq_ack1 == 1) && (harq_ack2 == 1) && (harq_ack3 == 1)) {
                b[0] = 1;
                b[1] = 1;
                return(n1_pucch1);
              } else if ((harq_ack0 == 1) && (harq_ack1 == 1) && (harq_ack2 == 1) && ((harq_ack3 == 2) || (harq_ack3 == 0))) {
                b[0] = 1;
                b[1] = 0;
                return(n1_pucch1);
              } else if (((harq_ack0 == 0) || (harq_ack0 == 2)) && ((harq_ack1 == 2) || (harq_ack1 == 0)) && (harq_ack2 == 0) && (harq_ack3 == 2)) {
                b[0] = 1;
                b[1] = 1;
                return(n1_pucch2);
              } else if ((harq_ack0 == 1) && (harq_ack1 == 1) && ((harq_ack2 == 2) || (harq_ack2 == 0)) && (harq_ack3 == 1)) {
                b[0] = 1;
                b[1] = 0;
                return(n1_pucch1);
              } else if ((harq_ack0 == 0) && (harq_ack1 == 2) && (harq_ack2 == 2) && (harq_ack3 == 2)) {
                b[0] = 1;
                b[1] = 0;
                return(n1_pucch0);
              } else if ((harq_ack0 == 1) && (harq_ack1 == 1) && ((harq_ack2 == 2) || (harq_ack2 == 0)) && ((harq_ack3 == 2) || (harq_ack3 == 0))) {
                b[0] = 1;
                b[1] = 0;
                return(n1_pucch1);
              } else if ((harq_ack0 == 1) && ((harq_ack1 == 2) || (harq_ack1 == 0)) && (harq_ack2 == 1) && (harq_ack3 == 1)) {
                b[0] = 0;
                b[1] = 1;
                return(n1_pucch3);
              } else if (((harq_ack0 == 0) || (harq_ack0 == 2)) && ((harq_ack1 == 2) || (harq_ack1 == 0)) && ((harq_ack2 == 2) || (harq_ack2 == 0)) && (harq_ack3 == 0)) {
                b[0] = 1;
                b[1] = 1;
                return(n1_pucch3);
              } else if ((harq_ack0 == 1) && ((harq_ack1 == 2) || (harq_ack1 == 0)) && (harq_ack2 == 1) && ((harq_ack3 == 2) || (harq_ack3 == 0))) {
                b[0] = 0;
                b[1] = 1;
                return(n1_pucch2);
              } else if ((harq_ack0 == 1) && ((harq_ack1 == 2) || (harq_ack1 == 0)) && ((harq_ack2 == 2) || (harq_ack2 == 0)) && (harq_ack3 == 1)) {
                b[0] = 0;
                b[1] = 1;
                return(n1_pucch0);
              } else if ((harq_ack0 == 1) && ((harq_ack1 == 2) || (harq_ack1 == 0)) && ((harq_ack2 == 2) || (harq_ack2 == 0)) && ((harq_ack3 == 2) || (harq_ack3 == 0))) {
                b[0] = 0;
                b[1] = 1;
                return(n1_pucch0);
              } else if (((harq_ack0 == 2) || (harq_ack0 == 0)) && (harq_ack1 == 1) && (harq_ack2 == 1) && (harq_ack3 == 1)) {
                b[0] = 0;
                b[1] = 1;
                return(n1_pucch3);
              } else if (((harq_ack0 == 2) || (harq_ack0 == 0)) && (harq_ack1 == 0) && (harq_ack2 == 2) && (harq_ack3 == 2)) {
                b[0] = 0;
                b[1] = 0;
                return(n1_pucch1);
              } else if (((harq_ack0 == 2) || (harq_ack0 == 0)) && (harq_ack1 == 1) && (harq_ack2 == 1) && ((harq_ack3 == 2) || (harq_ack3 == 0))) {
                b[0] = 1;
                b[1] = 0;
                return(n1_pucch2);
              } else if (((harq_ack0 == 2) || (harq_ack0 == 0)) && (harq_ack1 == 1) && ((harq_ack2 == 2) || (harq_ack2 == 0)) && (harq_ack3 == 1)) {
                b[0] = 1;
                b[1] = 0;
                return(n1_pucch3);
              } else if (((harq_ack0 == 2) || (harq_ack0 == 0)) && (harq_ack1 == 1) && ((harq_ack2 == 2) || (harq_ack2 == 0)) && ((harq_ack3 == 2) || (harq_ack3 == 0))) {
                b[0] = 0;
                b[1] = 1;
                return(n1_pucch1);
              } else if (((harq_ack0 == 2) || (harq_ack0 == 0)) && ((harq_ack1 == 2) || (harq_ack1 == 0)) && (harq_ack2 == 1) && (harq_ack3 == 1)) {
                b[0] = 0;
                b[1] = 1;
                return(n1_pucch3);
              } else if (((harq_ack0 == 2) || (harq_ack0 == 0)) && ((harq_ack1 == 2) || (harq_ack1 == 0)) && (harq_ack2 == 1) && ((harq_ack3 == 2) || (harq_ack3 == 0))) {
                b[0] = 0;
                b[1] = 0;
                return(n1_pucch2);
              } else if (((harq_ack0 == 2) || (harq_ack0 == 0)) && ((harq_ack1 == 2) || (harq_ack1 == 0)) && (harq_ack3 == 1) && ((harq_ack2 == 2) || (harq_ack2 == 0))) {
                b[0] = 0;
                b[1] = 0;
                return(n1_pucch3);
                }
             } else if (subframe == 2) {
                if ((harq_ack0 == 1) && (harq_ack1 == 1) && (harq_ack2 == 1)) {
                 b[0] = 1;
                 b[1] = 1;
                 return(n1_pucch2);
               } else if ((harq_ack0 == 1) && (harq_ack1 == 1) && ((harq_ack2 == 2) || (harq_ack2 == 0))) {
                 b[0] = 1;
                 b[1] = 1;
                 return(n1_pucch1);
               } else if ((harq_ack0 == 1) && ((harq_ack1 == 2) || (harq_ack1 == 0)) && (harq_ack2 == 1)) {
                 b[0] = 1;
                 b[1] = 1;
                 return(n1_pucch0);
               } else if ((harq_ack0 == 1) && ((harq_ack1 == 2) || (harq_ack1 == 0)) && ((harq_ack2 == 2) || (harq_ack2 == 0))) {
                 b[0] = 0;
                 b[1] = 1;
                 return(n1_pucch0);
               } else if (((harq_ack0 == 2) || (harq_ack0 == 0)) && (harq_ack1 == 1) && (harq_ack2 == 1)) {
                 b[0] = 1;
                 b[1] = 0;
                 return(n1_pucch2);
               } else if (((harq_ack0 == 2) || (harq_ack0 == 0)) && (harq_ack1 == 1) && ((harq_ack2 == 2) || (harq_ack2 == 0))) {
                 b[1] = 0;
                 b[0] = 0;
                 return(n1_pucch1);
               } else if (((harq_ack0 == 2) || (harq_ack0 == 0)) && ((harq_ack1 == 2) || (harq_ack1 == 0)) && (harq_ack2 == 1)) {
                 b[0] = 0;
                 b[1] = 0;
                 return(n1_pucch2);
               } else if ((harq_ack0 == 2) && (harq_ack1 == 2) && (harq_ack2 == 0)) {
                 b[0] = 0;
                 b[1] = 1;
                 return(n1_pucch2);
               } else if ((harq_ack0 == 2) && (harq_ack1 == 0) && ((harq_ack2 == 2) || (harq_ack2 == 0))) {
                 b[0] = 1;
                 b[1] = 0;
                 return(n1_pucch1);
               } else if ((harq_ack0 == 0) && ((harq_ack1 == 2) || (harq_ack1 == 0)) && ((harq_ack2 == 2) || (harq_ack2 == 0))) {
                 b[0] = 1;
                 b[1] = 0;
                 return(n1_pucch0);
               }

             }
            } else if (SR==1) { // SR and 0,1,or 2 ACKS, (first 3 entries in Table 7.3-1 of 36.213)
              // this should be number of ACKs (including
              ack_counter = 0;
              if (harq_ack0==1)
                 ack_counter ++;
              if (harq_ack1==1)
                 ack_counter ++;
              if (harq_ack2==1)
                 ack_counter ++;
              if (harq_ack3==1)
                 ack_counter ++;

            switch (ack_counter) {
               case 0:
                 b[0] = 0;
                 b[1] = 0;
               break;

               case 1:
                 b[0] = 1;
                 b[1] = 1;
               break;

               case 2:
                 b[0] = 1;
                 b[1] = 0;
               break;

               case 3:
                 b[0] = 0;
                 b[1] = 1;
               break;

               case 4:
                 b[0] = 1;
                 b[1] = 1;
               break;
            }

            ack_counter = 0;
            return(ue->scheduling_request_config[eNB_id].sr_PUCCH_ResourceIndex);
          }

          break;

    }  // switch tdd_config
  }

  LOG_E(PHY,"[UE%d] : Frame %d phy_procedures_lte.c: get_n1pucch, exit without proper return\n", ue->Mod_id, proc->frame_tx);
  return(-1);
}


void ulsch_common_procedures(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc, uint8_t empty_subframe) {

  int aa;
  LTE_DL_FRAME_PARMS *frame_parms=&ue->frame_parms;

  int nsymb;
  int subframe_tx = proc->subframe_tx;
  int ulsch_start;
  int overflow=0;
#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
  int k,l;
  int dummy_tx_buffer[frame_parms->samples_per_tti] __attribute__((aligned(16)));
#endif

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_ULSCH_COMMON,VCD_FUNCTION_IN);
LOG_DEBUG_BEGIN(UE_TIMING)
  start_meas(&ue->ofdm_mod_stats);
LOG_DEBUG_END
  nsymb = (frame_parms->Ncp == 0) ? 14 : 12;

#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)//this is the EXPRESS MIMO case
  ulsch_start = (ue->rx_offset+subframe_tx*frame_parms->samples_per_tti-
         ue->hw_timing_advance-
         ue->timing_advance-
         ue->N_TA_offset+5);
  //LOG_E(PHY,"ul-signal [subframe: %d, ulsch_start %d]\n",subframe_tx, ulsch_start);

  if(ulsch_start < 0)
      ulsch_start = ulsch_start + (LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*frame_parms->samples_per_tti);

  if (ulsch_start > (LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*frame_parms->samples_per_tti))
      ulsch_start = ulsch_start % (LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*frame_parms->samples_per_tti);

  //LOG_E(PHY,"ul-signal [subframe: %d, ulsch_start %d]\n",subframe_tx, ulsch_start);
#else //this is the normal case
  ulsch_start = (frame_parms->samples_per_tti*subframe_tx)-ue->N_TA_offset; //-ue->timing_advance;
#endif //else EXMIMO

  if (empty_subframe)
  {
    overflow = ulsch_start - 9*frame_parms->samples_per_tti;
    for (aa=0; aa<frame_parms->nb_antennas_tx; aa++) {
      
      if (overflow > 0)
	{
	  memset(&ue->common_vars.txdata[aa][ulsch_start],0,4*(frame_parms->samples_per_tti-overflow));
	  memset(&ue->common_vars.txdata[aa][0],0,4*overflow);
	}
      else
	{
	  memset(&ue->common_vars.txdata[aa][ulsch_start],0,4*frame_parms->samples_per_tti);
	}
    }
    return;
  }

  for (aa=0; aa<frame_parms->nb_antennas_tx; aa++) {
    if (frame_parms->Ncp == 1)
      PHY_ofdm_mod(&ue->common_vars.txdataF[aa][subframe_tx*nsymb*frame_parms->ofdm_symbol_size],
#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
       dummy_tx_buffer,
#else
       &ue->common_vars.txdata[aa][ulsch_start],
#endif
       frame_parms->ofdm_symbol_size,
       nsymb,
       frame_parms->nb_prefix_samples,
       CYCLIC_PREFIX);
    else {
      normal_prefix_mod(&ue->common_vars.txdataF[aa][subframe_tx*nsymb*frame_parms->ofdm_symbol_size],
#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
			dummy_tx_buffer,
#else
			&ue->common_vars.txdata[aa][ulsch_start],
#endif
			nsymb>>1,
			&ue->frame_parms);
      
      normal_prefix_mod(&ue->common_vars.txdataF[aa][((subframe_tx*nsymb)+(nsymb>>1))*frame_parms->ofdm_symbol_size],
#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
			dummy_tx_buffer+(frame_parms->samples_per_tti>>1),
#else
			&ue->common_vars.txdata[aa][ulsch_start+(frame_parms->samples_per_tti>>1)],
#endif
			nsymb>>1,
			&ue->frame_parms);
    }

#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
    apply_7_5_kHz(ue,dummy_tx_buffer,0);
    apply_7_5_kHz(ue,dummy_tx_buffer,1);
#else
    apply_7_5_kHz(ue,&ue->common_vars.txdata[aa][ulsch_start],0);
    apply_7_5_kHz(ue,&ue->common_vars.txdata[aa][ulsch_start],1);
#endif


#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
    overflow = ulsch_start - 9*frame_parms->samples_per_tti;


    for (k=ulsch_start,l=0; k<cmin(frame_parms->samples_per_tti*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME,ulsch_start+frame_parms->samples_per_tti); k++,l++) {
      ((short*)ue->common_vars.txdata[aa])[2*k] = ((short*)dummy_tx_buffer)[2*l];
      ((short*)ue->common_vars.txdata[aa])[2*k+1] = ((short*)dummy_tx_buffer)[2*l+1];
    }

    for (k=0; k<overflow; k++,l++) {
      ((short*)ue->common_vars.txdata[aa])[2*k] = ((short*)dummy_tx_buffer)[2*l];
      ((short*)ue->common_vars.txdata[aa])[2*k+1] = ((short*)dummy_tx_buffer)[2*l+1];
    }
#if defined(EXMIMO)
    // handle switch before 1st TX subframe, guarantee that the slot prior to transmission is switch on
    for (k=ulsch_start - (frame_parms->samples_per_tti>>1) ; k<ulsch_start ; k++) {
      if (k<0)
	ue->common_vars.txdata[aa][k+frame_parms->samples_per_tti*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME] &= 0xFFFEFFFE;
      else if (k>(frame_parms->samples_per_tti*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME))
	ue->common_vars.txdata[aa][k-frame_parms->samples_per_tti*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME] &= 0xFFFEFFFE;
      else
	ue->common_vars.txdata[aa][k] &= 0xFFFEFFFE;
    }
#endif
#endif
    /*
    only for debug
    LOG_I(PHY,"ul-signal [subframe: %d, ulsch_start %d, TA: %d, rxOffset: %d, timing_advance: %d, hw_timing_advance: %d]\n",subframe_tx, ulsch_start, ue->N_TA_offset, ue->rx_offset, ue->timing_advance, ue->hw_timing_advance);
    if( (crash == 1) && (subframe_tx == 0) )
    {
      LOG_E(PHY,"***** DUMP TX Signal [ulsch_start %d] *****\n",ulsch_start);
      LOG_M("txBuff.m","txSignal",&ue->common_vars.txdata[aa][ulsch_start],frame_parms->samples_per_tti,1,1);
    }
    */

  } //nb_antennas_tx

LOG_DEBUG_BEGIN(UE_TIMING)
      stop_meas(&ue->ofdm_mod_stats);
LOG_DEBUG_END

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_ULSCH_COMMON,VCD_FUNCTION_OUT);

}

void ue_prach_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t abstraction_flag,runmode_t mode) {

  int frame_tx = proc->frame_tx;
  int subframe_tx = proc->subframe_tx;
  LOG_USEDINLOG_VAR(int, prach_power);
  PRACH_RESOURCES_t prach_resources_local;

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_PRACH, VCD_FUNCTION_IN);

  ue->generate_prach=0;

  if (ue->mac_enabled==0){
    ue->prach_resources[eNB_id] = &prach_resources_local;
    prach_resources_local.ra_RNTI = 0xbeef;
    prach_resources_local.ra_PreambleIndex = 0;
  }

  if (ue->mac_enabled==1){
    // ask L2 for RACH transport
    if ((mode != rx_calib_ue) && (mode != rx_calib_ue_med) && (mode != rx_calib_ue_byp) && (mode != no_L2_connect) ) {
      //LOG_D(PHY,"Getting PRACH resources\n");

      ue->prach_resources[eNB_id] = ue_get_rach(ue->Mod_id,
						ue->CC_id,
						frame_tx,
						eNB_id,
						subframe_tx);
      LOG_D(PHY,"Prach resources %p\n",ue->prach_resources[eNB_id]);
    }
  }

  if (ue->prach_resources[eNB_id]!=NULL) {

    ue->generate_prach=1;
    ue->prach_cnt=0;
#ifdef SMBV
    ue->prach_resources[eNB_id]->ra_PreambleIndex = 19;
#endif
    LOG_I(PHY,"mode %d\n",mode);
    
    if ((ue->mac_enabled==1) && (mode != calib_prach_tx)) {
      ue->tx_power_dBm[subframe_tx] = ue->prach_resources[eNB_id]->ra_PREAMBLE_RECEIVED_TARGET_POWER+get_PL(ue->Mod_id,ue->CC_id,eNB_id);
    }
    else {
      ue->tx_power_dBm[subframe_tx] = ue->tx_power_max_dBm;
      ue->prach_resources[eNB_id]->ra_PreambleIndex = 19;
    }
    
    LOG_D(PHY,"[UE  %d][RAPROC] Frame %d, Subframe %d : Generating PRACH, preamble %d,PL %d,  P0_PRACH %d, TARGET_RECEIVED_POWER %d dBm, PRACH TDD Resource index %d, RA-RNTI %d\n",
	  ue->Mod_id,
	  frame_tx,
	  subframe_tx,
	  ue->prach_resources[eNB_id]->ra_PreambleIndex,
	  get_PL(ue->Mod_id,ue->CC_id,eNB_id),
	  ue->tx_power_dBm[subframe_tx],
	  ue->prach_resources[eNB_id]->ra_PREAMBLE_RECEIVED_TARGET_POWER,
	  ue->prach_resources[eNB_id]->ra_TDD_map_index,
	  ue->prach_resources[eNB_id]->ra_RNTI);
    
    ue->tx_total_RE[subframe_tx] = 96;
    
#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
    ue->prach_vars[eNB_id]->amp = get_tx_amp(ue->tx_power_dBm[subframe_tx],
					     ue->tx_power_max_dBm,
					     ue->frame_parms.N_RB_UL,
					     6);

#else
    ue->prach_vars[eNB_id]->amp = AMP;
#endif

    if ((mode == calib_prach_tx) && (((proc->frame_tx&0xfffe)%100)==0))
      LOG_D(PHY,"[UE  %d][RAPROC] Frame %d, Subframe %d : PRACH TX power %d dBm, amp %d\n",
	    ue->Mod_id,
	    proc->frame_rx,
	    proc->subframe_tx,
	    ue->tx_power_dBm[subframe_tx],
	    ue->prach_vars[eNB_id]->amp);
    
    
    //      start_meas(&ue->tx_prach);
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GENERATE_PRACH, VCD_FUNCTION_IN);
    prach_power = generate_prach(ue,eNB_id,subframe_tx,frame_tx);
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GENERATE_PRACH, VCD_FUNCTION_OUT);
    //      stop_meas(&ue->tx_prach);
    LOG_D(PHY,"[UE  %d][RAPROC] PRACH PL %d dB, power %d dBm, digital power %d dB (amp %d)\n",
	  ue->Mod_id,
	  get_PL(ue->Mod_id,ue->CC_id,eNB_id),
	  ue->tx_power_dBm[subframe_tx],
	  dB_fixed(prach_power),
	  ue->prach_vars[eNB_id]->amp);

    if (ue->mac_enabled==1){
      Msg1_transmitted(ue->Mod_id,
		       ue->CC_id,
		       frame_tx,
		       eNB_id);
    }
    
    LOG_I(PHY,"[UE  %d][RAPROC] Frame %d, subframe %d: Generating PRACH (eNB %d) preamble index %d for UL, TX power %d dBm (PL %d dB), l3msg \n",
	  ue->Mod_id,frame_tx,subframe_tx,eNB_id,
	  ue->prach_resources[eNB_id]->ra_PreambleIndex,
	  ue->prach_resources[eNB_id]->ra_PREAMBLE_RECEIVED_TARGET_POWER+get_PL(ue->Mod_id,ue->CC_id,eNB_id),
	  get_PL(ue->Mod_id,ue->CC_id,eNB_id));
    
    
    
    // if we're calibrating the PRACH kill the pointer to its resources so that the RA protocol doesn't continue
    if (mode == calib_prach_tx)
      ue->prach_resources[eNB_id]=NULL;

    LOG_D(PHY,"[UE %d] frame %d subframe %d : generate_prach %d, prach_cnt %d\n",
	  ue->Mod_id,frame_tx,subframe_tx,ue->generate_prach,ue->prach_cnt);

    ue->prach_cnt++;

    if (ue->prach_cnt==3)
      ue->generate_prach=0;
  }
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_PRACH, VCD_FUNCTION_OUT);
}

void ue_ulsch_uespec_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t abstraction_flag) {

  int harq_pid;
  int frame_tx=proc->frame_tx;
  int subframe_tx=proc->subframe_tx;
  int Mod_id = ue->Mod_id;
  int CC_id = ue->CC_id;
  uint8_t Msg3_flag=0;
  uint16_t first_rb, nb_rb;
  unsigned int input_buffer_length;
  int i;
  int aa;
  int tx_amp;
  uint8_t ulsch_input_buffer[5477] __attribute__ ((aligned(32)));
  uint8_t access_mode;
  uint8_t Nbundled=0;
  uint8_t NbundledCw1=0;
  uint8_t ack_status_cw0=0;
  uint8_t ack_status_cw1=0;
  uint8_t cqi_status = 0;
  uint8_t ri_status  = 0;
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_ULSCH_UESPEC,VCD_FUNCTION_IN);

  // get harq_pid from subframe relationship
  harq_pid = subframe2harq_pid(&ue->frame_parms,
             frame_tx,
             subframe_tx);

  LOG_D(PHY,"Frame %d, Subframe %d : ue_uespec_procedures, harq_pid %d => subframe_scheduling %d\n",
	frame_tx,subframe_tx,harq_pid,
	ue->ulsch[eNB_id]->harq_processes[harq_pid]->subframe_scheduling_flag);

  if (ue->mac_enabled == 1) {
    if ((ue->ulsch_Msg3_active[eNB_id] == 1)       &&
	(ue->ulsch_Msg3_frame[eNB_id] == frame_tx) &&
	(ue->ulsch_Msg3_subframe[eNB_id] == subframe_tx)) { // Initial Transmission of Msg3

      ue->ulsch[eNB_id]->harq_processes[harq_pid]->subframe_scheduling_flag = 1;

      if (ue->ulsch[eNB_id]->harq_processes[harq_pid]->round==0)
	generate_ue_ulsch_params_from_rar(ue,
					  proc,
					  eNB_id);

      ue->ulsch[eNB_id]->power_offset = 14;
      LOG_D(PHY,"[UE  %d][RAPROC] Frame %d: Setting Msg3_flag in subframe %d, for harq_pid %d\n",
      Mod_id,
      frame_tx,
      subframe_tx,
      harq_pid);
      Msg3_flag = 1;
    } else {

      
      AssertFatal(harq_pid!=255,"[UE%d] Frame %d subframe %d ulsch_decoding.c: FATAL ERROR: illegal harq_pid, exiting\n",
	      Mod_id,frame_tx, subframe_tx);
      Msg3_flag=0;
    }
  }

  if (ue->ulsch[eNB_id]->harq_processes[harq_pid]->subframe_scheduling_flag == 1) {

    uint8_t isBad = 0;
    if (ue->frame_parms.N_RB_UL <= ue->ulsch[eNB_id]->harq_processes[harq_pid]->first_rb) {
      LOG_D(PHY,"Invalid PUSCH first_RB=%d for N_RB_UL=%d\n",
          ue->ulsch[eNB_id]->harq_processes[harq_pid]->first_rb,
          ue->frame_parms.N_RB_UL);
      isBad = 1;
    }
    if (ue->frame_parms.N_RB_UL < ue->ulsch[eNB_id]->harq_processes[harq_pid]->nb_rb) {
      LOG_D(PHY,"Invalid PUSCH num_RB=%d for N_RB_UL=%d\n",
          ue->ulsch[eNB_id]->harq_processes[harq_pid]->nb_rb,
          ue->frame_parms.N_RB_UL);
      isBad = 1;
    }
    if (0 > ue->ulsch[eNB_id]->harq_processes[harq_pid]->first_rb) {
      LOG_D(PHY,"Invalid PUSCH first_RB=%d\n",
          ue->ulsch[eNB_id]->harq_processes[harq_pid]->first_rb);
      isBad = 1;
    }
    if (0 >= ue->ulsch[eNB_id]->harq_processes[harq_pid]->nb_rb) {
      LOG_D(PHY,"Invalid PUSCH num_RB=%d\n",
          ue->ulsch[eNB_id]->harq_processes[harq_pid]->nb_rb);
      isBad = 1;
    }
    if (ue->frame_parms.N_RB_UL < (ue->ulsch[eNB_id]->harq_processes[harq_pid]->nb_rb + ue->ulsch[eNB_id]->harq_processes[harq_pid]->first_rb)) {
      LOG_D(PHY,"Invalid PUSCH num_RB=%d + first_RB=%d for N_RB_UL=%d\n",
          ue->ulsch[eNB_id]->harq_processes[harq_pid]->nb_rb,
          ue->ulsch[eNB_id]->harq_processes[harq_pid]->first_rb,
          ue->frame_parms.N_RB_UL);
      isBad = 1;
    }
    if ((0 > ue->ulsch[eNB_id]->harq_processes[harq_pid]->rvidx) ||
        (3 < ue->ulsch[eNB_id]->harq_processes[harq_pid]->rvidx)) {
      LOG_D(PHY,"Invalid PUSCH RV index=%d\n", ue->ulsch[eNB_id]->harq_processes[harq_pid]->rvidx);
      isBad = 1;
    }

    if (isBad) {
      LOG_I(PHY,"Skip PUSCH generation!\n");
      ue->ulsch[eNB_id]->harq_processes[harq_pid]->subframe_scheduling_flag = 0;
    }
  }
  if (ue->ulsch[eNB_id]->harq_processes[harq_pid]->subframe_scheduling_flag == 1) {

    ue->generate_ul_signal[eNB_id] = 1;

    // deactivate service request
    // ue->ulsch[eNB_id]->harq_processes[harq_pid]->subframe_scheduling_flag = 0;
    LOG_D(PHY,"Generating PUSCH (Abssubframe: %d.%d): harq-Id: %d, round: %d, MaxReTrans: %d \n",frame_tx,subframe_tx,harq_pid,ue->ulsch[eNB_id]->harq_processes[harq_pid]->round,ue->ulsch[eNB_id]->Mlimit);
    if (ue->ulsch[eNB_id]->harq_processes[harq_pid]->round >= (ue->ulsch[eNB_id]->Mlimit - 1))
    {
      //        LOG_D(PHY,"PUSCH MAX Retransmission achieved ==> send last pusch\n");
        ue->ulsch[eNB_id]->harq_processes[harq_pid]->subframe_scheduling_flag = 0;
        ue->ulsch[eNB_id]->harq_processes[harq_pid]->round  = 0;
    }

    ack_status_cw0 = reset_ack(&ue->frame_parms,
            ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack,
            subframe_tx,
            proc->subframe_rx,
            ue->ulsch[eNB_id]->o_ACK,
            &Nbundled,
            0);
    ack_status_cw1 = reset_ack(&ue->frame_parms,
            ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][1]->harq_ack,
            subframe_tx,
            proc->subframe_rx,
            ue->ulsch[eNB_id]->o_ACK,
            &NbundledCw1,
            1);

    //Nbundled = ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack;
    //ue->ulsch[eNB_id]->bundling = Nbundled;

    first_rb = ue->ulsch[eNB_id]->harq_processes[harq_pid]->first_rb;
    nb_rb = ue->ulsch[eNB_id]->harq_processes[harq_pid]->nb_rb;


    // check Periodic CQI/RI reporting
    cqi_status = ((ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.cqi_PMI_ConfigIndex>0)&&
        (is_cqi_TXOp(ue,proc,eNB_id)==1));

    ri_status = ((ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.ri_ConfigIndex>0) &&
             (is_ri_TXOp(ue,proc,eNB_id)==1));

    // compute CQI/RI resources
    compute_cqi_ri_resources(ue, ue->ulsch[eNB_id], eNB_id, ue->ulsch[eNB_id]->rnti, P_RNTI, CBA_RNTI, cqi_status, ri_status);

    if (ack_status_cw0 > 0) {

      // check if we received a PDSCH at subframe_tx - 4
      // ==> send ACK/NACK on PUSCH
      if (ue->frame_parms.frame_type == FDD)
      {
        ue->ulsch[eNB_id]->harq_processes[harq_pid]->O_ACK = ack_status_cw0 + ack_status_cw1;
      }


LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
    if(ue->ulsch[eNB_id]->o_ACK[0])
    {
    	LOG_I(PHY,"PUSCH ACK\n");
        T(T_UE_PHY_DLSCH_UE_ACK, T_INT(eNB_id), T_INT(frame_tx%1024), T_INT(subframe_tx), T_INT(ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->rnti),
                      T_INT(ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->current_harq_pid));
    }
    else
    {
    	LOG_I(PHY,"PUSCH NACK\n");
        T(T_UE_PHY_DLSCH_UE_NACK, T_INT(eNB_id), T_INT(frame_tx%1024), T_INT(subframe_tx), T_INT(ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->rnti),
                      T_INT(ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->current_harq_pid));
    }
      LOG_I(PHY,"[UE  %d][PDSCH %x] AbsSubFrame %d.%d Generating ACK (%d,%d) for %d bits on PUSCH\n",
        Mod_id,
        ue->ulsch[eNB_id]->rnti,
        frame_tx%1024,subframe_tx,
        ue->ulsch[eNB_id]->o_ACK[0],ue->ulsch[eNB_id]->o_ACK[1],
        ue->ulsch[eNB_id]->harq_processes[harq_pid]->O_ACK);
LOG_DEBUG_END
    }


LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
        LOG_D(PHY,
              "[UE  %d][PUSCH %d] AbsSubframe %d.%d Generating PUSCH : first_rb %d, nb_rb %d, round %d, mcs %d, rv %d, "
              "cyclic_shift %d (cyclic_shift_common %d,n_DMRS2 %d,n_PRS %d), ACK (%d,%d), O_ACK %d, ack_status_cw0 %d ack_status_cw1 %d bundling %d, Nbundled %d, CQI %d, RI %d\n",
          Mod_id,harq_pid,frame_tx%1024,subframe_tx,
          first_rb,nb_rb,
          ue->ulsch[eNB_id]->harq_processes[harq_pid]->round,
          ue->ulsch[eNB_id]->harq_processes[harq_pid]->mcs,
          ue->ulsch[eNB_id]->harq_processes[harq_pid]->rvidx,
          (ue->frame_parms.pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift+
           ue->ulsch[eNB_id]->harq_processes[harq_pid]->n_DMRS2+
           ue->frame_parms.pusch_config_common.ul_ReferenceSignalsPUSCH.nPRS[subframe_tx<<1])%12,
          ue->frame_parms.pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift,
          ue->ulsch[eNB_id]->harq_processes[harq_pid]->n_DMRS2,
          ue->frame_parms.pusch_config_common.ul_ReferenceSignalsPUSCH.nPRS[subframe_tx<<1],
          ue->ulsch[eNB_id]->o_ACK[0],ue->ulsch[eNB_id]->o_ACK[1],
          ue->ulsch[eNB_id]->harq_processes[harq_pid]->O_ACK,
          ack_status_cw0,
          ack_status_cw1,
          ue->ulsch[eNB_id]->bundling, Nbundled,
          cqi_status,
          ri_status);
LOG_DEBUG_END





    if (Msg3_flag == 1) {
      LOG_I(PHY,"[UE  %d][RAPROC] Frame %d, Subframe %d Generating (RRCConnectionRequest) Msg3 (nb_rb %d, first_rb %d, round %d, rvidx %d) Msg3: %x.%x.%x|%x.%x.%x.%x.%x.%x\n",Mod_id,frame_tx,
	    subframe_tx,
	    ue->ulsch[eNB_id]->harq_processes[harq_pid]->nb_rb,
	    ue->ulsch[eNB_id]->harq_processes[harq_pid]->first_rb,
	    ue->ulsch[eNB_id]->harq_processes[harq_pid]->round,
	    ue->ulsch[eNB_id]->harq_processes[harq_pid]->rvidx,
	    ue->prach_resources[eNB_id]->Msg3[0],
	    ue->prach_resources[eNB_id]->Msg3[1],
	    ue->prach_resources[eNB_id]->Msg3[2],
	    ue->prach_resources[eNB_id]->Msg3[3],
	    ue->prach_resources[eNB_id]->Msg3[4],
	    ue->prach_resources[eNB_id]->Msg3[5],
	    ue->prach_resources[eNB_id]->Msg3[6],
	    ue->prach_resources[eNB_id]->Msg3[7],
	    ue->prach_resources[eNB_id]->Msg3[8]);
LOG_DEBUG_BEGIN(UE_TIMING)
      start_meas(&ue->ulsch_encoding_stats);
LOG_DEBUG_END
      
      AssertFatal(ulsch_encoding(ue->prach_resources[eNB_id]->Msg3,
				 ue,
				 harq_pid,
				 eNB_id,
				 proc->subframe_rx,
				 ue->transmission_mode[eNB_id],0,0)==0,
		  "ulsch_coding.c: FATAL ERROR: returning\n");
      
LOG_DEBUG_BEGIN(UE_TIMING)
      stop_meas(&ue->phy_proc_tx);
      LOG_UI(PHY,"------FULL TX PROC : %5.2f ------\n",ue->phy_proc_tx.p_time/(cpuf*1000.0));
      stop_meas(&ue->ulsch_encoding_stats);
LOG_DEBUG_END

      if (ue->mac_enabled == 1) {

	// signal MAC that Msg3 was sent
	Msg3_transmitted(Mod_id,
			 CC_id,
			 frame_tx,
			 eNB_id);
      }
      LOG_I(PHY,"Done Msg3 encoding\n");
    } // Msg3_flag==1
    else {// Msg3_flag==0
      input_buffer_length = ue->ulsch[eNB_id]->harq_processes[harq_pid]->TBS/8;

      if (ue->mac_enabled==1) {

	//  LOG_D(PHY,"[UE  %d] ULSCH : Searching for MAC SDUs\n",Mod_id);
	if (ue->ulsch[eNB_id]->harq_processes[harq_pid]->round==0) {
	  //if (ue->ulsch[eNB_id]->harq_processes[harq_pid]->calibration_flag == 0) {
	  access_mode=SCHEDULED_ACCESS;

	  ue_get_sdu(Mod_id,
		     CC_id,
		     frame_tx,
		     subframe_tx,
		     eNB_id,
		     ulsch_input_buffer,
		     input_buffer_length,
		     &access_mode);
	}
	
      

	
LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
	LOG_D(PHY,"[UE] Frame %d, subframe %d : ULSCH SDU (TX harq_pid %d)  (%d bytes) : \n",frame_tx,subframe_tx,harq_pid, ue->ulsch[eNB_id]->harq_processes[harq_pid]->TBS>>3);
	
	for (i=0; i<ue->ulsch[eNB_id]->harq_processes[harq_pid]->TBS>>3; i++)
	  LOG_T(PHY,"%x.",ulsch_input_buffer[i]);
	
	LOG_T(PHY,"\n");
LOG_DEBUG_END
      }
      else {
	unsigned int taus(void);
	
	for (i=0; i<input_buffer_length; i++)
	  ulsch_input_buffer[i]= (uint8_t)(taus()&0xff);
	
      }
      
LOG_DEBUG_BEGIN(UE_TIMING)
      start_meas(&ue->ulsch_encoding_stats);
LOG_DEBUG_END
      if (abstraction_flag==0) {
	
	if (ulsch_encoding(ulsch_input_buffer,
			   ue,
			   harq_pid,
			   eNB_id,
			   proc->subframe_rx,
			   ue->transmission_mode[eNB_id],0,
			   Nbundled)!=0) {
	  LOG_E(PHY,"ulsch_coding.c: FATAL ERROR: returning\n");
	  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX, VCD_FUNCTION_OUT);
LOG_DEBUG_BEGIN(UE_TIMING)
	  stop_meas(&ue->phy_proc_tx);
LOG_DEBUG_END
	  return;
	}
      }
      
LOG_DEBUG_BEGIN(UE_TIMING)
      stop_meas(&ue->ulsch_encoding_stats);
LOG_DEBUG_END
    }
    
    if (abstraction_flag == 0) {
      if (ue->mac_enabled==1) {
	pusch_power_cntl(ue,proc,eNB_id,1, abstraction_flag);
	ue->tx_power_dBm[subframe_tx] = ue->ulsch[eNB_id]->Po_PUSCH;
      }
      else {
	ue->tx_power_dBm[subframe_tx] = ue->tx_power_max_dBm;
      }
      ue->tx_total_RE[subframe_tx] = nb_rb*12;
      
#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
      tx_amp = get_tx_amp(ue->tx_power_dBm[subframe_tx],
			  ue->tx_power_max_dBm,
			  ue->frame_parms.N_RB_UL,
			  nb_rb);
#else
    tx_amp = AMP;
#endif

    T(T_UE_PHY_PUSCH_TX_POWER, T_INT(eNB_id), T_INT(frame_tx%1024), T_INT(subframe_tx),T_INT(ue->tx_power_dBm[subframe_tx]),
      T_INT(tx_amp),T_INT(ue->ulsch[eNB_id]->f_pusch),T_INT(get_PL(Mod_id,0,eNB_id)),T_INT(nb_rb));

LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
    LOG_D(PHY,"[UE  %d][PUSCH %d] AbsSubFrame %d.%d, generating PUSCH, Po_PUSCH: %d dBm (max %d dBm), amp %d\n",
	  Mod_id,harq_pid,frame_tx%1024,subframe_tx,ue->tx_power_dBm[subframe_tx],ue->tx_power_max_dBm, tx_amp);
LOG_DEBUG_END
LOG_DEBUG_BEGIN(UE_TIMING)
    start_meas(&ue->ulsch_modulation_stats);
LOG_DEBUG_END
    ulsch_modulation(ue->common_vars.txdataF,
		     tx_amp,
		     frame_tx,
		     subframe_tx,
		     &ue->frame_parms,
		     ue->ulsch[eNB_id]);
    for (aa=0; aa<1/*frame_parms->nb_antennas_tx*/; aa++)
      generate_drs_pusch(ue,
			 proc,
			 (LTE_DL_FRAME_PARMS *)NULL,
			 (int32_t**)NULL,
			 eNB_id,
			 tx_amp,
			 subframe_tx,
			 first_rb,
			 nb_rb,
			 aa);

LOG_DEBUG_BEGIN(UE_TIMING)
    stop_meas(&ue->ulsch_modulation_stats);
LOG_DEBUG_END

    }
    
    if (abstraction_flag==1) {
      // clear SR
      ue->sr[subframe_tx]=0;
    }
  } // subframe_scheduling_flag==1

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_ULSCH_UESPEC,VCD_FUNCTION_OUT);

}

void ue_srs_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t abstraction_flag)
{

  //LTE_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
  //int8_t  frame_tx    = proc->frame_tx;
  int8_t  subframe_tx = proc->subframe_tx;
  int16_t tx_amp;
  int16_t Po_SRS;
  uint8_t nb_rb_srs;

  SOUNDINGRS_UL_CONFIG_DEDICATED *pSoundingrs_ul_config_dedicated=&ue->soundingrs_ul_config_dedicated[eNB_id];
  uint8_t isSrsTxOccasion = pSoundingrs_ul_config_dedicated->srsUeSubframe;

  if(isSrsTxOccasion)
  {
    ue->generate_ul_signal[eNB_id] = 1;
    if (ue->mac_enabled==1)
    {
      srs_power_cntl(ue,proc,eNB_id, (uint8_t*)(&nb_rb_srs), abstraction_flag);
      Po_SRS = ue->ulsch[eNB_id]->Po_SRS;
    }
    else
    {
      Po_SRS = ue->tx_power_max_dBm;
    }

#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
    if (ue->mac_enabled==1)
    {
    tx_amp = get_tx_amp(Po_SRS,
                        ue->tx_power_max_dBm,
                        ue->frame_parms.N_RB_UL,
                        nb_rb_srs);
    }
    else
    {
        tx_amp = AMP;
    }
#else
      tx_amp = AMP;
#endif
    LOG_D(PHY,"SRS PROC; TX_MAX_POWER %d, Po_SRS %d, NB_RB_UL %d, NB_RB_SRS %d TX_AMPL %d\n",ue->tx_power_max_dBm,
            Po_SRS,
            ue->frame_parms.N_RB_UL,
            nb_rb_srs,
            tx_amp);

    uint16_t nsymb = (ue->frame_parms.Ncp==0) ? 14:12;
    uint16_t symbol_offset = (int)ue->frame_parms.ofdm_symbol_size*((subframe_tx*nsymb)+(nsymb-1));
    generate_srs(&ue->frame_parms,
     &ue->soundingrs_ul_config_dedicated[eNB_id],
     &ue->common_vars.txdataF[eNB_id][symbol_offset],
     tx_amp,
     subframe_tx);
  }
}

int16_t get_pucch2_cqi(PHY_VARS_UE *ue,int eNB_id,int *len) {

  if ((ue->transmission_mode[eNB_id]<4)||
      (ue->transmission_mode[eNB_id]==7)) { // Mode 1-0 feedback
    // 4-bit CQI message
          /*LOG_I(PHY,"compute CQI value, TM %d, length 4, Cqi Avg %d, value %d \n", ue->transmission_mode[eNB_id],
                          ue->measurements.wideband_cqi_avg[eNB_id],
                          sinr2cqi((double)ue->measurements.wideband_cqi_avg[eNB_id],
                                    ue->transmission_mode[eNB_id]));*/
    *len=4;
    return(sinr2cqi((double)ue->measurements.wideband_cqi_avg[eNB_id],
        ue->transmission_mode[eNB_id]));
  }
  else { // Mode 1-1 feedback, later
          //LOG_I(PHY,"compute CQI value, TM %d, length 0, Cqi Avg 0 \n", ue->transmission_mode[eNB_id]);
    *len=0;
    // 2-antenna ports RI=1, 6 bits (2 PMI, 4 CQI)

    // 2-antenna ports RI=2, 8 bits (1 PMI, 7 CQI/DIFF CQI)
    return(0);
  }
}


int16_t get_pucch2_ri(PHY_VARS_UE *ue,int eNB_id) {

  return(1);
}


void get_pucch_param(PHY_VARS_UE    *ue,
                     UE_rxtx_proc_t *proc,
                     uint8_t        *ack_payload,
                     PUCCH_FMT_t    format,
                     uint8_t        eNB_id,
                     uint8_t        SR,
                     uint8_t        cqi_report,
                     uint16_t       *pucch_resource,
                     uint8_t        *pucch_payload,
                     uint16_t       *plength)
{

    switch (format) {
    case pucch_format1:
    {
        pucch_resource[0] = ue->scheduling_request_config[eNB_id].sr_PUCCH_ResourceIndex;
        pucch_payload[0]  = 0; // payload is ignored in case of format1
        pucch_payload[1]  = 0; // payload is ignored in case of format1
    }
    break;

    case pucch_format1a:
    case pucch_format1b:
    case pucch_format1b_csA2:
    case pucch_format1b_csA3:
    case pucch_format1b_csA4:
    {
        pucch_resource[0] = get_n1_pucch(ue,
                                         proc,
                                         ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack,
                                         eNB_id,
                                         ack_payload,
                                         SR);
        pucch_payload[0]  = ack_payload[0];
        pucch_payload[1]  = ack_payload[1];
        //pucch_payload[1]  = 1;
    }
    break;

    case pucch_format2:
    {
        pucch_resource[0]    = ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.cqi_PUCCH_ResourceIndex;
        if(cqi_report)
        {
            pucch_payload[0] = get_pucch2_cqi(ue,eNB_id,(int*)plength);
        }
        else
        {
            *plength = 1;
            pucch_payload[0] = get_pucch2_ri(ue,eNB_id);
        }
    }
    break;

    case pucch_format2a:
    case pucch_format2b:
        LOG_E(PHY,"NO Resource available for PUCCH 2a/2b \n");
    break;

    case pucch_format3:
      fprintf(stderr, "PUCCH format 3 not handled\n");
      abort();
    }
}

void ue_pucch_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t abstraction_flag) {


  uint8_t  pucch_ack_payload[2];
  uint16_t pucch_resource;
  ANFBmode_t bundling_flag;
  PUCCH_FMT_t format;

  uint8_t  SR_payload;
  uint8_t  pucch_payload[2];
  uint16_t len;

  LTE_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
  int frame_tx=proc->frame_tx;
  int subframe_tx=proc->subframe_tx;
  int Mod_id = ue->Mod_id;
  int CC_id = ue->CC_id;
  int tx_amp;
  int16_t Po_PUCCH;
  uint8_t ack_status_cw0=0;
  uint8_t ack_status_cw1=0;
  uint8_t nb_cw=0;
  uint8_t cqi_status=0;
  uint8_t ri_status=0;

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_PUCCH,VCD_FUNCTION_IN);

  SOUNDINGRS_UL_CONFIG_DEDICATED *pSoundingrs_ul_config_dedicated=&ue->soundingrs_ul_config_dedicated[eNB_id];

  // 36.213 8.2
  /*if ackNackSRS_SimultaneousTransmission ==  TRUE and in the cell specific SRS subframes UE shall transmit
    ACK/NACK and SR using the shortened PUCCH format. This shortened PUCCH format shall be used in a cell
    specific SRS subframe even if the UE does not transmit SRS in that subframe
  */

  int harq_pid = subframe2harq_pid(&ue->frame_parms,
                                   frame_tx,
                                   subframe_tx);

  if(ue->ulsch[eNB_id]->harq_processes[harq_pid]->subframe_scheduling_flag)
  {
      LOG_D(PHY,"PUSCH is programmed on this subframe [pid %d] AbsSuframe %d.%d ==> Skip PUCCH transmission \n",harq_pid,frame_tx,subframe_tx);
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_PUCCH,VCD_FUNCTION_OUT);
      return;
  }

  uint8_t isShortenPucch = (pSoundingrs_ul_config_dedicated->srsCellSubframe && frame_parms->soundingrs_ul_config_common.ackNackSRS_SimultaneousTransmission);

  bundling_flag = ue->pucch_config_dedicated[eNB_id].tdd_AckNackFeedbackMode;

  if ((frame_parms->frame_type==FDD) ||
      (bundling_flag==bundling)    ||
      ((frame_parms->frame_type==TDD)&&(frame_parms->tdd_config==1)&&((subframe_tx!=2)||(subframe_tx!=7)))) {
    format = pucch_format1a;
    //    LOG_D(PHY,"[UE] PUCCH 1a\n");
  } else {
    format = pucch_format1b;
    //    LOG_D(PHY,"[UE] PUCCH 1b\n");
  }

  // Part - I
  // Collect feedback that should be transmitted at this subframe
  // - SR
  // - ACK/NACK
  // - CQI
  // - RI

  SR_payload = 0;
  if (is_SR_TXOp(ue,proc,eNB_id)==1)
  {
      if (ue->mac_enabled==1) {
	SR_payload = ue_get_SR(Mod_id,
			       CC_id,
			       frame_tx,
			       eNB_id,
			       ue->pdcch_vars[ue->current_thread_id[proc->subframe_rx]][eNB_id]->crnti,
			       subframe_tx); // subframe used for meas gap
      }
      else {
          SR_payload = 1;
      }
  }

  ack_status_cw0 = get_ack(&ue->frame_parms,
                       ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack,
                       subframe_tx,
                       proc->subframe_rx,
                       pucch_ack_payload,
                       0);

  ack_status_cw1 = get_ack(&ue->frame_parms,
                       ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][1]->harq_ack,
                       subframe_tx,
                       proc->subframe_rx,
                       pucch_ack_payload,
                       1);

  nb_cw = ( (ack_status_cw0 != 0) ? 1:0) + ( (ack_status_cw1 != 0) ? 1:0);

  cqi_status = ((ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.cqi_PMI_ConfigIndex>0)&&
      (is_cqi_TXOp(ue,proc,eNB_id)==1));

  ri_status = ((ue->cqi_report_config[eNB_id].CQI_ReportPeriodic.ri_ConfigIndex>0) &&
           (is_ri_TXOp(ue,proc,eNB_id)==1));

  // Part - II
  // if nothing to report ==> exit function
  if( (nb_cw==0) && (SR_payload==0) && (cqi_status==0) && (ri_status==0) )
  {
      LOG_D(PHY,"PUCCH No feedback AbsSubframe %d.%d SR_payload %d nb_cw %d pucch_ack_payload[0] %d pucch_ack_payload[1] %d cqi_status %d Return \n",
            frame_tx%1024, subframe_tx, SR_payload, nb_cw, pucch_ack_payload[0], pucch_ack_payload[1], cqi_status);
      return;
  }

  // Part - III
  // Decide which PUCCH format should be used if needed
  format = get_pucch_format(frame_parms->frame_type,
                            frame_parms->Ncp,
                            SR_payload,
                            nb_cw,
                            cqi_status,
                            ri_status,
                            bundling_flag);
  // Determine PUCCH resources and payload: mandatory for pucch encoding
  get_pucch_param(ue,
                  proc,
                  pucch_ack_payload,
                  format,
                  eNB_id,
                  SR_payload,
                  cqi_status,
                  &pucch_resource,
                  (uint8_t *)&pucch_payload,
                  &len);


  LOG_I(PHY,"PUCCH feedback AbsSubframe %d.%d SR %d NbCW %d (%d %d) AckNack %d.%d CQI %d RI %d format %d pucch_resource %d pucch_payload %d %d \n",
	frame_tx%1024, subframe_tx, SR_payload, nb_cw, ack_status_cw0, ack_status_cw1, pucch_ack_payload[0], pucch_ack_payload[1], cqi_status, ri_status, format, pucch_resource,pucch_payload[0],pucch_payload[1]);

  // Part - IV
  // Generate PUCCH signal
  ue->generate_ul_signal[eNB_id] = 1;

  switch (format) {
  case pucch_format1:
  case pucch_format1a:
  case pucch_format1b:
  {
    if (ue->mac_enabled == 1) {
      Po_PUCCH = pucch_power_cntl(ue,proc,subframe_tx,eNB_id,format);
    }
    else {
      Po_PUCCH = ue->tx_power_max_dBm;
    }
    ue->tx_power_dBm[subframe_tx] = Po_PUCCH;
    ue->tx_total_RE[subframe_tx] = 12;
    
#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
    tx_amp = get_tx_amp(Po_PUCCH,
			ue->tx_power_max_dBm,
			ue->frame_parms.N_RB_UL,
			1);
#else
    tx_amp = AMP;
#endif

    T(T_UE_PHY_PUCCH_TX_POWER, T_INT(eNB_id), T_INT(frame_tx%1024), T_INT(subframe_tx),T_INT(ue->tx_power_dBm[subframe_tx]),
      T_INT(tx_amp),T_INT(ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->g_pucch),T_INT(get_PL(ue->Mod_id,ue->CC_id,eNB_id)));
    
      if(format == pucch_format1)
	{
          LOG_D(PHY,"[UE  %d][SR %x] AbsSubframe %d.%d Generating PUCCH 1 (SR for PUSCH), an_srs_simultanous %d, shorten_pucch %d, n1_pucch %d, Po_PUCCH %d\n",
		Mod_id,
		ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->rnti,
		frame_tx%1024, subframe_tx,
		frame_parms->soundingrs_ul_config_common.ackNackSRS_SimultaneousTransmission,
		isShortenPucch,
		ue->scheduling_request_config[eNB_id].sr_PUCCH_ResourceIndex,
		Po_PUCCH);
      }
      else
      {
          if (SR_payload>0) {
              LOG_D(PHY,"[UE  %d][SR %x] AbsSubFrame %d.%d Generating PUCCH %s payload %d,%d (with SR for PUSCH), an_srs_simultanous %d, shorten_pucch %d, n1_pucch %d, Po_PUCCH %d, amp %d\n",
                      Mod_id,
                      ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->rnti,
                      frame_tx % 1024, subframe_tx,
                      (format == pucch_format1a? "1a": (
                              format == pucch_format1b? "1b" : "??")),
                              pucch_ack_payload[0],pucch_ack_payload[1],
                              frame_parms->soundingrs_ul_config_common.ackNackSRS_SimultaneousTransmission,
                              isShortenPucch,
                              pucch_resource,
                              Po_PUCCH,
                              tx_amp);
          } else {
              LOG_D(PHY,"[UE  %d][PDSCH %x] AbsSubFrame %d.%d rx_offset_diff: %d, Generating PUCCH %s, an_srs_simultanous %d, shorten_pucch %d, n1_pucch %d, b[0]=%d,b[1]=%d (SR_Payload %d), Po_PUCCH %d, amp %d\n",
                      Mod_id,
                      ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->rnti,
                      frame_tx%1024, subframe_tx,ue->rx_offset_diff,
                      (format == pucch_format1a? "1a": (
                              format == pucch_format1b? "1b" : "??")),
                              frame_parms->soundingrs_ul_config_common.ackNackSRS_SimultaneousTransmission,
                              isShortenPucch,
                              pucch_resource,pucch_payload[0],pucch_payload[1],SR_payload,
                              Po_PUCCH,
                              tx_amp);
          }
      }


LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
      if(pucch_payload[0])
      {
          T(T_UE_PHY_DLSCH_UE_ACK, T_INT(eNB_id), T_INT(frame_tx%1024), T_INT(subframe_tx), T_INT(ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->rnti),
                  T_INT(ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->current_harq_pid));
      }
      else
      {
          T(T_UE_PHY_DLSCH_UE_NACK, T_INT(eNB_id), T_INT(frame_tx%1024), T_INT(subframe_tx), T_INT(ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->rnti),
                  T_INT(ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->current_harq_pid));
      }
LOG_DEBUG_END

      generate_pucch1x(ue->common_vars.txdataF,
		       &ue->frame_parms,
		       ue->ncs_cell,
		       format,
		       &ue->pucch_config_dedicated[eNB_id],
		       pucch_resource,
		       isShortenPucch,  // shortened format
		       pucch_payload,
		       tx_amp,
		       subframe_tx);
      
  }
  break;


  case pucch_format2:
  {
      if (ue->mac_enabled == 1) {
          Po_PUCCH = pucch_power_cntl(ue,proc,subframe_tx,eNB_id,format);
      }
      else {
          Po_PUCCH = ue->tx_power_max_dBm;
      }
      ue->tx_power_dBm[subframe_tx] = Po_PUCCH;
      ue->tx_total_RE[subframe_tx] = 12;

#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
      tx_amp =  get_tx_amp(Po_PUCCH,
              ue->tx_power_max_dBm,
              ue->frame_parms.N_RB_UL,
              1);
#else
      tx_amp = AMP;
#endif
      T(T_UE_PHY_PUCCH_TX_POWER, T_INT(eNB_id), T_INT(frame_tx%1024), T_INT(subframe_tx),T_INT(ue->tx_power_dBm[subframe_tx]),
              T_INT(tx_amp),T_INT(ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->g_pucch),T_INT(get_PL(ue->Mod_id,ue->CC_id,eNB_id)));
LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
      LOG_D(PHY,"[UE  %d][RNTI %x] AbsSubFrame %d.%d Generating PUCCH 2 (RI or CQI), Po_PUCCH %d, isShortenPucch %d, amp %d\n",
              Mod_id,
              ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->rnti,
              frame_tx%1024, subframe_tx,
              Po_PUCCH,
              isShortenPucch,
              tx_amp);
LOG_DEBUG_END
      generate_pucch2x(ue->common_vars.txdataF,
              &ue->frame_parms,
              ue->ncs_cell,
              format,
              &ue->pucch_config_dedicated[eNB_id],
              pucch_resource,
              pucch_payload,
              len,          // A
              0,            // B2 not needed
              tx_amp,
              subframe_tx,
              ue->pdcch_vars[ue->current_thread_id[proc->subframe_rx]][eNB_id]->crnti);
  }
  break;

  case pucch_format2a:
      LOG_D(PHY,"[UE  %d][RNTI %x] AbsSubFrame %d.%d Generating PUCCH 2a (RI or CQI) Ack/Nack 1bit \n",
              Mod_id,
              ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->rnti,
              frame_tx%1024, subframe_tx);
      break;
  case pucch_format2b:
      LOG_D(PHY,"[UE  %d][RNTI %x] AbsSubFrame %d.%d Generating PUCCH 2b (RI or CQI) Ack/Nack 2bits\n",
              Mod_id,
              ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->rnti,
              frame_tx%1024, subframe_tx);
      break;
  default:
      break;
  }

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_PUCCH,VCD_FUNCTION_OUT);

}

void phy_procedures_UE_SL_TX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc) {

  int subframe_tx = proc->subframe_tx;
  int frame_tx = proc->frame_tx;
  SLSS_t *slss;
  SLDCH_t *sldch;
  SLSCH_t *slsch;

  LOG_D(PHY,"****** start Sidelink TX-Chain for AbsSubframe %d.%d ******\n", frame_tx, subframe_tx);

  // check for SLBCH/SLSS
  if ((slss = ue_get_slss(ue->Mod_id,ue->CC_id,frame_tx,subframe_tx)) != NULL) generate_slss(ue,slss,frame_tx,subframe_tx);

  // check for SLDCH
  if ((sldch = ue_get_sldch(ue->Mod_id,ue->CC_id,frame_tx,subframe_tx)) != NULL) generate_sldch(ue,sldch,frame_tx,subframe_tx);

  // check for SLSCH
  if ((slsch = ue_get_slsch(ue->Mod_id,ue->CC_id,frame_tx,subframe_tx)) != NULL) generate_slsch(ue,slsch,frame_tx,subframe_tx);

}

void phy_procedures_UE_TX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t abstraction_flag,runmode_t mode) {


  LTE_DL_FRAME_PARMS *frame_parms=&ue->frame_parms;
  //int32_t ulsch_start=0;
  int subframe_tx = proc->subframe_tx;
  int frame_tx = proc->frame_tx;
  unsigned int aa;
  uint8_t isSubframeSRS;

  uint8_t next1_thread_id = ue->current_thread_id[proc->subframe_rx]== (RX_NB_TH-1) ? 0:(ue->current_thread_id[proc->subframe_rx]+1);
  uint8_t next2_thread_id = next1_thread_id== (RX_NB_TH-1) ? 0:(next1_thread_id+1);

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX,VCD_FUNCTION_IN);

  LOG_D(PHY,"****** start TX-Chain for AbsSubframe %d.%d ******\n", frame_tx, subframe_tx);

  T(T_UE_PHY_UL_TICK, T_INT(ue->Mod_id), T_INT(frame_tx%1024), T_INT(subframe_tx));


  ue->generate_ul_signal[eNB_id] = 0;
LOG_DEBUG_BEGIN(UE_TIMING)
  start_meas(&ue->phy_proc_tx);
LOG_DEBUG_END

  ue->tx_power_dBm[subframe_tx]=-127;

      
  for (aa=0; aa<frame_parms->nb_antennas_tx; aa++) {
    memset(&ue->common_vars.txdataF[aa][subframe_tx*frame_parms->ofdm_symbol_size*frame_parms->symbols_per_tti],
	   0,
	   frame_parms->ofdm_symbol_size*frame_parms->symbols_per_tti*sizeof(int32_t));
  }
  
  if (subframe_select(&ue->frame_parms,proc->subframe_tx) == SF_UL ||
      ue->frame_parms.frame_type == FDD) {    
    if (ue->UE_mode[eNB_id] != PRACH ) {
      // check cell srs subframe and ue srs subframe. This has an impact on pusch encoding
      isSubframeSRS = is_srs_occasion_common(&ue->frame_parms,proc->frame_tx,proc->subframe_tx);
      
      ue_compute_srs_occasion(ue,proc,eNB_id,isSubframeSRS);
      
      ue_ulsch_uespec_procedures(ue,proc,eNB_id,abstraction_flag);
      
      LOG_D(PHY,"ULPOWERS After ulsch_uespec_procedures : ue->tx_power_dBm[%d]=%d, NPRB %d\n",
	    subframe_tx,ue->tx_power_dBm[subframe_tx],ue->tx_total_RE[subframe_tx]);
    }
    
    if (ue->UE_mode[eNB_id] == PUSCH) {
      // check if we need to use PUCCH 1a/1b
      ue_pucch_procedures(ue,proc,eNB_id,abstraction_flag);
      // check if we need to use SRS
      ue_srs_procedures(ue,proc,eNB_id,abstraction_flag);
    } // UE_mode==PUSCH

  }
  	

  LOG_D(PHY,"doing ulsch_common_procedures (%d.%d): generate_ul_signal %d\n",frame_tx,subframe_tx,
	ue->generate_ul_signal[eNB_id]);	
  ulsch_common_procedures(ue,proc, (ue->generate_ul_signal[eNB_id] == 0));
        
  if ((ue->UE_mode[eNB_id] == PRACH) && 
      (ue->frame_parms.prach_config_common.prach_Config_enabled==1)) {

    // check if we have PRACH opportunity

    if (is_prach_subframe(&ue->frame_parms,frame_tx,subframe_tx)) {

      ue_prach_procedures(ue,proc,eNB_id,abstraction_flag,mode);
    }
  } // mode is PRACH
  else {
    ue->generate_prach=0;
  }

  // reset DL ACK/NACK status
  uint8_t N_bundled = 0;
  if (ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0] != NULL)
  {
    reset_ack(&ue->frame_parms,
               ue->dlsch[ue->current_thread_id[proc->subframe_rx]][eNB_id][0]->harq_ack,
               subframe_tx,
               proc->subframe_rx,
               ue->ulsch[eNB_id]->o_ACK,
               &N_bundled,
               0);
    reset_ack(&ue->frame_parms,
               ue->dlsch[next1_thread_id][eNB_id][0]->harq_ack,
               subframe_tx,
               proc->subframe_rx,
               ue->ulsch[eNB_id]->o_ACK,
               &N_bundled,
               0);
    reset_ack(&ue->frame_parms,
               ue->dlsch[next2_thread_id][eNB_id][0]->harq_ack,
               subframe_tx,
               proc->subframe_rx,
               ue->ulsch[eNB_id]->o_ACK,
               &N_bundled,
               0);
  }

  if (ue->dlsch_SI[eNB_id] != NULL)
    reset_ack(&ue->frame_parms,
             ue->dlsch_SI[eNB_id]->harq_ack,
             subframe_tx,
             proc->subframe_rx,
             ue->ulsch[eNB_id]->o_ACK,
             &N_bundled,
             0);


  LOG_D(PHY,"****** end TX-Chain for AbsSubframe %d.%d ******\n", frame_tx, subframe_tx);

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX, VCD_FUNCTION_OUT);
LOG_DEBUG_BEGIN(UE_TIMING)
  stop_meas(&ue->phy_proc_tx);
LOG_DEBUG_END
}

void phy_procedures_UE_S_TX(PHY_VARS_UE *ue,uint8_t eNB_id,uint8_t abstraction_flag)
{
  int aa;//i,aa;
  LTE_DL_FRAME_PARMS *frame_parms=&ue->frame_parms;

  
  for (aa=0; aa<frame_parms->nb_antennas_tx; aa++) {
#if defined(EXMIMO) //this is the EXPRESS MIMO case
    int i;
    // set the whole tx buffer to RX
    for (i=0; i<LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*frame_parms->samples_per_tti; i++)
      ue->common_vars.txdata[aa][i] = 0x00010001;
    
#else //this is the normal case
    //    memset(&ue->common_vars.txdata[aa][0],0,
    //	   (LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*frame_parms->samples_per_tti)*sizeof(int32_t));
#endif //else EXMIMO
    
  }
  
}

void ue_measurement_procedures(
    uint16_t l,    // symbol index of each slot [0..6]
    PHY_VARS_UE *ue,UE_rxtx_proc_t *proc, uint8_t eNB_id,
    uint16_t slot, // slot index of each radio frame [0..19]
    uint8_t abstraction_flag,runmode_t mode)
{

  //LOG_I(PHY,"ue_measurement_procedures l %d Ncp %d\n",l,ue->frame_parms.Ncp);

  LTE_DL_FRAME_PARMS *frame_parms=&ue->frame_parms;

  int subframe_rx = proc->subframe_rx;

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_MEASUREMENT_PROCEDURES, VCD_FUNCTION_IN);

  if (l==0) {
    // UE measurements on symbol 0

    LOG_D(PHY,"Calling measurements subframe %d, rxdata %p\n",subframe_rx,ue->common_vars.rxdata);
      LOG_D(PHY,"Calling measurements subframe %d, rxdata %p\n",subframe_rx,ue->common_vars.rxdata);

      lte_ue_measurements(ue,
			  (subframe_rx*frame_parms->samples_per_tti+ue->rx_offset)%(frame_parms->samples_per_tti*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME),
			  (subframe_rx == 1) ? 1 : 0,
			  0,
			  0,
			  subframe_rx);
      

      if(slot == 0)
	T(T_UE_PHY_MEAS, T_INT(eNB_id), T_INT(proc->frame_rx%1024), T_INT(proc->subframe_rx),
	  T_INT((int)(10*log10(ue->measurements.rsrp[0])-ue->rx_total_gain_dB)),
	  T_INT((int)ue->measurements.rx_rssi_dBm[0]),
	  T_INT((int)(ue->measurements.rx_power_avg_dB[0] - ue->measurements.n0_power_avg_dB)),
	  T_INT((int)ue->measurements.rx_power_avg_dB[0]),
	  T_INT((int)ue->measurements.n0_power_avg_dB),
	  T_INT((int)ue->measurements.wideband_cqi_avg[0]),
	  T_INT((int)ue->common_vars.freq_offset));
  }

  if (l==(6-ue->frame_parms.Ncp)) {

    // make sure we have signal from PSS/SSS for N0 measurement
         // LOG_I(PHY," l==(6-ue->frame_parms.Ncp) ue_rrc_measurements\n");

    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_RRC_MEASUREMENTS, VCD_FUNCTION_IN);
    ue_rrc_measurements(ue,
      slot,
      abstraction_flag);
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_RRC_MEASUREMENTS, VCD_FUNCTION_OUT);

  }

  // accumulate and filter timing offset estimation every subframe (instead of every frame)
  if (( (slot%2) == 0) && (l==(4-frame_parms->Ncp))) {

    // AGC

    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GAIN_CONTROL, VCD_FUNCTION_IN);

#ifndef OAI_USRP
#ifndef OAI_BLADERF
#ifndef OAI_LMSSDR
    phy_adjust_gain (ue,dB_fixed(ue->measurements.rssi),0);
#endif
#endif
#endif

    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GAIN_CONTROL, VCD_FUNCTION_OUT);

    eNB_id = 0;

    
    if (ue->no_timing_correction==0)
      lte_adjust_synch(&ue->frame_parms,
		       ue,
		       eNB_id,
		       subframe_rx,
		       0,
		       16384);
 
  }

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_MEASUREMENT_PROCEDURES, VCD_FUNCTION_OUT);
}



void ue_pbch_procedures(uint8_t eNB_id,PHY_VARS_UE *ue,UE_rxtx_proc_t *proc, uint8_t abstraction_flag)
{

  //  int i;
  int pbch_tx_ant=0;
  uint8_t pbch_phase;
  uint16_t frame_tx;
  static uint8_t first_run = 1;
  uint8_t pbch_trials = 0;

  DevAssert(ue);

  int frame_rx = proc->frame_rx;
  int subframe_rx = proc->subframe_rx;

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PBCH_PROCEDURES, VCD_FUNCTION_IN);

  pbch_phase=(frame_rx%4);

  if (pbch_phase>=4)
    pbch_phase=0;

  for (pbch_trials=0; pbch_trials<4; pbch_trials++) {
    //for (pbch_phase=0;pbch_phase<4;pbch_phase++) {
    //LOG_I(PHY,"[UE  %d] Frame %d, Trying PBCH %d (NidCell %d, eNB_id %d)\n",ue->Mod_id,frame_rx,pbch_phase,ue->frame_parms.Nid_cell,eNB_id);

    pbch_tx_ant = rx_pbch(&ue->common_vars,
			  ue->pbch_vars[eNB_id],
			  &ue->frame_parms,
			  eNB_id,
			  ue->frame_parms.nb_antenna_ports_eNB==1?SISO:ALAMOUTI,
			  ue->high_speed_flag,
			  pbch_phase);
    
    if ((pbch_tx_ant>0) && (pbch_tx_ant<=4)) {
      break;
    }

    pbch_phase++;

    if (pbch_phase>=4)
      pbch_phase=0;
  }



  if ((pbch_tx_ant>0) && (pbch_tx_ant<=4)) {

    if (opt_enabled) {
      static uint8_t dummy[3];
      dummy[0] = ue->pbch_vars[eNB_id]->decoded_output[2];
      dummy[1] = ue->pbch_vars[eNB_id]->decoded_output[1];
      dummy[2] = ue->pbch_vars[eNB_id]->decoded_output[0];
      trace_pdu(1, dummy, 3, ue->Mod_id, 0, 0,
          frame_rx, subframe_rx, 0, 0);
      LOG_D(OPT,"[UE %d][PBCH] Frame %d trace pdu for PBCH\n",
          ue->Mod_id, subframe_rx);
    }

    if (pbch_tx_ant>2) {
      LOG_W(PHY,"[openair][SCHED][SYNCH] PBCH decoding: pbch_tx_ant>2 not supported\n");
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PBCH_PROCEDURES, VCD_FUNCTION_OUT);
      return;
    }


    ue->pbch_vars[eNB_id]->pdu_errors_conseq = 0;
    frame_tx = (((int)(ue->pbch_vars[eNB_id]->decoded_output[2]&0x03))<<8);
    frame_tx += ((int)(ue->pbch_vars[eNB_id]->decoded_output[1]&0xfc));
    frame_tx += pbch_phase;

    if (ue->mac_enabled==1) {

      dl_phy_sync_success(ue->Mod_id,frame_rx,eNB_id,
			  ue->UE_mode[eNB_id]==NOT_SYNCHED ? 1 : 0);
    }

    // if this is the first PBCH after initial synchronization, make L1 state = PRACH
    if (ue->UE_mode[eNB_id]==NOT_SYNCHED) ue->UE_mode[eNB_id] = PRACH;

    if (first_run) {
      first_run = 0;

      proc->frame_rx = (proc->frame_rx & 0xFFFFFC00) | (frame_tx & 0x000003FF);
      proc->frame_tx = proc->frame_rx;

      for(int th_id=0; th_id<RX_NB_TH; th_id++)
      {
        ue->proc.proc_rxtx[th_id].frame_rx = proc->frame_rx;
        ue->proc.proc_rxtx[th_id].frame_tx = proc->frame_tx;

        printf("[UE %d] frame %d, subframe %d: Adjusting frame counter (PBCH ant_tx=%d, frame_tx=%d, phase %d, rx_offset %d) => new frame %d\n",
 	    ue->Mod_id,
 	    ue->proc.proc_rxtx[th_id].frame_rx,
 	    subframe_rx,
 	    pbch_tx_ant,
 	    frame_tx,
 	    pbch_phase,
 	    ue->rx_offset,
 	    proc->frame_rx);
      }


      frame_rx = proc->frame_rx;

    } else if (((frame_tx & 0x03FF) != (proc->frame_rx & 0x03FF))) {
      //(pbch_tx_ant != ue->frame_parms.nb_antennas_tx)) {
      LOG_D(PHY,"[UE %d] frame %d, subframe %d: Re-adjusting frame counter (PBCH ant_tx=%d, frame_rx=%d, frame%%1024=%d, phase %d).\n",
      ue->Mod_id,
      proc->frame_rx,
      subframe_rx,
      pbch_tx_ant,
      frame_tx,
      frame_rx & 0x03FF,
      pbch_phase);


      proc->frame_rx = (proc->frame_rx & 0xFFFFFC00) | (frame_tx & 0x000003FF);
      proc->frame_tx = proc->frame_rx;
      frame_rx = proc->frame_rx;
      
      for(int th_id=0; th_id<RX_NB_TH; th_id++)
      {
        ue->proc.proc_rxtx[th_id].frame_rx = (proc->frame_rx & 0xFFFFFC00) | (frame_tx & 0x000003FF);
        ue->proc.proc_rxtx[th_id].frame_tx = proc->frame_rx;
      }

    }

LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)

    LOG_UI(PHY,"[UE %d] frame %d, subframe %d, Received PBCH (MIB): nb_antenna_ports_eNB %d, tx_ant %d, frame_tx %d. N_RB_DL %d, phich_duration %d, phich_resource %d/6!\n",
	  ue->Mod_id,
	  frame_rx,
	  subframe_rx,
	  ue->frame_parms.nb_antenna_ports_eNB,
	  pbch_tx_ant,
	  frame_tx,
	  ue->frame_parms.N_RB_DL,
	  ue->frame_parms.phich_config_common.phich_duration,
	  ue->frame_parms.phich_config_common.phich_resource);
LOG_DEBUG_END

  } else { 

    /*
    LOG_E(PHY,"[UE %d] frame %d, subframe %d, Error decoding PBCH!\n",
    ue->Mod_id,frame_rx, subframe_rx);

    LOG_I(PHY,"[UE %d] rx_offset %d\n",ue->Mod_id,ue->rx_offset);


    LOG_M("rxsig0.m","rxs0", ue->common_vars.rxdata[0],ue->frame_parms.samples_per_tti,1,1);

    LOG_M("H00.m","h00",&(ue->common_vars.dl_ch_estimates[0][0][0]),((ue->frame_parms.Ncp==0)?7:6)*(ue->frame_parms.ofdm_symbol_size),1,1);
    LOG_M("H10.m","h10",&(ue->common_vars.dl_ch_estimates[0][2][0]),((ue->frame_parms.Ncp==0)?7:6)*(ue->frame_parms.ofdm_symbol_size),1,1);

    LOG_M("rxsigF0.m","rxsF0", ue->common_vars.rxdataF[0],8*ue->frame_parms.ofdm_symbol_size,1,1);
    LOG_M("PBCH_rxF0_ext.m","pbch0_ext",ue->pbch_vars[0]->rxdataF_ext[0],12*4*6,1,1);
    LOG_M("PBCH_rxF0_comp.m","pbch0_comp",ue->pbch_vars[0]->rxdataF_comp[0],12*4*6,1,1);
    LOG_M("PBCH_rxF_llr.m","pbch_llr",ue->pbch_vars[0]->llr,(ue->frame_parms.Ncp==0) ? 1920 : 1728,1,4);
    exit(-1);
    */

    ue->pbch_vars[eNB_id]->pdu_errors_conseq++;
    ue->pbch_vars[eNB_id]->pdu_errors++;

    if (ue->mac_enabled == 1) rrc_out_of_sync_ind(ue->Mod_id,frame_rx,eNB_id);
    else AssertFatal(ue->pbch_vars[eNB_id]->pdu_errors_conseq<100,
		     "More that 100 consecutive PBCH errors! Exiting!\n");
  }
  

  if (frame_rx % 100 == 0) {
    ue->pbch_vars[eNB_id]->pdu_fer = ue->pbch_vars[eNB_id]->pdu_errors - ue->pbch_vars[eNB_id]->pdu_errors_last;
    ue->pbch_vars[eNB_id]->pdu_errors_last = ue->pbch_vars[eNB_id]->pdu_errors;
  }

LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
  LOG_UI(PHY,"[UE %d] frame %d, slot %d, PBCH errors = %d, consecutive errors = %d!\n",
  ue->Mod_id,frame_rx, subframe_rx,
  ue->pbch_vars[eNB_id]->pdu_errors,
  ue->pbch_vars[eNB_id]->pdu_errors_conseq);
LOG_DEBUG_END
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PBCH_PROCEDURES, VCD_FUNCTION_OUT);
}



int ue_pdcch_procedures(uint8_t eNB_id,PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t abstraction_flag)
{

  unsigned int dci_cnt=0, i;

  int frame_rx = proc->frame_rx;
  int subframe_rx = proc->subframe_rx;
  DCI_ALLOC_t dci_alloc_rx[8];

  uint8_t next1_thread_id = ue->current_thread_id[subframe_rx]== (RX_NB_TH-1) ? 0:(ue->current_thread_id[subframe_rx]+1);
  uint8_t next2_thread_id = next1_thread_id== (RX_NB_TH-1) ? 0:(next1_thread_id+1);

  LOG_D(PHY,"DCI Decoding procedure in %d.%d\n",frame_rx,subframe_rx);
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PDCCH_PROCEDURES, VCD_FUNCTION_IN);
LOG_DEBUG_BEGIN(UE_TIMING)
  start_meas(&ue->dlsch_rx_pdcch_stats);
LOG_DEBUG_END

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RX_PDCCH, VCD_FUNCTION_IN);
  rx_pdcch(ue,
	   proc->frame_rx,
	   subframe_rx,
	   eNB_id,
	   ue->frame_parms.nb_antenna_ports_eNB==1?SISO:ALAMOUTI,
	   ue->high_speed_flag);
  
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RX_PDCCH, VCD_FUNCTION_OUT);
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DCI_DECODING, VCD_FUNCTION_IN);
  
  
  /*printf("Decode SIB frame param aggregation + DCI %d %d, num_pdcch_symbols %d\n",
	 ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->agregationLevel,
	 ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->dciFormat,
	 ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->num_pdcch_symbols);
  */
  //agregation level == FF means no configuration on
  if(ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->agregationLevel == 0xFF || ue->decode_SIB)
    {
      // search all possible dcis
      dci_cnt = dci_decoding_procedure(ue,
				       dci_alloc_rx,
				       (ue->UE_mode[eNB_id] < PUSCH)? 1 : 0,  // if we're in PUSCH don't listen to common search space,
				       // later when we need paging or RA during connection, update this ...
				       eNB_id,subframe_rx);
    }
  else
    {
      // search only preconfigured dcis
      // search C RNTI dci
      dci_cnt = dci_CRNTI_decoding_procedure(ue,
					     dci_alloc_rx,
					     ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->dciFormat,
					     ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->agregationLevel,
					     eNB_id,
					     subframe_rx);
    }
  
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_DCI_DECODING, VCD_FUNCTION_OUT);
  //LOG_D(PHY,"[UE  %d][PUSCH] Frame %d subframe %d PHICH RX\n",ue->Mod_id,frame_rx,subframe_rx);
  
  if (is_phich_subframe(&ue->frame_parms,subframe_rx)) {
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RX_PHICH, VCD_FUNCTION_IN);
    rx_phich(ue,proc,
	     subframe_rx,eNB_id);
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RX_PHICH, VCD_FUNCTION_OUT);
  }
  
  uint8_t *nCCE_current = &ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->nCCE[subframe_rx];
  uint8_t *nCCE_dest = &ue->pdcch_vars[next1_thread_id][eNB_id]->nCCE[subframe_rx];
  uint8_t *nCCE_dest1 = &ue->pdcch_vars[next2_thread_id][eNB_id]->nCCE[subframe_rx];
  memcpy(nCCE_dest, nCCE_current, sizeof(uint8_t));
  memcpy(nCCE_dest1, nCCE_current, sizeof(uint8_t));

  LOG_D(PHY,"current_thread %d next1_thread %d next2_thread %d \n", ue->current_thread_id[subframe_rx], next1_thread_id, next2_thread_id);

  LOG_D(PHY,"[UE  %d] AbsSubFrame %d.%d, Mode %s: DCI found %i --> rnti %x / crnti %x : format %d\n",
       ue->Mod_id,frame_rx%1024,subframe_rx,mode_string[ue->UE_mode[eNB_id]],
       dci_cnt,
       dci_alloc_rx[0].rnti,
       ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->crnti,
       dci_alloc_rx[0].format );

  ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->dci_received += dci_cnt;

  for (i=0; i<dci_cnt; i++) {



    if ((ue->UE_mode[eNB_id]>PRACH) &&
	(dci_alloc_rx[i].rnti == ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->crnti) &&
	(dci_alloc_rx[i].format != format0)) {
      
      LOG_D(PHY,"[UE  %d][DCI][PDSCH %x] AbsSubframe %d.%d: format %d, num_pdcch_symbols %d, nCCE %d, total CCEs %d\n",
	    ue->Mod_id,dci_alloc_rx[i].rnti,
	    frame_rx%1024,subframe_rx,
	    dci_alloc_rx[i].format,
	    ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->num_pdcch_symbols,
	    ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->nCCE[subframe_rx],
	    get_nCCE(3,&ue->frame_parms,get_mi(&ue->frame_parms,0)));
      
      //dump_dci(&ue->frame_parms, &dci_alloc_rx[i]);
      
      if ((ue->UE_mode[eNB_id] > PRACH) &&
	  (generate_ue_dlsch_params_from_dci(frame_rx,
					     subframe_rx,
					     (void *)&dci_alloc_rx[i].dci_pdu,
					     ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->crnti,
					     dci_alloc_rx[i].format,
					     ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id],
					     ue->pdsch_vars[ue->current_thread_id[subframe_rx]][eNB_id],
					     ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id],
					     &ue->frame_parms,
					     ue->pdsch_config_dedicated,
					     SI_RNTI,
					     0,
					     P_RNTI,
					     ue->transmission_mode[eNB_id]<7?0:ue->transmission_mode[eNB_id],
					     ue->pdcch_vars[0%RX_NB_TH][eNB_id]->crnti_is_temporary? ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->crnti: 0)==0)) {
	
	// update TPC for PUCCH
	if((dci_alloc_rx[i].format == format1)   ||
	   (dci_alloc_rx[i].format == format1A) ||
	   (dci_alloc_rx[i].format == format1B) ||
	   (dci_alloc_rx[i].format == format2)  ||
	   (dci_alloc_rx[i].format == format2A) ||
	   (dci_alloc_rx[i].format == format2B))
          {
            //ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0]->g_pucch += ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0]->harq_processes[ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0]->current_harq_pid]->delta_PUCCH;
            int32_t delta_pucch = ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0]->harq_processes[ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0]->current_harq_pid]->delta_PUCCH;
            for(int th_id=0; th_id<RX_NB_TH; th_id++)
	      {
                ue->dlsch[th_id][eNB_id][0]->g_pucch += delta_pucch;
	      }
            LOG_D(PHY,"update TPC for PUCCH %d.%d / pid %d delta_PUCCH %d g_pucch %d %d \n",frame_rx, subframe_rx,ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0]->current_harq_pid,
		  delta_pucch,
		  ue->dlsch[0][eNB_id][0]->g_pucch,
		  ue->dlsch[1][eNB_id][0]->g_pucch
		  //ue->dlsch[2][eNB_id][0]->g_pucch
		  );
          }
	
	ue->dlsch_received[eNB_id]++;
	
LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
	LOG_D(PHY,"[UE  %d] Generated UE DLSCH C_RNTI format %d\n",ue->Mod_id,dci_alloc_rx[i].format);
	dump_dci(&ue->frame_parms, &dci_alloc_rx[i]);
	LOG_D(PHY,"[UE %d] *********** dlsch->active in subframe %d=> %d\n",ue->Mod_id,subframe_rx,ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0]->active);
LOG_DEBUG_END
	
	// we received a CRNTI, so we're in PUSCH
	if (ue->UE_mode[eNB_id] != PUSCH) {
LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
	  LOG_D(PHY,"[UE  %d] Frame %d, subframe %d: Received DCI with CRNTI %x => Mode PUSCH\n",ue->Mod_id,frame_rx,subframe_rx,ue->pdcch_vars[subframe_rx&1][eNB_id]->crnti);
LOG_DEBUG_END
	  
	  //dump_dci(&ue->frame_parms, &dci_alloc_rx[i]);
	  ue->UE_mode[eNB_id] = PUSCH;
	}
      } else {
	  LOG_E(PHY,"[UE  %d] Frame %d, subframe %d: Problem in DCI!\n",ue->Mod_id,frame_rx,subframe_rx);
	  dump_dci(&ue->frame_parms, &dci_alloc_rx[i]);
	}
    }
      
      else if ((dci_alloc_rx[i].rnti == SI_RNTI) &&
	       ((dci_alloc_rx[i].format == format1A) || (dci_alloc_rx[i].format == format1C))) {


LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
	LOG_D(PHY,"[UE  %d] subframe %d: Found rnti %x, format 1%s, dci_cnt %d\n",ue->Mod_id,subframe_rx,dci_alloc_rx[i].rnti,dci_alloc_rx[i].format==format1A?"A":"C",i);
LOG_DEBUG_END
	
	if (generate_ue_dlsch_params_from_dci(frame_rx,
					      subframe_rx,
					      (void *)&dci_alloc_rx[i].dci_pdu,
					      SI_RNTI,
					      dci_alloc_rx[i].format,
					      ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id],
					      ue->pdsch_vars_SI[eNB_id],
					      &ue->dlsch_SI[eNB_id],
					      &ue->frame_parms,
					      ue->pdsch_config_dedicated,
					      SI_RNTI,
					      0,
					      P_RNTI,
					      ue->transmission_mode[eNB_id]<7?0:ue->transmission_mode[eNB_id],
					      0)==0) {
	  
	  ue->dlsch_SI_received[eNB_id]++;
	  
	  LOG_D(PHY,"[UE  %d] Frame %d, subframe %d : Generate UE DLSCH SI_RNTI format 1%s\n",ue->Mod_id,frame_rx,subframe_rx,dci_alloc_rx[i].format==format1A?"A":"C");
	  //dump_dci(&ue->frame_parms, &dci_alloc_rx[i]);
	
	}
      }

    else if ((dci_alloc_rx[i].rnti == P_RNTI) &&
       ((dci_alloc_rx[i].format == format1A) || (dci_alloc_rx[i].format == format1C))) {

LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
      LOG_D(PHY,"[UE  %d] subframe %d: Found rnti %x, format 1%s, dci_cnt %d\n",ue->Mod_id,subframe_rx,dci_alloc_rx[i].rnti,dci_alloc_rx[i].format==format1A?"A":"C",i);
LOG_DEBUG_END


      if (generate_ue_dlsch_params_from_dci(frame_rx,
					    subframe_rx,
					    (void *)&dci_alloc_rx[i].dci_pdu,
					    P_RNTI,
					    dci_alloc_rx[i].format,
					    ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id],
					    ue->pdsch_vars_p[eNB_id],
					    &ue->dlsch_SI[eNB_id],
					    &ue->frame_parms,
					    ue->pdsch_config_dedicated,
					    SI_RNTI,
					    0,
					    P_RNTI,
					    ue->transmission_mode[eNB_id]<7?0:ue->transmission_mode[eNB_id],
                                            0)==0) {

	ue->dlsch_p_received[eNB_id]++;
	LOG_D(PHY,"[UE  %d] Frame %d, subframe %d : Generate UE DLSCH P_RNTI format 1%s\n",ue->Mod_id,frame_rx,subframe_rx,dci_alloc_rx[i].format==format1A?"A":"C");
	//dump_dci(&ue->frame_parms, &dci_alloc_rx[i]);
	
      }
    }

    else if ((ue->prach_resources[eNB_id]) &&
       (dci_alloc_rx[i].rnti == ue->prach_resources[eNB_id]->ra_RNTI) &&
       (dci_alloc_rx[i].format == format1A)) {

LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
      LOG_D(PHY,"[UE  %d][RAPROC] subframe %d: Found RA rnti %x, format 1A, dci_cnt %d\n",ue->Mod_id,subframe_rx,dci_alloc_rx[i].rnti,i);
LOG_DEBUG_END


      if (generate_ue_dlsch_params_from_dci(frame_rx,
					    subframe_rx,
					    (DCI1A_5MHz_TDD_1_6_t *)&dci_alloc_rx[i].dci_pdu,
					    ue->prach_resources[eNB_id]->ra_RNTI,
					    format1A,
					    ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id],
					    ue->pdsch_vars_ra[eNB_id],
					    &ue->dlsch_ra[eNB_id],
					    &ue->frame_parms,
					    ue->pdsch_config_dedicated,
					    SI_RNTI,
					    ue->prach_resources[eNB_id]->ra_RNTI,
					    P_RNTI,
					    ue->transmission_mode[eNB_id]<7?0:ue->transmission_mode[eNB_id],
                                            0)==0) {
	
  ue->dlsch_ra_received[eNB_id]++;

LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
  LOG_D(PHY,"[UE  %d] Generate UE DLSCH RA_RNTI format 1A, rb_alloc %x, dlsch_ra[eNB_id] %p\n",
        ue->Mod_id,ue->dlsch_ra[eNB_id]->harq_processes[0]->rb_alloc_even[0],ue->dlsch_ra[eNB_id]);
LOG_DEBUG_END
      }
    } else if( (dci_alloc_rx[i].rnti == ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->crnti) &&
	       (dci_alloc_rx[i].format == format0)) {

LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
      LOG_D(PHY,"[UE  %d][PUSCH] Frame %d subframe %d: Found rnti %x, format 0, dci_cnt %d\n",
      ue->Mod_id,frame_rx,subframe_rx,dci_alloc_rx[i].rnti,i);
LOG_DEBUG_END

      ue->ulsch_no_allocation_counter[eNB_id] = 0;
      //dump_dci(&ue->frame_parms,&dci_alloc_rx[i]);
      
      if ((ue->UE_mode[eNB_id] > PRACH) &&
	  (generate_ue_ulsch_params_from_dci((void *)&dci_alloc_rx[i].dci_pdu,
					     ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->crnti,
					     subframe_rx,
					     format0,
					     ue,
					     proc,
					     SI_RNTI,
					     0,
					     P_RNTI,
					     CBA_RNTI,
					     eNB_id,
					     0)==0)) {
LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
   
    LOG_USEDINLOG_VAR(int8_t,harq_pid) = subframe2harq_pid(&ue->frame_parms,
                              pdcch_alloc2ul_frame(&ue->frame_parms,proc->frame_rx,proc->subframe_rx),
                              pdcch_alloc2ul_subframe(&ue->frame_parms,proc->subframe_rx));
    T(T_UE_PHY_ULSCH_UE_DCI, T_INT(eNB_id), T_INT(proc->frame_rx%1024), T_INT(proc->subframe_rx),
      T_INT(dci_alloc_rx[i].rnti), 
      T_INT(harq_pid),
      T_INT(ue->ulsch[eNB_id]->harq_processes[harq_pid]->mcs),
      T_INT(ue->ulsch[eNB_id]->harq_processes[harq_pid]->round),
      T_INT(ue->ulsch[eNB_id]->harq_processes[harq_pid]->first_rb),
      T_INT(ue->ulsch[eNB_id]->harq_processes[harq_pid]->nb_rb),
      T_INT(ue->ulsch[eNB_id]->harq_processes[harq_pid]->TBS));

      LOG_D(PHY,"[UE  %d] Generate UE ULSCH C_RNTI format 0 (subframe %d)\n",ue->Mod_id,subframe_rx);
LOG_DEBUG_END

      }
    } else if( (dci_alloc_rx[i].rnti == ue->ulsch[eNB_id]->cba_rnti[0]) &&
         (dci_alloc_rx[i].format == format0)) {
      // UE could belong to more than one CBA group
      // ue->Mod_id%ue->ulsch[eNB_id]->num_active_cba_groups]
LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
      LOG_D(PHY,"[UE  %d][PUSCH] Frame %d subframe %d: Found cba rnti %x, format 0, dci_cnt %d\n",
      ue->Mod_id,frame_rx,subframe_rx,dci_alloc_rx[i].rnti,i);
      /*
  if (((frame_rx%100) == 0) || (frame_rx < 20))
  dump_dci(&ue->frame_parms, &dci_alloc_rx[i]);
      */
LOG_DEBUG_END

      ue->ulsch_no_allocation_counter[eNB_id] = 0;
      //dump_dci(&ue->frame_parms,&dci_alloc_rx[i]);

      if ((ue->UE_mode[eNB_id] > PRACH) &&
    (generate_ue_ulsch_params_from_dci((void *)&dci_alloc_rx[i].dci_pdu,
               ue->ulsch[eNB_id]->cba_rnti[0],
               subframe_rx,
               format0,
               ue,
               proc,
               SI_RNTI,
               0,
               P_RNTI,
               CBA_RNTI,
               eNB_id,
               0)==0)) {

LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
  LOG_D(PHY,"[UE  %d] Generate UE ULSCH CBA_RNTI format 0 (subframe %d)\n",ue->Mod_id,subframe_rx);
LOG_DEBUG_END
  ue->ulsch[eNB_id]->num_cba_dci[(subframe_rx+4)%10]++;
      }
    }

    else {
LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
      LOG_D(PHY,"[UE  %d] frame %d, subframe %d: received DCI %d with RNTI=%x (C-RNTI:%x, CBA_RNTI %x) and format %d!\n",ue->Mod_id,frame_rx,subframe_rx,i,dci_alloc_rx[i].rnti,
	    ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->crnti,
	    ue->ulsch[eNB_id]->cba_rnti[0],
	    dci_alloc_rx[i].format);

      //      dump_dci(&ue->frame_parms, &dci_alloc_rx[i]);
LOG_DEBUG_END
    }

  }
LOG_DEBUG_BEGIN(UE_TIMING)
  stop_meas(&ue->dlsch_rx_pdcch_stats);
LOG_DEBUG_END
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PDCCH_PROCEDURES, VCD_FUNCTION_OUT);
  return(0);
}


void ue_pmch_procedures(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc,int eNB_id,int abstraction_flag) {

  int subframe_rx = proc->subframe_rx;
  int frame_rx = proc->frame_rx;
  int pmch_mcs=-1;
#if (RRC_VERSION >= MAKE_VERSION(10, 0, 0))
  int CC_id = ue->CC_id;
#endif
  uint8_t sync_area=255;
  uint8_t mcch_active;
  int l;
  int ret=0;

  if (is_pmch_subframe(frame_rx,subframe_rx,&ue->frame_parms)) {
    // LOG_D(PHY,"ue calling pmch subframe ..\n ");

    LOG_D(PHY,"[UE %d] Frame %d, subframe %d: Querying for PMCH demodulation\n",
    ue->Mod_id,(subframe_rx==9?-1:0)+frame_rx,subframe_rx);
#if (RRC_VERSION >= MAKE_VERSION(10, 0, 0))

    pmch_mcs = ue_query_mch(ue->Mod_id,
			    CC_id,
			    frame_rx,
			    subframe_rx,
			    eNB_id,
			    &sync_area,
			    &mcch_active);
    
#else
    pmch_mcs=-1;
#endif

    if (pmch_mcs>=0) {
      LOG_D(PHY,"[UE %d] Frame %d, subframe %d: Programming PMCH demodulation for mcs %d\n",ue->Mod_id,frame_rx,subframe_rx,pmch_mcs);
      fill_UE_dlsch_MCH(ue,pmch_mcs,1,0,0);

      
      for (l=2; l<12; l++) {
	
	slot_fep_mbsfn(ue,
		       l,
		       subframe_rx,
		       0,0);//ue->rx_offset,0);
      }
      
      for (l=2; l<12; l++) {
	rx_pmch(ue,
		0,
		subframe_rx,
		l);
      }
      
      
      ue->dlsch_MCH[0]->harq_processes[0]->G = get_G(&ue->frame_parms,
						     ue->dlsch_MCH[0]->harq_processes[0]->nb_rb,
						     ue->dlsch_MCH[0]->harq_processes[0]->rb_alloc_even,
						     ue->dlsch_MCH[0]->harq_processes[0]->Qm,
						     1,
						     2,
						     frame_rx,
						     subframe_rx,
						     0);
      
      dlsch_unscrambling(&ue->frame_parms,1,ue->dlsch_MCH[0],
			 ue->dlsch_MCH[0]->harq_processes[0]->G,
			 ue->pdsch_vars_MCH[0]->llr[0],0,subframe_rx<<1);
      
      ret = dlsch_decoding(ue,
			   ue->pdsch_vars_MCH[0]->llr[0],
			   &ue->frame_parms,
			   ue->dlsch_MCH[0],
			   ue->dlsch_MCH[0]->harq_processes[0],
			   frame_rx,
			   subframe_rx,
			   0,
			   0,1);
      if (mcch_active == 1)
	ue->dlsch_mcch_trials[sync_area][0]++;
      else
	ue->dlsch_mtch_trials[sync_area][0]++;
      
      if (ret == (1+ue->dlsch_MCH[0]->max_turbo_iterations)) {
	if (mcch_active == 1)
	  ue->dlsch_mcch_errors[sync_area][0]++;
	else
	  ue->dlsch_mtch_errors[sync_area][0]++;
	
	LOG_D(PHY,"[UE %d] Frame %d, subframe %d: PMCH in error (%d,%d), not passing to L2 (TBS %d, iter %d,G %d)\n",
	      ue->Mod_id,
              frame_rx,subframe_rx,
	      ue->dlsch_mcch_errors[sync_area][0],
	      ue->dlsch_mtch_errors[sync_area][0],
	      ue->dlsch_MCH[0]->harq_processes[0]->TBS>>3,
	      ue->dlsch_MCH[0]->max_turbo_iterations,
	      ue->dlsch_MCH[0]->harq_processes[0]->G);
	dump_mch(ue,0,ue->dlsch_MCH[0]->harq_processes[0]->G,subframe_rx);
LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
	
	for (int i=0; i<ue->dlsch_MCH[0]->harq_processes[0]->TBS>>3; i++) {
	  LOG_T(PHY,"%02x.",ue->dlsch_MCH[0]->harq_processes[0]->c[0][i]);
	}
	
	LOG_T(PHY,"\n");
LOG_DEBUG_END
	
	
	//	if (subframe_rx==9)
	//  mac_xface->macphy_exit("Why are we exiting here?");
      } else { // decoding successful
#if (RRC_VERSION >= MAKE_VERSION(10, 0, 0))
	
	if (mcch_active == 1) {
	  ue_send_mch_sdu(ue->Mod_id,
			  CC_id,
			  frame_rx,
			  ue->dlsch_MCH[0]->harq_processes[0]->b,
			  ue->dlsch_MCH[0]->harq_processes[0]->TBS>>3,
			  eNB_id,// not relevant in eMBMS context
			  sync_area);
	  ue->dlsch_mcch_received[sync_area][0]++;
	  
	  
	  if (ue->dlsch_mch_received_sf[subframe_rx%5][0] == 1 ) {
	    ue->dlsch_mch_received_sf[subframe_rx%5][0]=0;
	  } else {
	    ue->dlsch_mch_received[0]+=1;
	    ue->dlsch_mch_received_sf[subframe_rx][0]=1;
	  }
	  
	  
	}

#endif // #if (RRC_VERSION >= MAKE_VERSION(10, 0, 0))
      } // decoding sucessful
    } // pmch_mcs>=0
  } // is_pmch_subframe=true
}

void copy_harq_proc_struct(LTE_DL_UE_HARQ_t *harq_processes_dest, LTE_DL_UE_HARQ_t *current_harq_processes)
{
      harq_processes_dest->B              = current_harq_processes->B              ;
      harq_processes_dest->C              = current_harq_processes->C              ;
      harq_processes_dest->Cminus         = current_harq_processes->Cminus         ;
      harq_processes_dest->Cplus          = current_harq_processes->Cplus          ;
      harq_processes_dest->DCINdi         = current_harq_processes->DCINdi         ;
      harq_processes_dest->F              = current_harq_processes->F              ;
      harq_processes_dest->G              = current_harq_processes->G              ;
      harq_processes_dest->Kminus         = current_harq_processes->Kminus         ;
      harq_processes_dest->Kplus          = current_harq_processes->Kplus          ;
      harq_processes_dest->Nl             = current_harq_processes->Nl             ;
      harq_processes_dest->Qm             = current_harq_processes->Qm             ;
      harq_processes_dest->TBS            = current_harq_processes->TBS            ;
      harq_processes_dest->b              = current_harq_processes->b              ;
      harq_processes_dest->codeword       = current_harq_processes->codeword       ;
      harq_processes_dest->delta_PUCCH    = current_harq_processes->delta_PUCCH    ;
      harq_processes_dest->dl_power_off   = current_harq_processes->dl_power_off   ;
      harq_processes_dest->first_tx       = current_harq_processes->first_tx       ;
      harq_processes_dest->mcs            = current_harq_processes->mcs            ;
      harq_processes_dest->mimo_mode      = current_harq_processes->mimo_mode      ;
      harq_processes_dest->nb_rb          = current_harq_processes->nb_rb          ;
      harq_processes_dest->pmi_alloc      = current_harq_processes->pmi_alloc      ;
      harq_processes_dest->rb_alloc_even[0]  = current_harq_processes->rb_alloc_even[0] ;
      harq_processes_dest->rb_alloc_even[1]  = current_harq_processes->rb_alloc_even[1] ;
      harq_processes_dest->rb_alloc_even[2]  = current_harq_processes->rb_alloc_even[2] ;
      harq_processes_dest->rb_alloc_even[3]  = current_harq_processes->rb_alloc_even[3] ;
      harq_processes_dest->rb_alloc_odd[0]  = current_harq_processes->rb_alloc_odd[0]  ;
      harq_processes_dest->rb_alloc_odd[1]  = current_harq_processes->rb_alloc_odd[1]  ;
      harq_processes_dest->rb_alloc_odd[2]  = current_harq_processes->rb_alloc_odd[2]  ;
      harq_processes_dest->rb_alloc_odd[3]  = current_harq_processes->rb_alloc_odd[3]  ;
      harq_processes_dest->round          = current_harq_processes->round          ;
      harq_processes_dest->rvidx          = current_harq_processes->rvidx          ;
      harq_processes_dest->status         = current_harq_processes->status         ;
      harq_processes_dest->vrb_type       = current_harq_processes->vrb_type       ;
}

void copy_ack_struct(harq_status_t *harq_ack_dest, harq_status_t *current_harq_ack)
{
    memcpy(harq_ack_dest, current_harq_ack, sizeof(harq_status_t));
}

void ue_pdsch_procedures(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc, int eNB_id, PDSCH_t pdsch, LTE_UE_DLSCH_t *dlsch0, LTE_UE_DLSCH_t *dlsch1, int s0, int s1, int abstraction_flag) {

  int subframe_rx = proc->subframe_rx;
  int m;
  int harq_pid;
  int i_mod,eNB_id_i,dual_stream_UE;
  int first_symbol_flag=0;

  if (dlsch0->active == 0)
    return;

  for (m=s0;m<=s1;m++) {

    if (dlsch0 && (!dlsch1))  {
      harq_pid = dlsch0->current_harq_pid;
      LOG_D(PHY,"[UE %d] PDSCH active in subframe %d, harq_pid %d Symbol %d\n",ue->Mod_id,subframe_rx,harq_pid,m);

      if ((pdsch==PDSCH) &&
          (ue->transmission_mode[eNB_id] == 5) &&
          (dlsch0->harq_processes[harq_pid]->dl_power_off==0) &&
          (ue->use_ia_receiver ==1)) {
        dual_stream_UE = 1;
        eNB_id_i = ue->n_connected_eNB;
        i_mod =  dlsch0->harq_processes[harq_pid]->Qm;

      }
      else if((pdsch==PDSCH) && (ue->transmission_mode[eNB_id]==3))
      {
          dual_stream_UE = rx_IC_dual_stream;
          eNB_id_i       = eNB_id;
          i_mod          = 0;
      }
      else {
        dual_stream_UE = 0;
        eNB_id_i = eNB_id+1;
        i_mod = 0;
      }

      //TM7 UE specific channel estimation here!!!
      if (ue->transmission_mode[eNB_id]==7) {
        if (ue->frame_parms.Ncp==0) {
          if ((m==3) || (m==6) || (m==9) || (m==12))
            //LOG_D(PHY,"[UE %d] dlsch->active in subframe %d => %d, l=%d\n",phy_vars_ue->Mod_id,subframe_rx,phy_vars_ue->dlsch_ue[eNB_id][0]->active, l);
            lte_dl_bf_channel_estimation(ue,eNB_id,0,subframe_rx*2+(m>6?1:0),5,m);
        } else {
          LOG_E(PHY,"[UE %d]Beamforming channel estimation not supported yet for TM7 extented CP.\n",ue->Mod_id);
        }
      }

      if ((m==s0) && (m<4))
          first_symbol_flag = 1;
      else
          first_symbol_flag = 0;

LOG_DEBUG_BEGIN(UE_TIMING)
      uint8_t slot = 0;
      if(m >= ue->frame_parms.symbols_per_tti>>1)
        slot = 1;
      start_meas(&ue->dlsch_llr_stats_parallelization[ue->current_thread_id[subframe_rx]][slot]);
LOG_DEBUG_END
      // process DLSCH received in first slot
      rx_pdsch(ue,
	       pdsch,
	       eNB_id,
	       eNB_id_i,
	       proc->frame_rx,
	       subframe_rx,  // subframe,
	       m,
	       first_symbol_flag,
	       dual_stream_UE,
	       i_mod,
	       dlsch0->current_harq_pid);
LOG_DEBUG_BEGIN(UE_TIMING)
      uint8_t slot = 0;
      if(m >= ue->frame_parms.symbols_per_tti>>1)
        slot = 1;
      stop_meas(&ue->dlsch_llr_stats_parallelization[ue->current_thread_id[subframe_rx]][slot]);
      LOG_UI(PHY, "[AbsSFN %d.%d] LLR Computation Symbol %d %5.2f \n",proc->frame_rx,subframe_rx,m,ue->dlsch_llr_stats_parallelization[ue->current_thread_id[subframe_rx]][slot].p_time/(cpuf*1000.0));
LOG_DEBUG_END



      if(first_symbol_flag)
      {
          proc->first_symbol_available = 1;
      }
    } // CRNTI active
  }
}

void process_rar(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc, int eNB_id, runmode_t mode, int abstraction_flag) {

  int frame_rx = proc->frame_rx;
  int subframe_rx = proc->subframe_rx;
  int timing_advance;
  LTE_UE_DLSCH_t *dlsch0 = ue->dlsch_ra[eNB_id];
  int harq_pid = 0;
  uint8_t *rar;
  uint8_t next1_thread_id = ue->current_thread_id[subframe_rx]== (RX_NB_TH-1) ? 0:(ue->current_thread_id[subframe_rx]+1);
  uint8_t next2_thread_id = next1_thread_id== (RX_NB_TH-1) ? 0:(next1_thread_id+1);

  LOG_D(PHY,"[UE  %d][RAPROC] Frame %d subframe %d Received RAR  mode %d\n",
  ue->Mod_id,
  frame_rx,
  subframe_rx, ue->UE_mode[eNB_id]);


  if (ue->mac_enabled == 1) {
    if ((ue->UE_mode[eNB_id] != PUSCH) &&
  (ue->prach_resources[eNB_id]->Msg3!=NULL)) {
      LOG_D(PHY,"[UE  %d][RAPROC] Frame %d subframe %d Invoking MAC for RAR (current preamble %d)\n",
	    ue->Mod_id,frame_rx,
	    subframe_rx,
	    ue->prach_resources[eNB_id]->ra_PreambleIndex);
      
      timing_advance = ue_process_rar(ue->Mod_id,
				      ue->CC_id,
				      frame_rx,
				      ue->prach_resources[eNB_id]->ra_RNTI,
				      dlsch0->harq_processes[0]->b,
				      &ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->crnti,
				      ue->prach_resources[eNB_id]->ra_PreambleIndex,
				      dlsch0->harq_processes[0]->b); // alter the 'b' buffer so it contains only the selected RAR header and RAR payload
      
      ue->pdcch_vars[next1_thread_id][eNB_id]->crnti = ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->crnti;
      ue->pdcch_vars[next2_thread_id][eNB_id]->crnti = ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->crnti;

      
      if (timing_advance!=0xffff) {

              LOG_D(PHY,"[UE  %d][RAPROC] Frame %d subframe %d Got rnti %x and timing advance %d from RAR\n",
              ue->Mod_id,
              frame_rx,
              subframe_rx,
              ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->crnti,
              timing_advance);

	      // remember this c-rnti is still a tc-rnti
	      
	      ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->crnti_is_temporary = 1;
	      
	      //timing_advance = 0;
	      process_timing_advance_rar(ue,proc,timing_advance);
	      
	      if (mode!=debug_prach) {
		ue->ulsch_Msg3_active[eNB_id]=1;
		get_Msg3_alloc(&ue->frame_parms,
			       subframe_rx,
			       frame_rx,
			       &ue->ulsch_Msg3_frame[eNB_id],
			       &ue->ulsch_Msg3_subframe[eNB_id]);
		
		LOG_D(PHY,"[UE  %d][RAPROC] Got Msg3_alloc Frame %d subframe %d: Msg3_frame %d, Msg3_subframe %d\n",
		      ue->Mod_id,
		      frame_rx,
		      subframe_rx,
		      ue->ulsch_Msg3_frame[eNB_id],
		      ue->ulsch_Msg3_subframe[eNB_id]);
		harq_pid = subframe2harq_pid(&ue->frame_parms,
					     ue->ulsch_Msg3_frame[eNB_id],
					     ue->ulsch_Msg3_subframe[eNB_id]);
		ue->ulsch[eNB_id]->harq_processes[harq_pid]->round = 0;
		
		ue->UE_mode[eNB_id] = RA_RESPONSE;
		//      ue->Msg3_timer[eNB_id] = 10;
		ue->ulsch[eNB_id]->power_offset = 6;
		ue->ulsch_no_allocation_counter[eNB_id] = 0;
	      }
      } else { // PRACH preamble doesn't match RAR
	LOG_W(PHY,"[UE  %d][RAPROC] Received RAR preamble (%d) doesn't match !!!\n",
	      ue->Mod_id,
	      ue->prach_resources[eNB_id]->ra_PreambleIndex);
      }
    } // mode != PUSCH
  }
  else {
    rar = dlsch0->harq_processes[0]->b+1;
    timing_advance = ((((uint16_t)(rar[0]&0x7f))<<4) + (rar[1]>>4));
    process_timing_advance_rar(ue,proc,timing_advance);
  }
  
}

void ue_dlsch_procedures(PHY_VARS_UE *ue,
       UE_rxtx_proc_t *proc,
       int eNB_id,
       PDSCH_t pdsch,
       LTE_UE_DLSCH_t *dlsch0,
       LTE_UE_DLSCH_t *dlsch1,
       int *dlsch_errors,
       runmode_t mode,
       int abstraction_flag) {

  int harq_pid;
  int frame_rx = proc->frame_rx;
  int subframe_rx = proc->subframe_rx;
  int ret=0, ret1=0;
  int CC_id = ue->CC_id;
  LTE_UE_PDSCH *pdsch_vars;
  uint8_t is_cw0_active = 0;
  uint8_t is_cw1_active = 0;

  if (dlsch0==NULL)
      AssertFatal(0,"dlsch0 should be defined at this level \n");

  harq_pid = dlsch0->current_harq_pid;
  is_cw0_active = dlsch0->harq_processes[harq_pid]->status;

  if(dlsch1)
    is_cw1_active = dlsch1->harq_processes[harq_pid]->status;

  LOG_D(PHY,"AbsSubframe %d.%d Start Turbo Decoder for CW0 [harq_pid %d] ? %d \n", frame_rx%1024, subframe_rx, harq_pid, is_cw0_active);
  LOG_D(PHY,"AbsSubframe %d.%d Start Turbo Decoder for CW1 [harq_pid %d] ? %d \n", frame_rx%1024, subframe_rx, harq_pid, is_cw1_active);

  if(is_cw0_active && is_cw1_active)
  {
      dlsch0->Kmimo = 2;
      dlsch1->Kmimo = 2;
  }
  else
  {
      dlsch0->Kmimo = 1;
  }
  if (1) {
    switch (pdsch) {
    case SI_PDSCH:
      pdsch_vars = ue->pdsch_vars_SI[eNB_id];
      break;
    case RA_PDSCH:
      pdsch_vars = ue->pdsch_vars_ra[eNB_id];
      break;
    case P_PDSCH:
      pdsch_vars = ue->pdsch_vars_p[eNB_id];
      break;
    case PDSCH:
      pdsch_vars = ue->pdsch_vars[ue->current_thread_id[subframe_rx]][eNB_id];
      break;
    case PMCH:
    case PDSCH1:
      LOG_E(PHY,"Illegal PDSCH %d for ue_pdsch_procedures\n",pdsch);
      pdsch_vars = NULL;
      return;
      break;
    default:
      pdsch_vars = NULL;
      return;
      break;

    }
    if (frame_rx < *dlsch_errors)
      *dlsch_errors=0;

    if (pdsch==RA_PDSCH) {
      
      if (ue->prach_resources[eNB_id]!=NULL)
	dlsch0->rnti = ue->prach_resources[eNB_id]->ra_RNTI;
      else {
	LOG_E(PHY,"[UE %d] Frame %d, subframe %d: FATAL, prach_resources is NULL\n",ue->Mod_id,frame_rx,subframe_rx);
	AssertFatal(1==0,"prach_resources is NULL");
      }
    }
    
      
      // start turbo decode for CW 0
      dlsch0->harq_processes[harq_pid]->G = get_G(&ue->frame_parms,
						  dlsch0->harq_processes[harq_pid]->nb_rb,
						  dlsch0->harq_processes[harq_pid]->rb_alloc_even,
						  dlsch0->harq_processes[harq_pid]->Qm,
						  dlsch0->harq_processes[harq_pid]->Nl,
						  ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->num_pdcch_symbols,
						  frame_rx,
						  subframe_rx,
						  ue->transmission_mode[eNB_id]<7?0:ue->transmission_mode[eNB_id]);
LOG_DEBUG_BEGIN(UE_TIMING)
      start_meas(&ue->dlsch_unscrambling_stats);
LOG_DEBUG_END
      dlsch_unscrambling(&ue->frame_parms,
			 0,
			 dlsch0,
			 dlsch0->harq_processes[harq_pid]->G,
			 pdsch_vars->llr[0],
			 0,
			 subframe_rx<<1);
LOG_DEBUG_BEGIN(UE_TIMING)
      stop_meas(&ue->dlsch_unscrambling_stats);
LOG_DEBUG_END
      
      LOG_D(PHY," ------ start turbo decoder for AbsSubframe %d.%d / %d  ------  \n", frame_rx, subframe_rx, harq_pid);
      LOG_D(PHY,"start turbo decode for CW 0 for AbsSubframe %d.%d / %d --> nb_rb %d \n", frame_rx, subframe_rx, harq_pid, dlsch0->harq_processes[harq_pid]->nb_rb);
      LOG_D(PHY,"start turbo decode for CW 0 for AbsSubframe %d.%d / %d  --> rb_alloc_even %x \n", frame_rx, subframe_rx, harq_pid, (unsigned int)((intptr_t)dlsch0->harq_processes[harq_pid]->rb_alloc_even));
      LOG_D(PHY,"start turbo decode for CW 0 for AbsSubframe %d.%d / %d  --> Qm %d \n", frame_rx, subframe_rx, harq_pid, dlsch0->harq_processes[harq_pid]->Qm);
      LOG_D(PHY,"start turbo decode for CW 0 for AbsSubframe %d.%d / %d  --> Nl %d \n", frame_rx, subframe_rx, harq_pid, dlsch0->harq_processes[harq_pid]->Nl);
      LOG_D(PHY,"start turbo decode for CW 0 for AbsSubframe %d.%d / %d  --> G  %d \n", frame_rx, subframe_rx, harq_pid, dlsch0->harq_processes[harq_pid]->G);
      LOG_D(PHY,"start turbo decode for CW 0 for AbsSubframe %d.%d / %d  --> Kmimo  %d \n", frame_rx, subframe_rx, harq_pid, dlsch0->Kmimo);
      LOG_D(PHY,"start turbo decode for CW 0 for AbsSubframe %d.%d / %d  --> Pdcch Sym  %d \n", frame_rx, subframe_rx, harq_pid, ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->num_pdcch_symbols);
      
LOG_DEBUG_BEGIN(UE_TIMING)
      start_meas(&ue->dlsch_decoding_stats[ue->current_thread_id[subframe_rx]]);
LOG_DEBUG_END
      ret = dlsch_decoding(ue,
			   pdsch_vars->llr[0],
			   &ue->frame_parms,
			   dlsch0,
			   dlsch0->harq_processes[harq_pid],
			   frame_rx,
			   subframe_rx,
			   harq_pid,
			   pdsch==PDSCH?1:0,
			   dlsch0->harq_processes[harq_pid]->TBS>256?1:0);
      
LOG_DEBUG_BEGIN(UE_TIMING)
      stop_meas(&ue->dlsch_decoding_stats[ue->current_thread_id[subframe_rx]]);
      LOG_UI(PHY, " --> Unscrambling for CW0 %5.3f\n",
	    (ue->dlsch_unscrambling_stats.p_time)/(cpuf*1000.0));
      LOG_UI(PHY, "AbsSubframe %d.%d --> Turbo Decoding for CW0 %5.3f\n",
	    frame_rx%1024, subframe_rx,(ue->dlsch_decoding_stats[ue->current_thread_id[subframe_rx]].p_time)/(cpuf*1000.0));
      
LOG_DEBUG_END
      if(is_cw1_active)
	{
          // start turbo decode for CW 1
          dlsch1->harq_processes[harq_pid]->G = get_G(&ue->frame_parms,
						      dlsch1->harq_processes[harq_pid]->nb_rb,
						      dlsch1->harq_processes[harq_pid]->rb_alloc_even,
						      dlsch1->harq_processes[harq_pid]->Qm,
						      dlsch1->harq_processes[harq_pid]->Nl,
						      ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->num_pdcch_symbols,
						      frame_rx,
						      subframe_rx,
						      ue->transmission_mode[eNB_id]<7?0:ue->transmission_mode[eNB_id]);
LOG_DEBUG_BEGIN(UE_TIMING)
          start_meas(&ue->dlsch_unscrambling_stats);
LOG_DEBUG_END
          dlsch_unscrambling(&ue->frame_parms,
			     0,
			     dlsch1,
			     dlsch1->harq_processes[harq_pid]->G,
			     pdsch_vars->llr[1],
			     1,
			     subframe_rx<<1);
LOG_DEBUG_BEGIN(UE_TIMING)
          stop_meas(&ue->dlsch_unscrambling_stats);
LOG_DEBUG_END
	  
          LOG_D(PHY,"start turbo decode for CW 1 for AbsSubframe %d.%d / %d --> nb_rb %d \n", frame_rx, subframe_rx, harq_pid, dlsch1->harq_processes[harq_pid]->nb_rb);
          LOG_D(PHY,"start turbo decode for CW 1 for AbsSubframe %d.%d / %d  --> rb_alloc_even %x \n", frame_rx, subframe_rx, harq_pid, (uint16_t)((intptr_t)dlsch1->harq_processes[harq_pid]->rb_alloc_even));
          LOG_D(PHY,"start turbo decode for CW 1 for AbsSubframe %d.%d / %d  --> Qm %d \n", frame_rx, subframe_rx, harq_pid, dlsch1->harq_processes[harq_pid]->Qm);
          LOG_D(PHY,"start turbo decode for CW 1 for AbsSubframe %d.%d / %d  --> Nl %d \n", frame_rx, subframe_rx, harq_pid, dlsch1->harq_processes[harq_pid]->Nl);
          LOG_D(PHY,"start turbo decode for CW 1 for AbsSubframe %d.%d / %d  --> G  %d \n", frame_rx, subframe_rx, harq_pid, dlsch1->harq_processes[harq_pid]->G);
          LOG_D(PHY,"start turbo decode for CW 1 for AbsSubframe %d.%d / %d  --> Kmimo  %d \n", frame_rx, subframe_rx, harq_pid, dlsch1->Kmimo);
          LOG_D(PHY,"start turbo decode for CW 1 for AbsSubframe %d.%d / %d  --> Pdcch Sym  %d \n", frame_rx, subframe_rx, harq_pid, ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->num_pdcch_symbols);
	  
LOG_DEBUG_BEGIN(UE_TIMING)
          start_meas(&ue->dlsch_decoding_stats[ue->current_thread_id[subframe_rx]]);
LOG_DEBUG_END
	  
          ret1 = dlsch_decoding(ue,
				pdsch_vars->llr[1],
				&ue->frame_parms,
				dlsch1,
				dlsch1->harq_processes[harq_pid],
				frame_rx,
				subframe_rx,
				harq_pid,
				pdsch==PDSCH?1:0,
				dlsch1->harq_processes[harq_pid]->TBS>256?1:0);
	  
LOG_DEBUG_BEGIN(UE_TIMING)
          stop_meas(&ue->dlsch_decoding_stats[ue->current_thread_id[subframe_rx]]);
          LOG_UI(PHY, " --> Unscrambling for CW1 %5.3f\n",
		(ue->dlsch_unscrambling_stats.p_time)/(cpuf*1000.0));
          LOG_UI(PHY, "AbsSubframe %d.%d --> Turbo Decoding for CW1 %5.3f\n",
		frame_rx%1024, subframe_rx,(ue->dlsch_decoding_stats[ue->current_thread_id[subframe_rx]].p_time)/(cpuf*1000.0));
LOG_DEBUG_END

          LOG_D(PHY,"AbsSubframe %d.%d --> Turbo Decoding for CW1 %5.3f\n",
		frame_rx%1024, subframe_rx,(ue->dlsch_decoding_stats[ue->current_thread_id[subframe_rx]].p_time)/(cpuf*1000.0));
	}
      
      LOG_D(PHY," ------ end turbo decoder for AbsSubframe %d.%d ------  \n", frame_rx, subframe_rx);
    
    

    // Check CRC for CW 0
    if (ret == (1+dlsch0->max_turbo_iterations)) {
      *dlsch_errors=*dlsch_errors+1;

      if(dlsch0->rnti != 0xffff)
      {

	LOG_D(PHY,"[UE  %d][PDSCH %x/%d] AbsSubframe %d.%d : DLSCH CW0 in error (rv %d,round %d, mcs %d,TBS %d)\n",
	      ue->Mod_id,dlsch0->rnti,
	      harq_pid,frame_rx,subframe_rx,
	      dlsch0->harq_processes[harq_pid]->rvidx,
	      dlsch0->harq_processes[harq_pid]->round,
	      dlsch0->harq_processes[harq_pid]->mcs,
	      dlsch0->harq_processes[harq_pid]->TBS);
      }


    } else {
        if(dlsch0->rnti != 0xffff)
        {
      LOG_D(PHY,"[UE  %d][PDSCH %x/%d] AbsSubframe %d.%d : Received DLSCH CW0 (rv %d,round %d, mcs %d,TBS %d)\n",
            ue->Mod_id,dlsch0->rnti,
            harq_pid,frame_rx,subframe_rx,
            dlsch0->harq_processes[harq_pid]->rvidx,
            dlsch0->harq_processes[harq_pid]->round,
            dlsch0->harq_processes[harq_pid]->mcs,
            dlsch0->harq_processes[harq_pid]->TBS);
        }

LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
      int j;
      LOG_D(PHY,"dlsch harq_pid %d (rx): \n",dlsch0->current_harq_pid);

      for (j=0; j<dlsch0->harq_processes[dlsch0->current_harq_pid]->TBS>>3; j++)
  LOG_T(PHY,"%x.",dlsch0->harq_processes[dlsch0->current_harq_pid]->b[j]);

      LOG_T(PHY,"\n");
LOG_DEBUG_END


      if (ue->mac_enabled == 1) {
	
	switch (pdsch) {
	case PDSCH:
	  ue_send_sdu(ue->Mod_id,
		      CC_id,
		      frame_rx,
		      subframe_rx,
		      dlsch0->harq_processes[dlsch0->current_harq_pid]->b,
		      dlsch0->harq_processes[dlsch0->current_harq_pid]->TBS>>3,
		      eNB_id);
	  break;
	case SI_PDSCH:
	  ue_decode_si(ue->Mod_id,
		       CC_id,
		       frame_rx,
		       eNB_id,
		       ue->dlsch_SI[eNB_id]->harq_processes[0]->b,
		       ue->dlsch_SI[eNB_id]->harq_processes[0]->TBS>>3);
	  break;
	case P_PDSCH:
		ue_decode_p(ue->Mod_id,
		      CC_id,
		      frame_rx,
		      eNB_id,
		      ue->dlsch_SI[eNB_id]->harq_processes[0]->b,
		      ue->dlsch_SI[eNB_id]->harq_processes[0]->TBS>>3);
	  break;
	case RA_PDSCH:
	  process_rar(ue,proc,eNB_id,mode,abstraction_flag);
	  break;
	case PDSCH1:
	  LOG_E(PHY,"Shouldn't have PDSCH1 yet, come back later\n");
	  AssertFatal(1==0,"exiting");
	  break;
	case PMCH:
	  LOG_E(PHY,"Shouldn't have PMCH here\n");
	  AssertFatal(1==0,"exiting");
	  break;
	}
      }
      ue->total_TBS[eNB_id] =  ue->total_TBS[eNB_id] +
	dlsch0->harq_processes[dlsch0->current_harq_pid]->TBS;
      ue->total_received_bits[eNB_id] = ue->total_TBS[eNB_id] +
	dlsch0->harq_processes[dlsch0->current_harq_pid]->TBS;
    }
    // Check CRC for CW 1
    if(is_cw1_active)
      {
        if (ret1 == (1+dlsch0->max_turbo_iterations)) {
	  LOG_D(PHY,"[UE  %d][PDSCH %x/%d] Frame %d subframe %d DLSCH CW1 in error (rv %d,mcs %d,TBS %d)\n",
		ue->Mod_id,dlsch0->rnti,
		harq_pid,frame_rx,subframe_rx,
		dlsch0->harq_processes[harq_pid]->rvidx,
		dlsch0->harq_processes[harq_pid]->mcs,
		dlsch0->harq_processes[harq_pid]->TBS);
	  
        } else {
	  LOG_D(PHY,"[UE  %d][PDSCH %x/%d] Frame %d subframe %d: Received DLSCH CW1 (rv %d,mcs %d,TBS %d)\n",
		ue->Mod_id,dlsch0->rnti,
		harq_pid,frame_rx,subframe_rx,
		dlsch0->harq_processes[harq_pid]->rvidx,
		dlsch0->harq_processes[harq_pid]->mcs,
		dlsch0->harq_processes[harq_pid]->TBS);
	  
	  
	  if (ue->mac_enabled == 1) {
	    switch (pdsch) {
	    case PDSCH:
	      if(is_cw1_active)
		ue_send_sdu(ue->Mod_id,
			    CC_id,
			    frame_rx,
			    subframe_rx,
			    dlsch1->harq_processes[dlsch1->current_harq_pid]->b,
			    dlsch1->harq_processes[dlsch1->current_harq_pid]->TBS>>3,
			    eNB_id);
	      break;
	    case SI_PDSCH:
	    case P_PDSCH:
	    case RA_PDSCH:
	    case PDSCH1:
	    case PMCH:
	      AssertFatal(0,"exiting");
	      break;
	    }
	  }
        }
      }
    
LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
    LOG_D(PHY,"[UE  %d][PDSCH %x/%d] Frame %d subframe %d: PDSCH/DLSCH decoding iter %d (mcs %d, rv %d, TBS %d)\n",
	  ue->Mod_id,
	  dlsch0->rnti,harq_pid,
	  frame_rx,subframe_rx,ret,
	  dlsch0->harq_processes[harq_pid]->mcs,
	  dlsch0->harq_processes[harq_pid]->rvidx,
	  dlsch0->harq_processes[harq_pid]->TBS);
    
    if (frame_rx%100==0) {
      LOG_D(PHY,"[UE  %d][PDSCH %x] Frame %d subframe %d dlsch_errors %d, dlsch_received %d, dlsch_fer %d, current_dlsch_cqi %d\n",
	    ue->Mod_id,dlsch0->rnti,
	    frame_rx,subframe_rx,
	    ue->dlsch_errors[eNB_id],
	    ue->dlsch_received[eNB_id],
	    ue->dlsch_fer[eNB_id],
	    ue->measurements.wideband_cqi_tot[eNB_id]);
    }
    
LOG_DEBUG_END
    
  }
  
  
}

/*!
 * \brief This is the UE synchronize thread.
 * It performs band scanning and synchonization.
 * \param arg is a pointer to a \ref PHY_VARS_UE structure.
 * \returns a pointer to an int. The storage is not on the heap and must not be freed.
 */
#ifdef UE_SLOT_PARALLELISATION
#define FIFO_PRIORITY   40
void *UE_thread_slot1_dl_processing(void *arg) {

    static __thread int UE_dl_slot1_processing_retval;
    struct rx_tx_thread_data *rtd = arg;
    UE_rxtx_proc_t *proc = rtd->proc;
    PHY_VARS_UE    *ue   = rtd->UE;

    int frame_rx;
    uint8_t subframe_rx;
    uint8_t pilot0;
    uint8_t pilot1;
    uint8_t slot1;

    uint8_t next_subframe_rx;
    uint8_t next_subframe_slot0;

    proc->instance_cnt_slot1_dl_processing=-1;
    proc->subframe_rx=proc->sub_frame_start;

    char threadname[256];
    sprintf(threadname,"UE_thread_slot1_dl_processing_%d", proc->sub_frame_start);

    cpu_set_t cpuset;
    CPU_ZERO(&cpuset);
    if ( (proc->sub_frame_start+1)%RX_NB_TH == 0 && threads.slot1_proc_one != -1 )
        CPU_SET(threads.slot1_proc_one, &cpuset);
    if ( (proc->sub_frame_start+1)%RX_NB_TH == 1 && threads.slot1_proc_two != -1 )
        CPU_SET(threads.slot1_proc_two, &cpuset);
    if ( (proc->sub_frame_start+1)%RX_NB_TH == 2 && threads.slot1_proc_three != -1 )
        CPU_SET(threads.slot1_proc_three, &cpuset);

    init_thread(900000,1000000 , FIFO_PRIORITY-1, &cpuset,
                threadname);

    while (!oai_exit) {
        if (pthread_mutex_lock(&proc->mutex_slot1_dl_processing) != 0) {
            LOG_E( PHY, "[SCHED][UE] error locking mutex for UE slot1 dl processing\n" );
            exit_fun("nothing to add");
        }
        while (proc->instance_cnt_slot1_dl_processing < 0) {
            // most of the time, the thread is waiting here
            pthread_cond_wait( &proc->cond_slot1_dl_processing, &proc->mutex_slot1_dl_processing );
        }
        if (pthread_mutex_unlock(&proc->mutex_slot1_dl_processing) != 0) {
            LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE slot1 dl processing \n" );
            exit_fun("nothing to add");
        }

        /*for(int th_idx=0; th_idx< RX_NB_TH; th_idx++)
        {
        frame_rx    = ue->proc.proc_rxtx[0].frame_rx;
        subframe_rx = ue->proc.proc_rxtx[0].subframe_rx;
        printf("AbsSubframe %d.%d execute dl slot1 processing \n", frame_rx, subframe_rx);
        }*/
        frame_rx    = proc->frame_rx;
        subframe_rx = proc->subframe_rx;
        next_subframe_rx    = (1+subframe_rx)%10;
        next_subframe_slot0 = next_subframe_rx<<1;

        slot1  = (subframe_rx<<1) + 1;
        pilot0 = 0;

        //printf("AbsSubframe %d.%d execute dl slot1 processing \n", frame_rx, subframe_rx);

        if (ue->frame_parms.Ncp == 0) {  // normal prefix
            pilot1 = 4;
        } else { // extended prefix
            pilot1 = 3;
        }

        /**** Slot1 FE Processing ****/
LOG_DEBUG_BEGIN(UE_TIMING)
        start_meas(&ue->ue_front_end_per_slot_stat[ue->current_thread_id[subframe_rx]][1]);
LOG_DEBUG_END
        // I- start dl slot1 processing
        // do first symbol of next downlink subframe for channel estimation
        /*
        // 1- perform FFT for pilot ofdm symbols first (ofdmSym0 next subframe ofdmSym11)
        if (subframe_select(&ue->frame_parms,next_subframe_rx) != SF_UL)
        {
            front_end_fft(ue,
                    pilot0,
                    next_subframe_slot0,
                    0,
                    0);
        }

        front_end_fft(ue,
                pilot1,
                slot1,
                0,
                0);
         */
        // 1- perform FFT
        for (int l=1; l<ue->frame_parms.symbols_per_tti>>1; l++)
        {
            //if( (l != pilot0) && (l != pilot1))
            {
LOG_DEBUG_BEGIN(UE_TIMING)
                start_meas(&ue->ofdm_demod_stats);
LOG_DEBUG_END
                VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP, VCD_FUNCTION_IN);
                //printf("AbsSubframe %d.%d FFT slot %d, symbol %d\n", frame_rx,subframe_rx,slot1,l);
                front_end_fft(ue,
                        l,
                        slot1,
                        0,
                        0);
                VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP, VCD_FUNCTION_OUT);
LOG_DEBUG_BEGIN(UE_TIMING)
                stop_meas(&ue->ofdm_demod_stats);
LOG_DEBUG_END
            }
        } // for l=1..l2

        if (subframe_select(&ue->frame_parms,next_subframe_rx) != SF_UL)
        {
            //printf("AbsSubframe %d.%d FFT slot %d, symbol %d\n", frame_rx,subframe_rx,next_subframe_slot0,pilot0);
            front_end_fft(ue,
                    pilot0,
                    next_subframe_slot0,
                    0,
                    0);
        }

        // 2- perform Channel Estimation for slot1
        for (int l=1; l<ue->frame_parms.symbols_per_tti>>1; l++)
        {
            if(l == pilot1)
            {
                //wait until channel estimation for pilot0/slot1 is available
                uint32_t wait = 0;
                while(proc->chan_est_pilot0_slot1_available == 0)
                {
                    usleep(1);
                    wait++;
                }
                //printf("[slot1 dl processing] ChanEst symbol %d slot %d wait%d\n",l,slot1,wait);
            }
            //printf("AbsSubframe %d.%d ChanEst slot %d, symbol %d\n", frame_rx,subframe_rx,slot1,l);
            front_end_chanEst(ue,
                    l,
                    slot1,
                    0);
            ue_measurement_procedures(l-1,ue,proc,0,1+(subframe_rx<<1),0,ue->mode);
        }
        //printf("AbsSubframe %d.%d ChanEst slot %d, symbol %d\n", frame_rx,subframe_rx,next_subframe_slot0,pilot0);
        front_end_chanEst(ue,
                pilot0,
                next_subframe_slot0,
                0);

        if ( (subframe_rx == 0) && (ue->decode_MIB == 1))
        {
            ue_pbch_procedures(0,ue,proc,0);
        }

        proc->chan_est_slot1_available = 1;
        //printf("Set available slot 1channelEst to 1 AbsSubframe %d.%d \n",frame_rx,subframe_rx);
        //printf(" [slot1 dl processing] ==> FFT/CHanEst Done for AbsSubframe %d.%d \n", proc->frame_rx, proc->subframe_rx);

        //printf(" [slot1 dl processing] ==> Start LLR Comuptation slot1 for AbsSubframe %d.%d \n", proc->frame_rx, proc->subframe_rx);


LOG_DEBUG_BEGIN(UE_TIMING)
        stop_meas(&ue->ue_front_end_per_slot_stat[ue->current_thread_id[subframe_rx]][1]);
        LOG_UI(PHY, "[AbsSFN %d.%d] Slot1: FFT + Channel Estimate + Pdsch Proc Slot0 %5.2f \n",frame_rx,subframe_rx,ue->ue_front_end_per_slot_stat[ue->current_thread_id[subframe_rx]][1].p_time/(cpuf*1000.0));

LOG_DEBUG_END


    //wait until pdcch is decoded
    uint32_t wait = 0;
    while(proc->dci_slot0_available == 0)
    {
        usleep(1);
        wait++;
    }
    //printf("[slot1 dl processing] AbsSubframe %d.%d LLR Computation Start wait DCI %d\n",frame_rx,subframe_rx,wait);


    /**** Pdsch Procedure Slot1 ****/
    // start slot1 thread for Pdsch Procedure (slot1)
    // do procedures for C-RNTI
    //printf("AbsSubframe %d.%d Pdsch Procedure (slot1)\n",frame_rx,subframe_rx);


LOG_DEBUG_BEGIN(UE_TIMING)
    start_meas(&ue->pdsch_procedures_per_slot_stat[ue->current_thread_id[subframe_rx]][1]);
LOG_DEBUG_END
    // start slave thread for Pdsch Procedure (slot1)
    // do procedures for C-RNTI
    uint8_t eNB_id = 0;
    uint8_t abstraction_flag = 0;
    if (ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0]->active == 1) {
        //wait until first ofdm symbol is processed
        //wait = 0;
        //while(proc->first_symbol_available == 0)
        //{
        //    usleep(1);
        //    wait++;
        //}
        //printf("[slot1 dl processing] AbsSubframe %d.%d LLR Computation Start wait First Ofdm Sym %d\n",frame_rx,subframe_rx,wait);

        //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_IN);
        ue_pdsch_procedures(ue,
                proc,
                eNB_id,
                PDSCH,
                ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0],
                NULL,
                (ue->frame_parms.symbols_per_tti>>1),
                ue->frame_parms.symbols_per_tti-1,
                abstraction_flag);
        LOG_D(PHY," ------ end PDSCH ChannelComp/LLR slot 0: AbsSubframe %d.%d ------  \n", frame_rx%1024, subframe_rx);
        LOG_D(PHY," ------ --> PDSCH Turbo Decoder slot 0/1: AbsSubframe %d.%d ------  \n", frame_rx%1024, subframe_rx);
    }

    // do procedures for SI-RNTI
    if ((ue->dlsch_SI[eNB_id]) && (ue->dlsch_SI[eNB_id]->active == 1)) {
        ue_pdsch_procedures(ue,
                proc,
                eNB_id,
                SI_PDSCH,
                ue->dlsch_SI[eNB_id],
                NULL,
                (ue->frame_parms.symbols_per_tti>>1),
                ue->frame_parms.symbols_per_tti-1,
                abstraction_flag);
    }

    // do procedures for P-RNTI
    if ((ue->dlsch_p[eNB_id]) && (ue->dlsch_p[eNB_id]->active == 1)) {
        ue_pdsch_procedures(ue,
                proc,
                eNB_id,
                P_PDSCH,
                ue->dlsch_p[eNB_id],
                NULL,
                (ue->frame_parms.symbols_per_tti>>1),
                ue->frame_parms.symbols_per_tti-1,
                abstraction_flag);
    }
    // do procedures for RA-RNTI
    if ((ue->dlsch_ra[eNB_id]) && (ue->dlsch_ra[eNB_id]->active == 1)) {
        ue_pdsch_procedures(ue,
                proc,
                eNB_id,
                RA_PDSCH,
                ue->dlsch_ra[eNB_id],
                NULL,
                (ue->frame_parms.symbols_per_tti>>1),
                ue->frame_parms.symbols_per_tti-1,
                abstraction_flag);
    }

    proc->llr_slot1_available=1;
    //printf("Set available LLR slot1 to 1 AbsSubframe %d.%d \n",frame_rx,subframe_rx);

LOG_DEBUG_BEGIN(UE_TIMING)
    stop_meas(&ue->pdsch_procedures_per_slot_stat[ue->current_thread_id[subframe_rx]][1]);
    LOG_UI(PHY, "[AbsSFN %d.%d] Slot1: LLR Computation %5.2f \n",frame_rx,subframe_rx,ue->pdsch_procedures_per_slot_stat[ue->current_thread_id[subframe_rx]][1].p_time/(cpuf*1000.0));
LOG_DEBUG_END


        if (pthread_mutex_lock(&proc->mutex_slot1_dl_processing) != 0) {
            LOG_E( PHY, "[SCHED][UE] error locking mutex for UE RXTX\n" );
            exit_fun("noting to add");
        }
        proc->instance_cnt_slot1_dl_processing--;
        if (pthread_mutex_unlock(&proc->mutex_slot1_dl_processing) != 0) {
            LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE FEP Slo1\n" );
            exit_fun("noting to add");
        }
    }
    // thread finished
        free(arg);
        return &UE_dl_slot1_processing_retval;
}
#endif

#ifdef UE_SLOT_PARALLELISATION
int phy_procedures_slot_parallelization_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,
        uint8_t abstraction_flag,uint8_t do_pdcch_flag,runmode_t mode)  {

    int l,l2;
    int pmch_flag=0;
    int frame_rx = proc->frame_rx;
    int subframe_rx = proc->subframe_rx;
    uint8_t pilot0;
    uint8_t pilot1;
    uint8_t slot0;
    uint8_t slot1;
    uint8_t first_ofdm_sym;

    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX, VCD_FUNCTION_IN);


    T(T_UE_PHY_DL_TICK, T_INT(ue->Mod_id), T_INT(frame_rx%1024), T_INT(subframe_rx));

    T(T_UE_PHY_INPUT_SIGNAL, T_INT(ue->Mod_id), T_INT(frame_rx%1024), T_INT(subframe_rx), T_INT(0),
            T_BUFFER(&ue->common_vars.rxdata[0][subframe_rx*ue->frame_parms.samples_per_tti],
                    ue->frame_parms.samples_per_tti * 4));


    // start timers
LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
    LOG_D(PHY," ****** start RX-Chain for AbsSubframe %d.%d ******  \n", frame_rx%1024, subframe_rx);
LOG_DEBUG_END

LOG_DEBUG_BEGIN(UE_TIMING)
    start_meas(&ue->phy_proc_rx[ue->current_thread_id[subframe_rx]]);
    start_meas(&ue->ue_front_end_stat[ue->current_thread_id[subframe_rx]]);
LOG_DEBUG_END

    pmch_flag = is_pmch_subframe(frame_rx,subframe_rx,&ue->frame_parms) ? 1 : 0;

    if (do_pdcch_flag) {
        // deactivate reception until we scan pdcch
        if (ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0])
            ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0]->active = 0;
        if (ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][1])
            ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][1]->active = 0;

        if (ue->dlsch_SI[eNB_id])
            ue->dlsch_SI[eNB_id]->active = 0;
        if (ue->dlsch_p[eNB_id])
            ue->dlsch_p[eNB_id]->active = 0;
        if (ue->dlsch_ra[eNB_id])
            ue->dlsch_ra[eNB_id]->active = 0;
    }

LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
    LOG_D(PHY,"[UE %d] Frame %d subframe %d: Doing phy_procedures_UE_RX\n",
                    ue->Mod_id,frame_rx, subframe_rx);
LOG_DEBUG_END




    if (subframe_select(&ue->frame_parms,subframe_rx) == SF_S) { // S-subframe, do first 5 symbols only
        l2 = 5;
    } else if (pmch_flag == 1) { // do first 2 symbols only
        l2 = 1;
    } else { // normal subframe, last symbol to be processed is the first of the second slot
        l2 = (ue->frame_parms.symbols_per_tti/2)-1;
    }

    int prev_subframe_rx = (subframe_rx - 1)<0? 9: (subframe_rx - 1);
    if (subframe_select(&ue->frame_parms,prev_subframe_rx) != SF_DL) {
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        // RX processing of symbols l=0...l2
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        first_ofdm_sym = 0;
    } else {
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        // RX processing of symbols l=1...l2 (l=0 is done in last scheduling epoch)
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        first_ofdm_sym = 1;
    }
    slot0  = (subframe_rx<<1);
    slot1  = (subframe_rx<<1) + 1;
    pilot0 = 0;
    if (ue->frame_parms.Ncp == 0) {  // normal prefix
        pilot1 = 4;
    } else { // extended prefix
        pilot1 = 3;
    }

    //LOG_I(PHY,"Set available channelEst to 0 AbsSubframe %d.%d \n",frame_rx,subframe_rx);
    //LOG_I(PHY,"Set available llrs slot1 to 0 AbsSubframe %d.%d \n",frame_rx,subframe_rx);
    //LOG_I(PHY,"Set available dci info slot0 to 0 AbsSubframe %d.%d \n",frame_rx,subframe_rx);
    proc->chan_est_pilot0_slot1_available=0;
    proc->llr_slot1_available=0;
    proc->dci_slot0_available=0;
    proc->first_symbol_available=0;
    proc->chan_est_slot1_available=0;
    //proc->channel_level=0;

    if (pthread_mutex_lock(&proc->mutex_slot1_dl_processing) != 0) {
        LOG_E( PHY, "[SCHED][UE %d][Slot0] error locking mutex for UE slot1 dl processing\n",ue->Mod_id );
        exit_fun("nothing to add");
    }

    proc->instance_cnt_slot1_dl_processing++;
    if (proc->instance_cnt_slot1_dl_processing == 0)
    {
    LOG_D(PHY,"unblock slot1 dl processing thread blocked on instance_cnt_slot1_dl_processing : %d \n", proc->instance_cnt_slot1_dl_processing );
        if (pthread_cond_signal(&proc->cond_slot1_dl_processing) != 0) {
            LOG_E( PHY, "[SCHED][UE %d][Slot0] ERROR pthread_cond_signal for UE slot1 processing thread\n", ue->Mod_id);
            exit_fun("nothing to add");
        }
        if (pthread_mutex_unlock(&proc->mutex_slot1_dl_processing) != 0) {
            LOG_E( PHY, "[SCHED][UE %d][Slot0] error unlocking mutex for UE slot1 dl processing \n",ue->Mod_id );
            exit_fun("nothing to add");
        }

    } else
    {
        LOG_E( PHY, "[SCHED][UE %d] UE RX thread busy (IC %d)!!\n", ue->Mod_id, proc->instance_cnt_slot1_dl_processing);
        if (proc->instance_cnt_slot1_dl_processing > 2)
            exit_fun("instance_cnt_slot1_dl_processing > 2");
    }
    //AssertFatal(pthread_cond_signal(&proc->cond_slot1_dl_processing) ==0 ,"");
    AssertFatal(pthread_mutex_unlock(&proc->mutex_slot1_dl_processing) ==0,"");


    /**** Slot0 FE Processing ****/
    // I- start main thread for FFT/ChanEst symbol: 0/1 --> 7
LOG_DEBUG_BEGIN(UE_TIMING)
    start_meas(&ue->ue_front_end_per_slot_stat[ue->current_thread_id[subframe_rx]][0]);
LOG_DEBUG_END
    // 1- perform FFT for pilot ofdm symbols first (ofdmSym7 ofdmSym4 or (ofdmSym6 ofdmSym3))
    //printf("AbsSubframe %d.%d FFT slot %d, symbol %d\n", frame_rx,subframe_rx,slot1,pilot0);
    front_end_fft(ue,
            pilot0,
            slot1,
            0,
            0);
    //printf("AbsSubframe %d.%d FFT slot %d, symbol %d\n", frame_rx,subframe_rx,slot0,pilot1);
    front_end_fft(ue,
            pilot1,
            slot0,
            0,
            0);
    //printf("AbsSubframe %d.%d ChanEst slot %d, symbol %d\n", frame_rx,subframe_rx,slot0,pilot1);
    front_end_chanEst(ue,
            pilot1,
            slot0,
            0);
    //printf("AbsSubframe %d.%d ChanEst slot %d, symbol %d\n", frame_rx,subframe_rx,slot1,pilot0);
    front_end_chanEst(ue,
            pilot0,
            slot1,
            0);
    proc->chan_est_pilot0_slot1_available = 1;
    //printf("Set available channelEst to 1 AbsSubframe %d.%d \n",frame_rx,subframe_rx);

    // 2- perform FFT for other ofdm symbols other than pilots
    for (l=first_ofdm_sym; l<=l2; l++)
    {
        if( (l != pilot0) && (l != pilot1))
        {
            //printf("AbsSubframe %d.%d FFT slot %d, symbol %d\n", frame_rx,subframe_rx,slot0,l);
LOG_DEBUG_BEGIN(UE_TIMING)
            start_meas(&ue->ofdm_demod_stats);
LOG_DEBUG_END
            VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP, VCD_FUNCTION_IN);
            front_end_fft(ue,
                    l,
                    slot0,
                    0,
                    0);
            VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP, VCD_FUNCTION_OUT);
LOG_DEBUG_BEGIN(UE_TIMING)
            stop_meas(&ue->ofdm_demod_stats);
LOG_DEBUG_END
        }
    } // for l=1..l2

    // 3- perform Channel Estimation for slot0
    for (l=first_ofdm_sym; l<=l2; l++)
    {
        if( (l != pilot0) && (l != pilot1))
        {
            //printf("AbsSubframe %d.%d ChanEst slot %d, symbol %d\n", frame_rx,subframe_rx,slot0,l);
            front_end_chanEst(ue,
                    l,
                    slot0,
                    0);
        }
        ue_measurement_procedures(l-1,ue,proc,eNB_id,(subframe_rx<<1),abstraction_flag,mode);
    }

    if (do_pdcch_flag) {
LOG_DEBUG_BEGIN(UE_TIMING)
        start_meas(&ue->pdcch_procedures_stat[ue->current_thread_id[subframe_rx]]);
LOG_DEBUG_END
        if (ue_pdcch_procedures(eNB_id,ue,proc,abstraction_flag) == -1) {
            LOG_E(PHY,"[UE  %d] Frame %d, subframe %d: Error in pdcch procedures\n",ue->Mod_id,frame_rx,subframe_rx);
LOG_DEBUG_BEGIN(UE_TIMING)
            LOG_UI(PHY, "[AbsSFN %d.%d] Slot0: PDCCH %5.2f \n",frame_rx,subframe_rx,ue->pdcch_procedures_stat[ue->current_thread_id[subframe_rx]].p_time/(cpuf*1000.0));
LOG_DEBUG_END

            //proc->dci_slot0_available = 1;
            return(-1);
        }
        //proc->dci_slot0_available=1;
LOG_DEBUG_BEGIN(UE_TIMING)
        stop_meas(&ue->pdcch_procedures_stat[ue->current_thread_id[subframe_rx]]);
        LOG_UI(PHY, "[AbsSFN %d.%d] Slot0: PDCCH %5.2f \n",frame_rx,subframe_rx,ue->pdcch_procedures_stat[ue->current_thread_id[subframe_rx]].p_time/(cpuf*1000.0));
LOG_DEBUG_END
    }

    //printf("num_pdcch_symbols %d\n",ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->num_pdcch_symbols);

    // first slot has been processed (FFTs + Channel Estimation, PCFICH/PHICH/PDCCH)
LOG_DEBUG_BEGIN(UE_TIMING)
    stop_meas(&ue->ue_front_end_per_slot_stat[ue->current_thread_id[subframe_rx]][0]);
    LOG_UI(PHY, "[AbsSFN %d.%d] Slot0: FFT + Channel Estimate + PCFICH/PHICH/PDCCH %5.2f \n",frame_rx,subframe_rx,ue->ue_front_end_per_slot_stat[ue->current_thread_id[subframe_rx]][0].p_time/(cpuf*1000.0));
LOG_DEBUG_END

    //wait until slot1 FE is done
    uint32_t wait = 0;
    while(proc->chan_est_slot1_available == 0)
    {
        usleep(1);
        wait++;
    }

LOG_DEBUG_BEGIN(UE_TIMING)
    stop_meas(&ue->ue_front_end_stat[ue->current_thread_id[subframe_rx]]);
    LOG_UI(PHY, "[AbsSFN %d.%d] FULL FE Processing %5.2f \n",frame_rx,subframe_rx,ue->ue_front_end_per_slot_stat[ue->current_thread_id[subframe_rx]][0].p_time/(cpuf*1000.0));
LOG_DEBUG_END
    /**** End Subframe FE Processing ****/


    //Trigger LLR parallelized for Slot 1
    //proc->dci_slot0_available=1;
    //printf("Set available dci slot0 to 1 AbsSubframe %d.%d \n",frame_rx%1024,subframe_rx);

    /**** Pdsch Procedure Slot0 ****/
    // start main thread for Pdsch Procedure (slot0)
    // do procedures for C-RNTI
    //printf("AbsSubframe %d.%d Pdsch Procedure (slot0)\n",frame_rx%1024,subframe_rx);
    //printf("AbsSubframe %d.%d Pdsch Procedure PDSCH Active %d \n",frame_rx%1024,subframe_rx, ue->dlsch[ue->current_thread_id[subframe_rx]][0][0]->active);

LOG_DEBUG_BEGIN(UE_TIMING)
    start_meas(&ue->pdsch_procedures_stat[ue->current_thread_id[subframe_rx]]);
LOG_DEBUG_END

LOG_DEBUG_BEGIN(UE_TIMING)
    start_meas(&ue->pdsch_procedures_per_slot_stat[ue->current_thread_id[subframe_rx]][0]);
LOG_DEBUG_END
    if (ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0]->active == 1) {
        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_IN);
        ue_pdsch_procedures(ue,
                proc,
                eNB_id,
                PDSCH,
                ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0],
                NULL,
                ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->num_pdcch_symbols,
                (ue->frame_parms.symbols_per_tti>>1)-1,
                abstraction_flag);

        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_OUT);
    }

    // do procedures for SI-RNTI
    if ((ue->dlsch_SI[eNB_id]) && (ue->dlsch_SI[eNB_id]->active == 1)) {
        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_SI, VCD_FUNCTION_IN);
        ue_pdsch_procedures(ue,
                proc,
                eNB_id,
                SI_PDSCH,
                ue->dlsch_SI[eNB_id],
                NULL,
                ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->num_pdcch_symbols,
                (ue->frame_parms.symbols_per_tti>>1)-1,
                abstraction_flag);
        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_SI, VCD_FUNCTION_OUT);
    }

    // do procedures for SI-RNTI
    if ((ue->dlsch_p[eNB_id]) && (ue->dlsch_p[eNB_id]->active == 1)) {
        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_P, VCD_FUNCTION_IN);
        ue_pdsch_procedures(ue,
                proc,
                eNB_id,
                P_PDSCH,
                ue->dlsch_p[eNB_id],
                NULL,
                ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->num_pdcch_symbols,
                (ue->frame_parms.symbols_per_tti>>1)-1,
                abstraction_flag);
        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_P, VCD_FUNCTION_OUT);
    }

    // do procedures for RA-RNTI
    if ((ue->dlsch_ra[eNB_id]) && (ue->dlsch_ra[eNB_id]->active == 1)) {
        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_RA, VCD_FUNCTION_IN);
        ue_pdsch_procedures(ue,
                proc,
                eNB_id,
                RA_PDSCH,
                ue->dlsch_ra[eNB_id],
                NULL,
                ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->num_pdcch_symbols,
                (ue->frame_parms.symbols_per_tti>>1)-1,
                abstraction_flag);
        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_RA, VCD_FUNCTION_OUT);
    }

    // LLR linear
    proc->dci_slot0_available=1;
    //printf("Set available dci slot0 to 1 AbsSubframe %d.%d \n",frame_rx%1024,subframe_rx);


LOG_DEBUG_BEGIN(UE_TIMING)
    stop_meas(&ue->pdsch_procedures_per_slot_stat[ue->current_thread_id[subframe_rx]][0]);
    LOG_UI(PHY, "[AbsSFN %d.%d] Slot0: LLR Computation %5.2f \n",frame_rx,subframe_rx,ue->pdsch_procedures_per_slot_stat[ue->current_thread_id[subframe_rx]][0].p_time/(cpuf*1000.0));
LOG_DEBUG_END


    //wait until LLR Slot1 is done
    wait = 0;
    while(proc->llr_slot1_available == 0)
    {
        usleep(1);
        wait++;
    }



LOG_DEBUG_BEGIN(UE_TIMING)
    stop_meas(&ue->pdsch_procedures_stat[ue->current_thread_id[subframe_rx]]);
    LOG_UI(PHY, "[AbsSFN %d.%d] Full LLR Computation %5.2f \n",frame_rx,subframe_rx,ue->pdsch_procedures_stat[ue->current_thread_id[subframe_rx]].p_time/(cpuf*1000.0));
LOG_DEBUG_END


    //=====================================================================//
LOG_DEBUG_BEGIN(UE_TIMING)
    start_meas(&ue->dlsch_procedures_stat[ue->current_thread_id[subframe_rx]]);
LOG_DEBUG_END

    LOG_D(PHY,"==> Start Turbo Decoder active dlsch %d SI %d RA %d \n",ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0]->active,
    		ue->dlsch_SI[eNB_id]->active,
			//ue->dlsch_p[eNB_id]->active,
			ue->dlsch_ra[eNB_id]->active);
    // Start Turbo decoder
    if (ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0]->active == 1) {
        //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_IN);
        ue_dlsch_procedures(ue,
                proc,
                eNB_id,
                PDSCH,
                ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0],
                ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][1],
                &ue->dlsch_errors[eNB_id],
                mode,
                abstraction_flag);
        //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_OUT);
    }

    // do procedures for SI-RNTI
    if ((ue->dlsch_SI[eNB_id]) && (ue->dlsch_SI[eNB_id]->active == 1)) {
        ue_dlsch_procedures(ue,
                proc,
                eNB_id,
                SI_PDSCH,
                ue->dlsch_SI[eNB_id],
                NULL,
                &ue->dlsch_SI_errors[eNB_id],
                mode,
                abstraction_flag);
        ue->dlsch_SI[eNB_id]->active = 0;
    }

    // do procedures for P-RNTI
    if ((ue->dlsch_p[eNB_id]) && (ue->dlsch_p[eNB_id]->active == 1)) {
        ue_dlsch_procedures(ue,
                proc,
                eNB_id,
                P_PDSCH,
                ue->dlsch_p[eNB_id],
                NULL,
                &ue->dlsch_p_errors[eNB_id],
                mode,
                abstraction_flag);
        ue->dlsch_p[eNB_id]->active = 0;
    }
    // do procedures for RA-RNTI
    if ((ue->dlsch_ra[eNB_id]) && (ue->dlsch_ra[eNB_id]->active == 1)) {
        ue_dlsch_procedures(ue,
                proc,
                eNB_id,
                RA_PDSCH,
                ue->dlsch_ra[eNB_id],
                NULL,
                &ue->dlsch_ra_errors[eNB_id],
                mode,
                abstraction_flag);
        ue->dlsch_ra[eNB_id]->active = 0;
    }

LOG_DEBUG_BEGIN(UE_TIMING)
        stop_meas(&ue->dlsch_procedures_stat[ue->current_thread_id[subframe_rx]]);
        LOG_UI(PHY, "[AbsSFN %d.%d] Channel Decoder: %5.2f \n",frame_rx,subframe_rx,ue->dlsch_procedures_stat[ue->current_thread_id[subframe_rx]].p_time/(cpuf*1000.0));
LOG_DEBUG_END

        // duplicate harq structure
        uint8_t          current_harq_pid        = ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0]->current_harq_pid;
        LTE_DL_UE_HARQ_t *current_harq_processes = ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0]->harq_processes[current_harq_pid];
        harq_status_t    *current_harq_ack       = &ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0]->harq_ack[subframe_rx];

        // For Debug parallelisation
        //if (current_harq_ack->ack == 0) {
            //printf("[slot0 dl processing][End of Channel Decoding] AbsSubframe %d.%d Decode Fail for HarqId%d Round%d\n",frame_rx,subframe_rx,current_harq_pid,current_harq_processes->round);
        //}
        for(uint8_t rx_th_idx=1; rx_th_idx<RX_NB_TH; rx_th_idx++)
        {
            LTE_DL_UE_HARQ_t *harq_processes_dest  = ue->dlsch[ue->current_thread_id[(subframe_rx+rx_th_idx)%10]][eNB_id][0]->harq_processes[current_harq_pid];
            harq_status_t    *harq_ack_dest        = &ue->dlsch[ue->current_thread_id[(subframe_rx+rx_th_idx)%10]][eNB_id][0]->harq_ack[subframe_rx];

            copy_harq_proc_struct(harq_processes_dest, current_harq_processes);
            copy_ack_struct(harq_ack_dest, current_harq_ack);

        }
    /*
    LTE_DL_UE_HARQ_t *harq_processes_dest    = ue->dlsch[(subframe_rx+1)%RX_NB_TH][eNB_id][0]->harq_processes[current_harq_pid];
    LTE_DL_UE_HARQ_t *harq_processes_dest1    = ue->dlsch[(subframe_rx+2)%RX_NB_TH][eNB_id][0]->harq_processes[current_harq_pid];

    harq_status_t *current_harq_ack = &ue->dlsch[subframe_rx%RX_NB_TH][eNB_id][0]->harq_ack[subframe_rx];
    harq_status_t *harq_ack_dest    = &ue->dlsch[(subframe_rx+1)%RX_NB_TH][eNB_id][0]->harq_ack[subframe_rx];
    harq_status_t *harq_ack_dest1    = &ue->dlsch[(subframe_rx+2)%RX_NB_TH][eNB_id][0]->harq_ack[subframe_rx];

    copy_harq_proc_struct(harq_processes_dest, current_harq_processes);
    copy_ack_struct(harq_ack_dest, current_harq_ack);

    copy_harq_proc_struct(harq_processes_dest1, current_harq_processes);
    copy_ack_struct(harq_ack_dest1, current_harq_ack);
    */
    if (subframe_rx==9) {
        if (frame_rx % 10 == 0) {
            if ((ue->dlsch_received[eNB_id] - ue->dlsch_received_last[eNB_id]) != 0)
                ue->dlsch_fer[eNB_id] = (100*(ue->dlsch_errors[eNB_id] - ue->dlsch_errors_last[eNB_id]))/(ue->dlsch_received[eNB_id] - ue->dlsch_received_last[eNB_id]);

            ue->dlsch_errors_last[eNB_id] = ue->dlsch_errors[eNB_id];
            ue->dlsch_received_last[eNB_id] = ue->dlsch_received[eNB_id];
        }


        ue->bitrate[eNB_id] = (ue->total_TBS[eNB_id] - ue->total_TBS_last[eNB_id])*100;
        ue->total_TBS_last[eNB_id] = ue->total_TBS[eNB_id];
        LOG_D(PHY,"[UE %d] Calculating bitrate Frame %d: total_TBS = %d, total_TBS_last = %d, bitrate %f kbits\n",
                ue->Mod_id,frame_rx,ue->total_TBS[eNB_id],
                ue->total_TBS_last[eNB_id],(float) ue->bitrate[eNB_id]/1000.0);

#if UE_AUTOTEST_TRACE
        if ((frame_rx % 100 == 0)) {
            LOG_I(PHY,"[UE  %d] AUTOTEST Metric : UE_DLSCH_BITRATE = %5.2f kbps (frame = %d) \n", ue->Mod_id, (float) ue->bitrate[eNB_id]/1000.0, frame_rx);
        }
#endif

    }

    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX, VCD_FUNCTION_OUT);

LOG_DEBUG_BEGIN(UE_TIMING)
    stop_meas(&ue->phy_proc_rx[ue->current_thread_id[subframe_rx]]);
    LOG_UI(PHY, "------FULL RX PROC [AbsSFN %d.%d]: %5.2f ------\n",frame_rx,subframe_rx,ue->phy_proc_rx[ue->current_thread_id[subframe_rx]].p_time/(cpuf*1000.0));
LOG_DEBUG_END

    LOG_D(PHY," ****** end RX-Chain  for AbsSubframe %d.%d ******  \n", frame_rx%1024, subframe_rx);
    return (0);
}
#endif /*UE_SLOT_PARALLELISATION */


void phy_procedures_UE_SL_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc) {


}

int phy_procedures_UE_RX(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,
			 uint8_t abstraction_flag,uint8_t do_pdcch_flag,runmode_t mode) {

  int l,l2;
  int pilot1;
  int pmch_flag=0;
  int frame_rx = proc->frame_rx;
  int subframe_rx = proc->subframe_rx;

  uint8_t next1_thread_id = ue->current_thread_id[subframe_rx]== (RX_NB_TH-1) ? 0:(ue->current_thread_id[subframe_rx]+1);
  uint8_t next2_thread_id = next1_thread_id== (RX_NB_TH-1) ? 0:(next1_thread_id+1);

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX, VCD_FUNCTION_IN);


  T(T_UE_PHY_DL_TICK, T_INT(ue->Mod_id), T_INT(frame_rx%1024), T_INT(subframe_rx));

  T(T_UE_PHY_INPUT_SIGNAL, T_INT(ue->Mod_id), T_INT(frame_rx%1024), T_INT(subframe_rx), T_INT(0),
    T_BUFFER(&ue->common_vars.rxdata[0][subframe_rx*ue->frame_parms.samples_per_tti],
             ue->frame_parms.samples_per_tti * 4));


  // start timers
LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
  LOG_I(PHY," ****** start RX-Chain for AbsSubframe %d.%d ******  \n", frame_rx%1024, subframe_rx);
LOG_DEBUG_END

LOG_DEBUG_BEGIN(UE_TIMING)
  start_meas(&ue->phy_proc_rx[ue->current_thread_id[subframe_rx]]);
  start_meas(&ue->generic_stat);
LOG_DEBUG_END

  pmch_flag = is_pmch_subframe(frame_rx,subframe_rx,&ue->frame_parms) ? 1 : 0;

  if (do_pdcch_flag) {
  // deactivate reception until we scan pdcch
  if (ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0])
    ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0]->active = 0;
  if (ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][1])
    ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][1]->active = 0;

  if (ue->dlsch_SI[eNB_id])
    ue->dlsch_SI[eNB_id]->active = 0;
  if (ue->dlsch_p[eNB_id])
    ue->dlsch_p[eNB_id]->active = 0;
  if (ue->dlsch_ra[eNB_id])
    ue->dlsch_ra[eNB_id]->active = 0;
  }

LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
  LOG_D(PHY,"[UE %d] Frame %d subframe %d: Doing phy_procedures_UE_RX\n",
  ue->Mod_id,frame_rx, subframe_rx);
LOG_DEBUG_END

  if (ue->frame_parms.Ncp == 0) {  // normal prefix
    pilot1 = 4;
  } else { // extended prefix
    pilot1 = 3;
  }


  if (subframe_select(&ue->frame_parms,subframe_rx) == SF_S) { // S-subframe, do first 5 symbols only
    l2 = 5;
  } else if (pmch_flag == 1) { // do first 2 symbols only
    l2 = 1;
  } else { // normal subframe, last symbol to be processed is the first of the second slot
    l2 = (ue->frame_parms.symbols_per_tti/2)-1;
  }

  int prev_subframe_rx = (subframe_rx - 1)<0? 9: (subframe_rx - 1);
  if (subframe_select(&ue->frame_parms,prev_subframe_rx) != SF_DL) {
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    // RX processing of symbols l=0...l2
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    l=0;
  } else {
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    // RX processing of symbols l=1...l2 (l=0 is done in last scheduling epoch)
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    l=1;
  }

  LOG_D(PHY," ------ slot 0 Processing: AbsSubframe %d.%d ------  \n", frame_rx%1024, subframe_rx);
  LOG_D(PHY," ------  --> FFT/ChannelEst/PDCCH slot 0: AbsSubframe %d.%d ------  \n", frame_rx%1024, subframe_rx);
  for (; l<=l2; l++) {
    if (abstraction_flag == 0) {
LOG_DEBUG_BEGIN(UE_TIMING)
        start_meas(&ue->ofdm_demod_stats);
LOG_DEBUG_END
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP, VCD_FUNCTION_IN);
      slot_fep(ue,
         l,
         (subframe_rx<<1),
         0,
         0,
         0);
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP, VCD_FUNCTION_OUT);
LOG_DEBUG_BEGIN(UE_TIMING)
      stop_meas(&ue->ofdm_demod_stats);
LOG_DEBUG_END
    }

    ue_measurement_procedures(l-1,ue,proc,eNB_id,(subframe_rx<<1),abstraction_flag,mode);

    if (do_pdcch_flag) {
      if ((l==pilot1) ||
	  ((pmch_flag==1)&(l==l2)))  {
	LOG_D(PHY,"[UE  %d] Frame %d: Calling pdcch procedures (eNB %d)\n",ue->Mod_id,frame_rx,eNB_id);

	//start_meas(&ue->rx_pdcch_stats[ue->current_thread_id[subframe_rx]]);
	if (ue_pdcch_procedures(eNB_id,ue,proc,abstraction_flag) == -1) {
	  LOG_E(PHY,"[UE  %d] Frame %d, subframe %d: Error in pdcch procedures\n",ue->Mod_id,frame_rx,subframe_rx);
	  return(-1);
	}
	//stop_meas(&ue->rx_pdcch_stats[ue->current_thread_id[subframe_rx]]);
    //printf("subframe %d n_pdcch_sym %d pdcch procedures  %5.3f \n",
    //        subframe_rx, ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->num_pdcch_symbols,
    //     (ue->rx_pdcch_stats[ue->current_thread_id[subframe_rx]].p_time)/(cpuf*1000.0));
	LOG_D(PHY,"num_pdcch_symbols %d\n",ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->num_pdcch_symbols);
      }
    }

  } // for l=1..l2
  ue_measurement_procedures(l-1,ue,proc,eNB_id,(subframe_rx<<1),abstraction_flag,mode);

  LOG_D(PHY," ------  end FFT/ChannelEst/PDCCH slot 0: AbsSubframe %d.%d ------  \n", frame_rx%1024, subframe_rx);
    // If this is PMCH, call procedures and return
  if (pmch_flag == 1) {
    ue_pmch_procedures(ue,proc,eNB_id,abstraction_flag);
    return 0;
  }

  slot_fep(ue,
     0,
     1+(subframe_rx<<1),
     0,
     0,
     0);

  // first slot has been processed (FFTs + Channel Estimation, PCFICH/PHICH/PDCCH)
LOG_DEBUG_BEGIN(UE_TIMING)
  stop_meas(&ue->generic_stat);
  LOG_UI(PHY, "[SFN %d] Slot0: FFT + Channel Estimate + PCFICH/PHICH/PDCCH %5.2f \n",subframe_rx,ue->generic_stat.p_time/(cpuf*1000.0));
LOG_DEBUG_END


  LOG_D(PHY," ------ --> PDSCH ChannelComp/LLR slot 0: AbsSubframe %d.%d ------  \n", frame_rx%1024, subframe_rx);
LOG_DEBUG_BEGIN(UE_TIMING)
  start_meas(&ue->generic_stat);
LOG_DEBUG_END
  // do procedures for C-RNTI
  if (ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0]->active == 1) {
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_IN);
    ue_pdsch_procedures(ue,
			proc,
			eNB_id,
			PDSCH,
			ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0],
			NULL,
			ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->num_pdcch_symbols,
			ue->frame_parms.symbols_per_tti>>1,
			abstraction_flag);

    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_OUT);
  }

  LOG_D(PHY," ------ end PDSCH ChannelComp/LLR slot 0: AbsSubframe %d.%d ------  \n", frame_rx%1024, subframe_rx);
  // do procedures for SI-RNTI
  if ((ue->dlsch_SI[eNB_id]) && (ue->dlsch_SI[eNB_id]->active == 1)) {
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_SI, VCD_FUNCTION_IN);
    ue_pdsch_procedures(ue,

			proc,
			eNB_id,
			SI_PDSCH,
			ue->dlsch_SI[eNB_id],
			NULL,
			ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->num_pdcch_symbols,
			ue->frame_parms.symbols_per_tti>>1,
			abstraction_flag);
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_SI, VCD_FUNCTION_OUT);
  }

  // do procedures for SI-RNTI
  if ((ue->dlsch_p[eNB_id]) && (ue->dlsch_p[eNB_id]->active == 1)) {
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_P, VCD_FUNCTION_IN);
    ue_pdsch_procedures(ue,
			proc,
			eNB_id,
			P_PDSCH,
			ue->dlsch_p[eNB_id],
			NULL,
			ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->num_pdcch_symbols,
			ue->frame_parms.symbols_per_tti>>1,
			abstraction_flag);
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_P, VCD_FUNCTION_OUT);
  }

  // do procedures for RA-RNTI
  if ((ue->dlsch_ra[eNB_id]) && (ue->dlsch_ra[eNB_id]->active == 1)) {
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_RA, VCD_FUNCTION_IN);
    ue_pdsch_procedures(ue,
			proc,
			eNB_id,
			RA_PDSCH,
			ue->dlsch_ra[eNB_id],
			NULL,
			ue->pdcch_vars[ue->current_thread_id[subframe_rx]][eNB_id]->num_pdcch_symbols,
			ue->frame_parms.symbols_per_tti>>1,
			abstraction_flag);
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_RA, VCD_FUNCTION_OUT);
  }

  LOG_D(PHY," ------ slot 1 Processing: AbsSubframe %d.%d ------  \n", frame_rx%1024, subframe_rx);
  LOG_D(PHY," ------  --> FFT/ChannelEst/PDCCH slot 1: AbsSubframe %d.%d ------  \n", frame_rx%1024, subframe_rx);

  if (subframe_select(&ue->frame_parms,subframe_rx) != SF_S) {  // do front-end processing for second slot, and first symbol of next subframe
    for (l=1; l<ue->frame_parms.symbols_per_tti>>1; l++) {
      if (abstraction_flag == 0) {
LOG_DEBUG_BEGIN(UE_TIMING)
          start_meas(&ue->ofdm_demod_stats);
LOG_DEBUG_END
	VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP, VCD_FUNCTION_IN);
	slot_fep(ue,
		 l,
		 1+(subframe_rx<<1),
		 0,
		 0,
		 0);
	VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP, VCD_FUNCTION_OUT);
LOG_DEBUG_BEGIN(UE_TIMING)
    stop_meas(&ue->ofdm_demod_stats);
LOG_DEBUG_END
      }

      ue_measurement_procedures(l-1,ue,proc,eNB_id,1+(subframe_rx<<1),abstraction_flag,mode);

    } // for l=1..l2

    // do first symbol of next downlink subframe for channel estimation
    int next_subframe_rx = (1+subframe_rx)%10;
    if (subframe_select(&ue->frame_parms,next_subframe_rx) != SF_UL)
    {
      slot_fep(ue,
         0,
         (next_subframe_rx<<1),
         0,
         0,
         0);
    }
  } // not an S-subframe
LOG_DEBUG_BEGIN(UE_TIMING)
  stop_meas(&ue->generic_stat);
  LOG_UI(PHY, "[SFN %d] Slot1: FFT + Channel Estimate + Pdsch Proc Slot0 %5.2f \n",subframe_rx,ue->generic_stat.p_time/(cpuf*1000.0));
LOG_DEBUG_END

  LOG_D(PHY," ------  end FFT/ChannelEst/PDCCH slot 1: AbsSubframe %d.%d ------  \n", frame_rx%1024, subframe_rx);

  if ( (subframe_rx == 0) && (ue->decode_MIB == 1))
  {
    ue_pbch_procedures(eNB_id,ue,proc,abstraction_flag);
  }



  // do procedures for C-RNTI
  LOG_D(PHY," ------ --> PDSCH ChannelComp/LLR slot 0: AbsSubframe %d.%d ------  \n", frame_rx%1024, subframe_rx);
  if (ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0]->active == 1) {
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_IN);
LOG_DEBUG_BEGIN(UE_TIMING)
    start_meas(&ue->pdsch_procedures_stat[ue->current_thread_id[subframe_rx]]);
LOG_DEBUG_END
    ue_pdsch_procedures(ue,
			proc,
			eNB_id,
			PDSCH,
			ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0],
			NULL,
			1+(ue->frame_parms.symbols_per_tti>>1),
			ue->frame_parms.symbols_per_tti-1,
			abstraction_flag);
    LOG_D(PHY," ------ end PDSCH ChannelComp/LLR slot 0: AbsSubframe %d.%d ------  \n", frame_rx%1024, subframe_rx);
    LOG_D(PHY," ------ --> PDSCH Turbo Decoder slot 0/1: AbsSubframe %d.%d ------  \n", frame_rx%1024, subframe_rx);
LOG_DEBUG_BEGIN(UE_TIMING)
    stop_meas(&ue->pdsch_procedures_stat[ue->current_thread_id[subframe_rx]]);
    start_meas(&ue->dlsch_procedures_stat[ue->current_thread_id[subframe_rx]]);
LOG_DEBUG_END
    ue_dlsch_procedures(ue,
			proc,
			eNB_id,
			PDSCH,
			ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0],
			ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][1],
			&ue->dlsch_errors[eNB_id],
			mode,
			abstraction_flag);
LOG_DEBUG_BEGIN(UE_TIMING)
    stop_meas(&ue->dlsch_procedures_stat[ue->current_thread_id[subframe_rx]]);
    LOG_UI(PHY, "[SFN %d] Slot1:       Pdsch Proc %5.2f\n",subframe_rx,ue->pdsch_procedures_stat[ue->current_thread_id[subframe_rx]].p_time/(cpuf*1000.0));
    LOG_UI(PHY, "[SFN %d] Slot0 Slot1: Dlsch Proc %5.2f\n",subframe_rx,ue->dlsch_procedures_stat[ue->current_thread_id[subframe_rx]].p_time/(cpuf*1000.0));
LOG_DEBUG_END

    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_OUT);

  }
LOG_DEBUG_BEGIN(UE_TIMING)
  start_meas(&ue->generic_stat);
LOG_DEBUG_END

LOG_M_BEGIN(DEBUG_UE_PHYPROC)
  if(subframe_rx==5 &&  ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0]->harq_processes[ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0]->current_harq_pid]->nb_rb > 20){
       //LOG_M("decoder_llr.m","decllr",dlsch_llr,G,1,0);
       //LOG_M("llr.m","llr",  &ue->pdsch_vars[eNB_id]->llr[0][0],(14*nb_rb*12*dlsch1_harq->Qm) - 4*(nb_rb*4*dlsch1_harq->Qm),1,0);

       LOG_M("rxdataF0_current.m"    , "rxdataF0", &ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe_rx]].rxdataF[0][0],14*ue->frame_parms.ofdm_symbol_size,1,1);
       //LOG_M("rxdataF0_previous.m"    , "rxdataF0_prev_sss", &ue->common_vars.common_vars_rx_data_per_thread[next_thread_id].rxdataF[0][0],14*ue->frame_parms.ofdm_symbol_size,1,1);

       //LOG_M("rxdataF0_previous.m"    , "rxdataF0_prev", &ue->common_vars.common_vars_rx_data_per_thread[next_thread_id].rxdataF[0][0],14*ue->frame_parms.ofdm_symbol_size,1,1);

       LOG_M("dl_ch_estimates.m", "dl_ch_estimates_sfn5", &ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe_rx]].dl_ch_estimates[0][0][0],14*ue->frame_parms.ofdm_symbol_size,1,1);
       LOG_M("dl_ch_estimates_ext.m", "dl_ch_estimatesExt_sfn5", &ue->pdsch_vars[ue->current_thread_id[subframe_rx]][0]->dl_ch_estimates_ext[0][0],14*ue->frame_parms.N_RB_DL*12,1,1);
       LOG_M("rxdataF_comp00.m","rxdataF_comp00",         &ue->pdsch_vars[ue->current_thread_id[subframe_rx]][0]->rxdataF_comp0[0][0],14*ue->frame_parms.N_RB_DL*12,1,1);
       //LOG_M("magDLFirst.m", "magDLFirst", &phy_vars_ue->pdsch_vars[ue->current_thread_id[subframe_rx]][0]->dl_ch_mag0[0][0],14*frame_parms->N_RB_DL*12,1,1);
       //LOG_M("magDLSecond.m", "magDLSecond", &phy_vars_ue->pdsch_vars[ue->current_thread_id[subframe_rx]][0]->dl_ch_magb0[0][0],14*frame_parms->N_RB_DL*12,1,1);

       AssertFatal (0,"");
  }
LOG_M_END

  // do procedures for SI-RNTI
  if ((ue->dlsch_SI[eNB_id]) && (ue->dlsch_SI[eNB_id]->active == 1)) {
    ue_pdsch_procedures(ue,
      proc,
      eNB_id,
      SI_PDSCH,
      ue->dlsch_SI[eNB_id],
      NULL,
      1+(ue->frame_parms.symbols_per_tti>>1),
      ue->frame_parms.symbols_per_tti-1,
      abstraction_flag);

    ue_dlsch_procedures(ue,
      proc,
      eNB_id,
      SI_PDSCH,
      ue->dlsch_SI[eNB_id],
      NULL,
      &ue->dlsch_SI_errors[eNB_id],
      mode,
      abstraction_flag);
    ue->dlsch_SI[eNB_id]->active = 0;
  }

  // do procedures for P-RNTI
  if ((ue->dlsch_p[eNB_id]) && (ue->dlsch_p[eNB_id]->active == 1)) {
    ue_pdsch_procedures(ue,
      proc,
      eNB_id,
      P_PDSCH,
      ue->dlsch_p[eNB_id],
      NULL,
      1+(ue->frame_parms.symbols_per_tti>>1),
      ue->frame_parms.symbols_per_tti-1,
      abstraction_flag);

    ue_dlsch_procedures(ue,
      proc,
      eNB_id,
      P_PDSCH,
      ue->dlsch_p[eNB_id],
      NULL,
      &ue->dlsch_p_errors[eNB_id],
      mode,
      abstraction_flag);
    ue->dlsch_p[eNB_id]->active = 0;
  }
  // do procedures for RA-RNTI
  if ((ue->dlsch_ra[eNB_id]) && (ue->dlsch_ra[eNB_id]->active == 1)) {
    ue_pdsch_procedures(ue,
      proc,
      eNB_id,
      RA_PDSCH,
      ue->dlsch_ra[eNB_id],
      NULL,
      1+(ue->frame_parms.symbols_per_tti>>1),
      ue->frame_parms.symbols_per_tti-1,
      abstraction_flag);
    ue_dlsch_procedures(ue,
      proc,
      eNB_id,
      RA_PDSCH,
      ue->dlsch_ra[eNB_id],
      NULL,
      &ue->dlsch_ra_errors[eNB_id],
      mode,
      abstraction_flag);
    ue->dlsch_ra[eNB_id]->active = 0;
  }

  // duplicate harq structure

  uint8_t          current_harq_pid        = ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0]->current_harq_pid;
  LTE_DL_UE_HARQ_t *current_harq_processes = ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0]->harq_processes[current_harq_pid];
  LTE_DL_UE_HARQ_t *harq_processes_dest    = ue->dlsch[next1_thread_id][eNB_id][0]->harq_processes[current_harq_pid];
  LTE_DL_UE_HARQ_t *harq_processes_dest1    = ue->dlsch[next2_thread_id][eNB_id][0]->harq_processes[current_harq_pid];

  harq_status_t *current_harq_ack = &ue->dlsch[ue->current_thread_id[subframe_rx]][eNB_id][0]->harq_ack[subframe_rx];
  harq_status_t *harq_ack_dest    = &ue->dlsch[next1_thread_id][eNB_id][0]->harq_ack[subframe_rx];
  harq_status_t *harq_ack_dest1    = &ue->dlsch[next2_thread_id][eNB_id][0]->harq_ack[subframe_rx];

  copy_harq_proc_struct(harq_processes_dest, current_harq_processes);
  copy_ack_struct(harq_ack_dest, current_harq_ack);

  copy_harq_proc_struct(harq_processes_dest1, current_harq_processes);
  copy_ack_struct(harq_ack_dest1, current_harq_ack);

  if (subframe_rx==9) {
    if (frame_rx % 10 == 0) {
      if ((ue->dlsch_received[eNB_id] - ue->dlsch_received_last[eNB_id]) != 0)
  ue->dlsch_fer[eNB_id] = (100*(ue->dlsch_errors[eNB_id] - ue->dlsch_errors_last[eNB_id]))/(ue->dlsch_received[eNB_id] - ue->dlsch_received_last[eNB_id]);

      ue->dlsch_errors_last[eNB_id] = ue->dlsch_errors[eNB_id];
      ue->dlsch_received_last[eNB_id] = ue->dlsch_received[eNB_id];
    }


    ue->bitrate[eNB_id] = (ue->total_TBS[eNB_id] - ue->total_TBS_last[eNB_id])*100;
    ue->total_TBS_last[eNB_id] = ue->total_TBS[eNB_id];
    LOG_D(PHY,"[UE %d] Calculating bitrate Frame %d: total_TBS = %d, total_TBS_last = %d, bitrate %f kbits\n",
    ue->Mod_id,frame_rx,ue->total_TBS[eNB_id],
    ue->total_TBS_last[eNB_id],(float) ue->bitrate[eNB_id]/1000.0);

LOG_DEBUG_BEGIN(DEBUG_UE_PHYPROC)
    if ((frame_rx % 100 == 0)) {
      LOG_I(PHY,"[UE  %d] AUTOTEST Metric : UE_DLSCH_BITRATE = %5.2f kbps (frame = %d) \n", ue->Mod_id, (float) ue->bitrate[eNB_id]/1000.0, frame_rx);
    }
LOG_DEBUG_END

  }

LOG_DEBUG_BEGIN(UE_TIMING)
  stop_meas(&ue->generic_stat);
  printf("after tubo until end of Rx %5.2f \n",ue->generic_stat.p_time/(cpuf*1000.0));
LOG_DEBUG_END

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX, VCD_FUNCTION_OUT);

LOG_DEBUG_BEGIN(UE_TIMING)
  stop_meas(&ue->phy_proc_rx[ue->current_thread_id[subframe_rx]]);
  LOG_UI(PHY, "------FULL RX PROC [SFN %d]: %5.2f ------\n",subframe_rx,ue->phy_proc_rx[ue->current_thread_id[subframe_rx]].p_time/(cpuf*1000.0));
LOG_DEBUG_END

  LOG_D(PHY," ****** end RX-Chain  for AbsSubframe %d.%d ******  \n", frame_rx%1024, subframe_rx);
  return (0);
}



void phy_procedures_UE_lte(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t abstraction_flag,uint8_t do_pdcch_flag,runmode_t mode)
{
#if defined(ENABLE_ITTI)
  MessageDef   *msg_p;
  int           result;
#endif

  int           frame_rx = proc->frame_rx;
  int           frame_tx = proc->frame_tx;
  int           subframe_rx = proc->subframe_rx;
  int           subframe_tx = proc->subframe_tx;


  UE_L2_STATE_t ret;
  int slot;

  if (ue->mac_enabled == 0) {
    ue->UE_mode[eNB_id]=PUSCH;
  }


  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_LTE,1);
LOG_DEBUG_BEGIN(UE_TIMING)
  start_meas(&ue->phy_proc[ue->current_thread_id[subframe_rx]]);
LOG_DEBUG_END

#if defined(ENABLE_ITTI)

  do {
    // Checks if a message has been sent to PHY sub-task
    itti_poll_msg (TASK_PHY_UE, &msg_p);

    if (msg_p != NULL) {
      switch (ITTI_MSG_ID(msg_p)) {
      case PHY_FIND_CELL_REQ:
  LOG_I(PHY, "[UE %d] Received %s\n", ITTI_MSG_INSTANCE (msg_p) - NB_eNB_INST, ITTI_MSG_NAME (msg_p));

  /* TODO process the message */
  break;

      default:
  LOG_E(PHY, "[UE %d] Received unexpected message %s\n", ITTI_MSG_INSTANCE (msg_p) - NB_eNB_INST, ITTI_MSG_NAME (msg_p));
  break;
      }

      result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
      AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
    }
  } while(msg_p != NULL);

#endif

  for (slot=0;slot<2;slot++) {

    if ((subframe_select(&ue->frame_parms,subframe_tx)==SF_UL)||
  (ue->frame_parms.frame_type == FDD)) {
      phy_procedures_UE_TX(ue,proc,eNB_id,abstraction_flag,mode);
    }

    if ((subframe_select(&ue->frame_parms,subframe_rx)==SF_DL) ||
	(ue->frame_parms.frame_type == FDD)) {
      phy_procedures_UE_RX(ue,proc,eNB_id,abstraction_flag,do_pdcch_flag,mode);
    }

    if ((subframe_select(&ue->frame_parms,subframe_tx)==SF_S) &&
	(slot==1)) {
      phy_procedures_UE_S_TX(ue,eNB_id,abstraction_flag);
    }

    if ((subframe_select(&ue->frame_parms,subframe_rx)==SF_S) &&
	(slot==0)) {
	phy_procedures_UE_RX(ue,proc,eNB_id,abstraction_flag,do_pdcch_flag,mode);
    }

    if (ue->mac_enabled==1) {
      if (slot==0) {

          //LOG_I(PHY,"[UE %d] Frame %d, subframe %d, star ue_scheduler\n", ue->Mod_id,frame_rx,subframe_tx);
        ret = ue_scheduler(ue->Mod_id,
			   frame_rx,
			   subframe_rx,
			   frame_tx,
			   subframe_tx,
			   subframe_select(&ue->frame_parms,subframe_tx),
			   eNB_id,
			   0/*FIXME CC_id*/);
	
	if (ret == CONNECTION_LOST) {
	  LOG_E(PHY,"[UE %d] Frame %d, subframe %d RRC Connection lost, returning to PRACH\n",ue->Mod_id,
		frame_rx,subframe_tx);
	  ue->UE_mode[eNB_id] = PRACH;
	  //      mac_xface->macphy_exit("Connection lost");
	} else if (ret == PHY_RESYNCH) {
	  LOG_E(PHY,"[UE %d] Frame %d, subframe %d RRC Connection lost, trying to resynch\n",
		ue->Mod_id,
		frame_rx,subframe_tx);
	  ue->UE_mode[eNB_id] = RESYNCH;
	  //     mac_xface->macphy_exit("Connection lost");
	} else if (ret == PHY_HO_PRACH) {
	  LOG_I(PHY,"[UE %d] Frame %d, subframe %d, return to PRACH and perform a contention-free access\n",
		ue->Mod_id,frame_rx,subframe_tx);
	  ue->UE_mode[eNB_id] = PRACH;
	}
      }
    }
    
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_LTE,0);
LOG_DEBUG_BEGIN(UE_TIMING)
    stop_meas(&ue->phy_proc[ue->current_thread_id[subframe_rx]]);
LOG_DEBUG_END
  } // slot
}


