From ad98f5aa9e9ce9c254fa1e797eb4c86f6916d845 Mon Sep 17 00:00:00 2001
From: Raymond Knopp <raymond.knopp@eurecom.fr>
Date: Mon, 7 Aug 2017 23:25:17 -0700
Subject: [PATCH] L1/L2 scheduling extensions for BL/CE operation, BR
 random-access procedure, BR PRACH detection. Still untested, but compilation
 succeeds. Missing elements in L2 - PUSCH programming for Msg3, Msg4
 retransmission programming for BL/CE. DLSCH/ULSCH programming for UE-specific
 DLSCH/ULSCH for BL/CE

---
 openair1/PHY/INIT/lte_init.c                  | 527 +++++-----
 openair1/PHY/LTE_TRANSPORT/if4_tools.c        |  70 +-
 openair1/PHY/LTE_TRANSPORT/if4_tools.h        |   6 +-
 openair1/PHY/LTE_TRANSPORT/prach.c            | 385 +++++--
 openair1/PHY/LTE_TRANSPORT/proto.h            |  18 +-
 openair1/PHY/defs.h                           |  94 +-
 openair1/PHY/impl_defs_lte.h                  |  61 +-
 openair1/SCHED/defs.h                         |   9 +-
 openair1/SCHED/phy_procedures_lte_eNb.c       | 185 ++--
 openair2/LAYER2/MAC/config.c                  |  54 +-
 openair2/LAYER2/MAC/defs.h                    |  28 +-
 openair2/LAYER2/MAC/eNB_scheduler_RA.c        | 967 ++++++++++++------
 .../LAYER2/MAC/eNB_scheduler_primitives.c     |  63 ++
 openair2/LAYER2/MAC/main.c                    |   2 +
 openair2/LAYER2/MAC/proto.h                   |   9 +-
 openair2/LAYER2/MAC/rar_tools.c               |  90 ++
 openair2/PHY_INTERFACE/IF_Module.c            |  29 +-
 openair2/PHY_INTERFACE/IF_Module.h            |   5 +
 targets/RT/USER/lte-enb.c                     | 153 ++-
 targets/RT/USER/lte-ru.c                      | 159 ++-
 20 files changed, 2099 insertions(+), 815 deletions(-)

diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c
index 1def93e8c2..81a8478e33 100644
--- a/openair1/PHY/INIT/lte_init.c
+++ b/openair1/PHY/INIT/lte_init.c
@@ -145,6 +145,61 @@ void phy_config_request(PHY_Config_t *phy_config) {
   LOG_I(PHY,"prach_config_common.prach_ConfigInfo.prach_FreqOffset = %d\n",cfg->prach_config.frequency_offset.value);
 
   init_prach_tables(839);
+#ifdef Rel14
+  fp->prach_emtc_config_common.prach_Config_enabled=1;
+
+  fp->prach_emtc_config_common.rootSequenceIndex                                         = cfg->emtc_config.prach_catm_root_sequence_index.value;
+
+  fp->prach_emtc_config_common.prach_ConfigInfo.highSpeedFlag                            = cfg->emtc_config.prach_catm_high_speed_flag.value;
+  fp->prach_emtc_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig                = cfg->emtc_config.prach_catm_zero_correlation_zone_configuration.value;
+
+  // CE Level 3 parameters
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[3]                  = cfg->emtc_config.prach_ce_level_3_enable.value;
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[3]   = cfg->emtc_config.prach_ce_level_3_starting_subframe_periodicity.value;
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[3] = cfg->emtc_config.prach_ce_level_3_number_of_repetitions_per_attempt.value;
+  AssertFatal(fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[3]>=fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[3],
+	      "prach_starting_subframe_periodicity[3] < prach_numPetitionPerPreambleAttempt[3]\n");
+
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[3]                     = cfg->emtc_config.prach_ce_level_3_configuration_index.value;
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[3]                      = cfg->emtc_config.prach_ce_level_3_frequency_offset.value;
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_enable[3]                  = cfg->emtc_config.prach_ce_level_3_hopping_enable.value;
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_offset[3]                  = cfg->emtc_config.prach_ce_level_3_hopping_offset.value;
+
+  // CE Level 2 parameters
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[2]                  = cfg->emtc_config.prach_ce_level_2_enable.value;
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[2]   = cfg->emtc_config.prach_ce_level_2_starting_subframe_periodicity.value;
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[2] = cfg->emtc_config.prach_ce_level_2_number_of_repetitions_per_attempt.value;
+  AssertFatal(fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[2]>=fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[2],
+	      "prach_starting_subframe_periodicity[2] < prach_numPetitionPerPreambleAttempt[2]\n");
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[2]                     = cfg->emtc_config.prach_ce_level_2_configuration_index.value;
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[2]                      = cfg->emtc_config.prach_ce_level_2_frequency_offset.value;
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_enable[2]                  = cfg->emtc_config.prach_ce_level_2_hopping_enable.value;
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_offset[2]                  = cfg->emtc_config.prach_ce_level_2_hopping_offset.value;
+
+  // CE Level 1 parameters
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[1]                  = cfg->emtc_config.prach_ce_level_1_enable.value;
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[1]   = cfg->emtc_config.prach_ce_level_1_starting_subframe_periodicity.value;
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[1] = cfg->emtc_config.prach_ce_level_1_number_of_repetitions_per_attempt.value;
+  AssertFatal(fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[1]>=fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[1],
+	      "prach_starting_subframe_periodicity[1] < prach_numPetitionPerPreambleAttempt[1]\n");
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[1]                     = cfg->emtc_config.prach_ce_level_1_configuration_index.value;
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[1]                      = cfg->emtc_config.prach_ce_level_1_frequency_offset.value;
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_enable[1]                  = cfg->emtc_config.prach_ce_level_1_hopping_enable.value;
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_offset[1]                  = cfg->emtc_config.prach_ce_level_1_hopping_offset.value;
+
+  // CE Level 0 parameters
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[0]                  = cfg->emtc_config.prach_ce_level_0_enable.value;
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[0]   = cfg->emtc_config.prach_ce_level_0_starting_subframe_periodicity.value;
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[0] = cfg->emtc_config.prach_ce_level_0_number_of_repetitions_per_attempt.value;
+  AssertFatal(fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[0]>=fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[0],
+	      "prach_starting_subframe_periodicity[0] < prach_numPetitionPerPreambleAttempt[0]\n");
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[0]                     = cfg->emtc_config.prach_ce_level_0_configuration_index.value;
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[0]                      = cfg->emtc_config.prach_ce_level_0_frequency_offset.value;
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_enable[0]                = cfg->emtc_config.prach_ce_level_0_hopping_enable.value;
+  fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_offset[0]                = cfg->emtc_config.prach_ce_level_0_hopping_offset.value;
+
+#endif
+
   compute_prach_seq(&fp->prach_config_common,fp->frame_type,
                     RC.eNB[Mod_id][CC_id]->X_u);
 
@@ -1278,31 +1333,30 @@ int init_lte_ue_signal(PHY_VARS_UE *ue,
   for (i=0;i<10;i++)
     ue->tx_power_dBm[i]=-127;
 
-  if (abstraction_flag == 0) {
-
-    // init TX buffers
-
-    common_vars->txdata  = (int32_t**)malloc16( fp->nb_antennas_tx*sizeof(int32_t*) );
-    common_vars->txdataF = (int32_t **)malloc16( fp->nb_antennas_tx*sizeof(int32_t*) );
-
-    for (i=0; i<fp->nb_antennas_tx; i++) {
-
-      common_vars->txdata[i]  = (int32_t*)malloc16_clear( fp->samples_per_tti*10*sizeof(int32_t) );
-      common_vars->txdataF[i] = (int32_t *)malloc16_clear( fp->ofdm_symbol_size*fp->symbols_per_tti*10*sizeof(int32_t) );
-    }
 
-    // init RX buffers
-
-    common_vars->rxdata   = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) );
-    common_vars->common_vars_rx_data_per_thread[0].rxdataF  = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) );
-    common_vars->common_vars_rx_data_per_thread[1].rxdataF  = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) );
-
-    for (i=0; i<fp->nb_antennas_rx; i++) {
-      common_vars->rxdata[i] = (int32_t*) malloc16_clear( (fp->samples_per_tti*10+2048)*sizeof(int32_t) );
-      common_vars->common_vars_rx_data_per_thread[0].rxdataF[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(fp->ofdm_symbol_size*14) );
-      common_vars->common_vars_rx_data_per_thread[1].rxdataF[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(fp->ofdm_symbol_size*14) );
-    }
+  // init TX buffers
+  
+  common_vars->txdata  = (int32_t**)malloc16( fp->nb_antennas_tx*sizeof(int32_t*) );
+  common_vars->txdataF = (int32_t **)malloc16( fp->nb_antennas_tx*sizeof(int32_t*) );
+  
+  for (i=0; i<fp->nb_antennas_tx; i++) {
+    
+    common_vars->txdata[i]  = (int32_t*)malloc16_clear( fp->samples_per_tti*10*sizeof(int32_t) );
+    common_vars->txdataF[i] = (int32_t *)malloc16_clear( fp->ofdm_symbol_size*fp->symbols_per_tti*10*sizeof(int32_t) );
   }
+  
+  // init RX buffers
+  
+  common_vars->rxdata   = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) );
+  common_vars->common_vars_rx_data_per_thread[0].rxdataF  = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) );
+  common_vars->common_vars_rx_data_per_thread[1].rxdataF  = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) );
+  
+  for (i=0; i<fp->nb_antennas_rx; i++) {
+    common_vars->rxdata[i] = (int32_t*) malloc16_clear( (fp->samples_per_tti*10+2048)*sizeof(int32_t) );
+    common_vars->common_vars_rx_data_per_thread[0].rxdataF[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(fp->ofdm_symbol_size*14) );
+    common_vars->common_vars_rx_data_per_thread[1].rxdataF[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(fp->ofdm_symbol_size*14) );
+  }
+
 
   // Channel estimates
   for (eNB_id=0; eNB_id<7; eNB_id++) {
@@ -1333,140 +1387,140 @@ int init_lte_ue_signal(PHY_VARS_UE *ue,
     prach_vars[eNB_id]     = (LTE_UE_PRACH *)malloc16_clear(sizeof(LTE_UE_PRACH));
     pbch_vars[eNB_id]      = (LTE_UE_PBCH *)malloc16_clear(sizeof(LTE_UE_PBCH));
 
-    if (abstraction_flag == 0) {
-      phy_init_lte_ue__PDSCH( pdsch_vars_th0[eNB_id], fp );
-      phy_init_lte_ue__PDSCH( pdsch_vars_th1[eNB_id], fp );
-
-      // thread 0
-      pdsch_vars_th0[eNB_id]->llr_shifts      = (uint8_t*)malloc16_clear(7*2*fp->N_RB_DL*12);
-      pdsch_vars_th0[eNB_id]->llr_shifts_p        = pdsch_vars_th0[eNB_id]->llr_shifts;
-      pdsch_vars_th0[eNB_id]->llr[1]              = (int16_t*)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) );
-      pdsch_vars_th0[eNB_id]->llr128_2ndstream    = (int16_t**)malloc16_clear( sizeof(int16_t*) );
-      pdsch_vars_th0[eNB_id]->rho                 = (int32_t**)malloc16_clear( fp->nb_antennas_rx*sizeof(int32_t*) );
-
-       // thread 0
-      pdsch_vars_th1[eNB_id]->llr_shifts      = (uint8_t*)malloc16_clear(7*2*fp->N_RB_DL*12);
-      pdsch_vars_th1[eNB_id]->llr_shifts_p        = pdsch_vars_th0[eNB_id]->llr_shifts;
-      pdsch_vars_th1[eNB_id]->llr[1]              = (int16_t*)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) );
-      pdsch_vars_th1[eNB_id]->llr128_2ndstream    = (int16_t**)malloc16_clear( sizeof(int16_t*) );
-      pdsch_vars_th1[eNB_id]->rho                 = (int32_t**)malloc16_clear( fp->nb_antennas_rx*sizeof(int32_t*) );
-
-
-
-
-      for (int i=0; i<fp->nb_antennas_rx; i++){
-        pdsch_vars_th0[eNB_id]->rho[i]     = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) );
-        pdsch_vars_th1[eNB_id]->rho[i]     = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) );
-        }
-
-      pdsch_vars_th0[eNB_id]->dl_ch_rho2_ext      = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
-      pdsch_vars_th1[eNB_id]->dl_ch_rho2_ext      = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
 
-      for (i=0; i<fp->nb_antennas_rx; i++)
-        for (j=0; j<4; j++) {
-          const int idx = (j<<1)+i;
-          const size_t num = 7*2*fp->N_RB_DL*12+4;
-          pdsch_vars_th0[eNB_id]->dl_ch_rho2_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num );
-          pdsch_vars_th1[eNB_id]->dl_ch_rho2_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num );
-        }
-
-
-      //const size_t num = 7*2*fp->N_RB_DL*12+4;
-      for (k=0;k<8;k++) { //harq_pid
-        for (l=0;l<8;l++) { //round
-          pdsch_vars_th0[eNB_id]->rxdataF_comp1[k][l] = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
-          pdsch_vars_th0[eNB_id]->dl_ch_rho_ext[k][l] = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
-          pdsch_vars_th0[eNB_id]->dl_ch_mag1[k][l] = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
-          pdsch_vars_th0[eNB_id]->dl_ch_magb1[k][l] = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
-
-          pdsch_vars_th1[eNB_id]->rxdataF_comp1[k][l] = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
-          pdsch_vars_th1[eNB_id]->dl_ch_rho_ext[k][l] = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
-          pdsch_vars_th1[eNB_id]->dl_ch_mag1[k][l] = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
-          pdsch_vars_th1[eNB_id]->dl_ch_magb1[k][l] = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
-
-
-          for (int i=0; i<fp->nb_antennas_rx; i++)
-            for (int j=0; j<4; j++) { //frame_parms->nb_antennas_tx; j++)
-              const int idx = (j<<1)+i;
-              pdsch_vars_th0[eNB_id]->dl_ch_rho_ext[k][l][idx] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) );
-              pdsch_vars_th0[eNB_id]->rxdataF_comp1[k][l][idx] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) );
-              pdsch_vars_th0[eNB_id]->dl_ch_mag1[k][l][idx] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) );
-              pdsch_vars_th0[eNB_id]->dl_ch_magb1[k][l][idx] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) );
-
-              pdsch_vars_th1[eNB_id]->dl_ch_rho_ext[k][l][idx] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) );
-              pdsch_vars_th1[eNB_id]->rxdataF_comp1[k][l][idx] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) );
-              pdsch_vars_th1[eNB_id]->dl_ch_mag1[k][l][idx] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) );
-              pdsch_vars_th1[eNB_id]->dl_ch_magb1[k][l][idx] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) );
-                }
-        }
+    phy_init_lte_ue__PDSCH( pdsch_vars_th0[eNB_id], fp );
+    phy_init_lte_ue__PDSCH( pdsch_vars_th1[eNB_id], fp );
+    
+    // thread 0
+    pdsch_vars_th0[eNB_id]->llr_shifts      = (uint8_t*)malloc16_clear(7*2*fp->N_RB_DL*12);
+    pdsch_vars_th0[eNB_id]->llr_shifts_p        = pdsch_vars_th0[eNB_id]->llr_shifts;
+    pdsch_vars_th0[eNB_id]->llr[1]              = (int16_t*)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) );
+    pdsch_vars_th0[eNB_id]->llr128_2ndstream    = (int16_t**)malloc16_clear( sizeof(int16_t*) );
+    pdsch_vars_th0[eNB_id]->rho                 = (int32_t**)malloc16_clear( fp->nb_antennas_rx*sizeof(int32_t*) );
+    
+    // thread 0
+    pdsch_vars_th1[eNB_id]->llr_shifts      = (uint8_t*)malloc16_clear(7*2*fp->N_RB_DL*12);
+    pdsch_vars_th1[eNB_id]->llr_shifts_p        = pdsch_vars_th0[eNB_id]->llr_shifts;
+    pdsch_vars_th1[eNB_id]->llr[1]              = (int16_t*)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) );
+    pdsch_vars_th1[eNB_id]->llr128_2ndstream    = (int16_t**)malloc16_clear( sizeof(int16_t*) );
+    pdsch_vars_th1[eNB_id]->rho                 = (int32_t**)malloc16_clear( fp->nb_antennas_rx*sizeof(int32_t*) );
+    
+    
+    
+    
+    for (int i=0; i<fp->nb_antennas_rx; i++){
+      pdsch_vars_th0[eNB_id]->rho[i]     = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) );
+      pdsch_vars_th1[eNB_id]->rho[i]     = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) );
+    }
+    
+    pdsch_vars_th0[eNB_id]->dl_ch_rho2_ext      = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
+    pdsch_vars_th1[eNB_id]->dl_ch_rho2_ext      = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
+    
+    for (i=0; i<fp->nb_antennas_rx; i++)
+      for (j=0; j<4; j++) {
+	const int idx = (j<<1)+i;
+	const size_t num = 7*2*fp->N_RB_DL*12+4;
+	pdsch_vars_th0[eNB_id]->dl_ch_rho2_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num );
+	pdsch_vars_th1[eNB_id]->dl_ch_rho2_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num );
       }
-      phy_init_lte_ue__PDSCH( pdsch_vars_SI[eNB_id], fp );
-      phy_init_lte_ue__PDSCH( pdsch_vars_ra[eNB_id], fp );
-      phy_init_lte_ue__PDSCH( pdsch_vars_mch[eNB_id], fp );
-
-      // 100 PRBs * 12 REs/PRB * 4 PDCCH SYMBOLS * 2 LLRs/RE
-      pdcch_vars_th0[eNB_id]->llr   = (uint16_t*)malloc16_clear( 2*4*100*12*sizeof(uint16_t) );
-      pdcch_vars_th0[eNB_id]->llr16 = (uint16_t*)malloc16_clear( 2*4*100*12*sizeof(uint16_t) );
-      pdcch_vars_th0[eNB_id]->wbar  = (uint16_t*)malloc16_clear( 2*4*100*12*sizeof(uint16_t) );
-      pdcch_vars_th0[eNB_id]->e_rx  = (int8_t*)malloc16_clear( 4*2*100*12 );
-
-      pdcch_vars_th0[eNB_id]->rxdataF_comp        = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
-      pdcch_vars_th0[eNB_id]->dl_ch_rho_ext       = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
-      pdcch_vars_th0[eNB_id]->rho                 = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) );
-      pdcch_vars_th0[eNB_id]->rxdataF_ext         = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
-      pdcch_vars_th0[eNB_id]->dl_ch_estimates_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
-
-      pdcch_vars_th1[eNB_id]->llr   = (uint16_t*)malloc16_clear( 2*4*100*12*sizeof(uint16_t) );
-      pdcch_vars_th1[eNB_id]->llr16 = (uint16_t*)malloc16_clear( 2*4*100*12*sizeof(uint16_t) );
-      pdcch_vars_th1[eNB_id]->wbar  = (uint16_t*)malloc16_clear( 2*4*100*12*sizeof(uint16_t) );
-      pdcch_vars_th1[eNB_id]->e_rx  = (int8_t*)malloc16_clear( 4*2*100*12 );
-
-      pdcch_vars_th1[eNB_id]->rxdataF_comp        = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
-      pdcch_vars_th1[eNB_id]->dl_ch_rho_ext       = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
-      pdcch_vars_th1[eNB_id]->rho                 = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) );
-      pdcch_vars_th1[eNB_id]->rxdataF_ext         = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
-      pdcch_vars_th1[eNB_id]->dl_ch_estimates_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
-
-      for (i=0; i<fp->nb_antennas_rx; i++) {
-        //ue_pdcch_vars[eNB_id]->rho[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(fp->N_RB_DL*12*7*2) );
-        pdcch_vars_th0[eNB_id]->rho[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(100*12*4) );
-        pdcch_vars_th1[eNB_id]->rho[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(100*12*4) );
-
-        for (j=0; j<4; j++) { //fp->nb_antennas_tx; j++)
-          int idx = (j<<1)+i;
-          //  size_t num = 7*2*fp->N_RB_DL*12;
-          size_t num = 4*100*12;  // 4 symbols, 100 PRBs, 12 REs per PRB
-          pdcch_vars_th0[eNB_id]->rxdataF_comp[idx]        = (int32_t*)malloc16_clear( sizeof(int32_t) * num );
-          pdcch_vars_th0[eNB_id]->dl_ch_rho_ext[idx]       = (int32_t*)malloc16_clear( sizeof(int32_t) * num );
-          pdcch_vars_th0[eNB_id]->rxdataF_ext[idx]         = (int32_t*)malloc16_clear( sizeof(int32_t) * num );
-          pdcch_vars_th0[eNB_id]->dl_ch_estimates_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num );
-
-          pdcch_vars_th1[eNB_id]->rxdataF_comp[idx]        = (int32_t*)malloc16_clear( sizeof(int32_t) * num );
-          pdcch_vars_th1[eNB_id]->dl_ch_rho_ext[idx]       = (int32_t*)malloc16_clear( sizeof(int32_t) * num );
-          pdcch_vars_th1[eNB_id]->rxdataF_ext[idx]         = (int32_t*)malloc16_clear( sizeof(int32_t) * num );
-          pdcch_vars_th1[eNB_id]->dl_ch_estimates_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num );
-        }
+    
+    
+    //const size_t num = 7*2*fp->N_RB_DL*12+4;
+    for (k=0;k<8;k++) { //harq_pid
+      for (l=0;l<8;l++) { //round
+	pdsch_vars_th0[eNB_id]->rxdataF_comp1[k][l] = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
+	pdsch_vars_th0[eNB_id]->dl_ch_rho_ext[k][l] = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
+	pdsch_vars_th0[eNB_id]->dl_ch_mag1[k][l] = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
+	pdsch_vars_th0[eNB_id]->dl_ch_magb1[k][l] = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
+	
+	pdsch_vars_th1[eNB_id]->rxdataF_comp1[k][l] = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
+	pdsch_vars_th1[eNB_id]->dl_ch_rho_ext[k][l] = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
+	pdsch_vars_th1[eNB_id]->dl_ch_mag1[k][l] = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
+	pdsch_vars_th1[eNB_id]->dl_ch_magb1[k][l] = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
+	
+	
+	for (int i=0; i<fp->nb_antennas_rx; i++)
+	  for (int j=0; j<4; j++) { //frame_parms->nb_antennas_tx; j++)
+	    const int idx = (j<<1)+i;
+	    pdsch_vars_th0[eNB_id]->dl_ch_rho_ext[k][l][idx] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) );
+	    pdsch_vars_th0[eNB_id]->rxdataF_comp1[k][l][idx] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) );
+	    pdsch_vars_th0[eNB_id]->dl_ch_mag1[k][l][idx] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) );
+	    pdsch_vars_th0[eNB_id]->dl_ch_magb1[k][l][idx] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) );
+	    
+	    pdsch_vars_th1[eNB_id]->dl_ch_rho_ext[k][l][idx] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) );
+	    pdsch_vars_th1[eNB_id]->rxdataF_comp1[k][l][idx] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) );
+	    pdsch_vars_th1[eNB_id]->dl_ch_mag1[k][l][idx] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) );
+	    pdsch_vars_th1[eNB_id]->dl_ch_magb1[k][l][idx] = (int32_t*)malloc16_clear( 7*2*sizeof(int32_t)*(fp->N_RB_DL*12) );
+	  }
       }
-
-      // PBCH
-      pbch_vars[eNB_id]->rxdataF_ext         = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) );
-      pbch_vars[eNB_id]->rxdataF_comp        = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
-      pbch_vars[eNB_id]->dl_ch_estimates_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
-      pbch_vars[eNB_id]->llr                 = (int8_t*)malloc16_clear( 1920 );
-      prach_vars[eNB_id]->prachF             = (int16_t*)malloc16_clear( sizeof(int)*(7*2*sizeof(int)*(fp->ofdm_symbol_size*12)) );
-      prach_vars[eNB_id]->prach              = (int16_t*)malloc16_clear( sizeof(int)*(7*2*sizeof(int)*(fp->ofdm_symbol_size*12)) );
-
-      for (i=0; i<fp->nb_antennas_rx; i++) {
-        pbch_vars[eNB_id]->rxdataF_ext[i]    = (int32_t*)malloc16_clear( sizeof(int32_t)*6*12*4 );
-
-        for (j=0; j<4; j++) {//fp->nb_antennas_tx;j++) {
-          int idx = (j<<1)+i;
-          pbch_vars[eNB_id]->rxdataF_comp[idx]        = (int32_t*)malloc16_clear( sizeof(int32_t)*6*12*4 );
-          pbch_vars[eNB_id]->dl_ch_estimates_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t)*6*12*4 );
-        }
+    }
+    phy_init_lte_ue__PDSCH( pdsch_vars_SI[eNB_id], fp );
+    phy_init_lte_ue__PDSCH( pdsch_vars_ra[eNB_id], fp );
+    phy_init_lte_ue__PDSCH( pdsch_vars_mch[eNB_id], fp );
+    
+    // 100 PRBs * 12 REs/PRB * 4 PDCCH SYMBOLS * 2 LLRs/RE
+    pdcch_vars_th0[eNB_id]->llr   = (uint16_t*)malloc16_clear( 2*4*100*12*sizeof(uint16_t) );
+    pdcch_vars_th0[eNB_id]->llr16 = (uint16_t*)malloc16_clear( 2*4*100*12*sizeof(uint16_t) );
+    pdcch_vars_th0[eNB_id]->wbar  = (uint16_t*)malloc16_clear( 2*4*100*12*sizeof(uint16_t) );
+    pdcch_vars_th0[eNB_id]->e_rx  = (int8_t*)malloc16_clear( 4*2*100*12 );
+    
+    pdcch_vars_th0[eNB_id]->rxdataF_comp        = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
+    pdcch_vars_th0[eNB_id]->dl_ch_rho_ext       = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
+    pdcch_vars_th0[eNB_id]->rho                 = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) );
+    pdcch_vars_th0[eNB_id]->rxdataF_ext         = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
+    pdcch_vars_th0[eNB_id]->dl_ch_estimates_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
+    
+    pdcch_vars_th1[eNB_id]->llr   = (uint16_t*)malloc16_clear( 2*4*100*12*sizeof(uint16_t) );
+    pdcch_vars_th1[eNB_id]->llr16 = (uint16_t*)malloc16_clear( 2*4*100*12*sizeof(uint16_t) );
+    pdcch_vars_th1[eNB_id]->wbar  = (uint16_t*)malloc16_clear( 2*4*100*12*sizeof(uint16_t) );
+    pdcch_vars_th1[eNB_id]->e_rx  = (int8_t*)malloc16_clear( 4*2*100*12 );
+    
+    pdcch_vars_th1[eNB_id]->rxdataF_comp        = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
+    pdcch_vars_th1[eNB_id]->dl_ch_rho_ext       = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
+    pdcch_vars_th1[eNB_id]->rho                 = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) );
+    pdcch_vars_th1[eNB_id]->rxdataF_ext         = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
+    pdcch_vars_th1[eNB_id]->dl_ch_estimates_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
+    
+    for (i=0; i<fp->nb_antennas_rx; i++) {
+      //ue_pdcch_vars[eNB_id]->rho[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(fp->N_RB_DL*12*7*2) );
+      pdcch_vars_th0[eNB_id]->rho[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(100*12*4) );
+      pdcch_vars_th1[eNB_id]->rho[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*(100*12*4) );
+      
+      for (j=0; j<4; j++) { //fp->nb_antennas_tx; j++)
+	int idx = (j<<1)+i;
+	//  size_t num = 7*2*fp->N_RB_DL*12;
+	size_t num = 4*100*12;  // 4 symbols, 100 PRBs, 12 REs per PRB
+	pdcch_vars_th0[eNB_id]->rxdataF_comp[idx]        = (int32_t*)malloc16_clear( sizeof(int32_t) * num );
+	pdcch_vars_th0[eNB_id]->dl_ch_rho_ext[idx]       = (int32_t*)malloc16_clear( sizeof(int32_t) * num );
+	pdcch_vars_th0[eNB_id]->rxdataF_ext[idx]         = (int32_t*)malloc16_clear( sizeof(int32_t) * num );
+	pdcch_vars_th0[eNB_id]->dl_ch_estimates_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num );
+	
+	pdcch_vars_th1[eNB_id]->rxdataF_comp[idx]        = (int32_t*)malloc16_clear( sizeof(int32_t) * num );
+	pdcch_vars_th1[eNB_id]->dl_ch_rho_ext[idx]       = (int32_t*)malloc16_clear( sizeof(int32_t) * num );
+	pdcch_vars_th1[eNB_id]->rxdataF_ext[idx]         = (int32_t*)malloc16_clear( sizeof(int32_t) * num );
+	pdcch_vars_th1[eNB_id]->dl_ch_estimates_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num );
       }
     }
-
+    
+    // PBCH
+    pbch_vars[eNB_id]->rxdataF_ext         = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) );
+    pbch_vars[eNB_id]->rxdataF_comp        = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
+    pbch_vars[eNB_id]->dl_ch_estimates_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
+    pbch_vars[eNB_id]->llr                 = (int8_t*)malloc16_clear( 1920 );
+    prach_vars[eNB_id]->prachF             = (int16_t*)malloc16_clear( sizeof(int)*(7*2*sizeof(int)*(fp->ofdm_symbol_size*12)) );
+    prach_vars[eNB_id]->prach              = (int16_t*)malloc16_clear( sizeof(int)*(7*2*sizeof(int)*(fp->ofdm_symbol_size*12)) );
+    
+    for (i=0; i<fp->nb_antennas_rx; i++) {
+      pbch_vars[eNB_id]->rxdataF_ext[i]    = (int32_t*)malloc16_clear( sizeof(int32_t)*6*12*4 );
+      
+      for (j=0; j<4; j++) {//fp->nb_antennas_tx;j++) {
+	int idx = (j<<1)+i;
+	pbch_vars[eNB_id]->rxdataF_comp[idx]        = (int32_t*)malloc16_clear( sizeof(int32_t)*6*12*4 );
+	pbch_vars[eNB_id]->dl_ch_estimates_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t)*6*12*4 );
+      }
+    }
+  
+    
     pbch_vars[eNB_id]->decoded_output = (uint8_t*)malloc16_clear( 64 );
   }
 
@@ -1476,16 +1530,12 @@ int init_lte_ue_signal(PHY_VARS_UE *ue,
   pdsch_vars_th1[eNB_id]     = (LTE_UE_PDSCH *)malloc16_clear( sizeof(LTE_UE_PDSCH) );
   pdsch_vars_SI[eNB_id]  = (LTE_UE_PDSCH *)malloc16_clear( sizeof(LTE_UE_PDSCH) );
   pdsch_vars_ra[eNB_id]  = (LTE_UE_PDSCH *)malloc16_clear( sizeof(LTE_UE_PDSCH) );
-
-  if (abstraction_flag == 0) {
-    phy_init_lte_ue__PDSCH( pdsch_vars_th0[eNB_id], fp );
-    pdsch_vars_th0[eNB_id]->llr[1] = (int16_t*)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) );
-
-    phy_init_lte_ue__PDSCH( pdsch_vars_th1[eNB_id], fp );
-    pdsch_vars_th1[eNB_id]->llr[1] = (int16_t*)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) );
-  } else { //abstraction == 1
-    ue->sinr_dB = (double*) malloc16_clear( fp->N_RB_DL*12*sizeof(double) );
-  }
+  
+  phy_init_lte_ue__PDSCH( pdsch_vars_th0[eNB_id], fp );
+  pdsch_vars_th0[eNB_id]->llr[1] = (int16_t*)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) );
+  
+  phy_init_lte_ue__PDSCH( pdsch_vars_th1[eNB_id], fp );
+  pdsch_vars_th1[eNB_id]->llr[1] = (int16_t*)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) );
 
   ue->sinr_CQI_dB = (double*) malloc16_clear( fp->N_RB_DL*12*sizeof(double) );
 
@@ -1639,12 +1689,14 @@ int phy_init_lte_eNB(PHY_VARS_eNB *eNB,
 {
 
   // shortcuts
-  LTE_DL_FRAME_PARMS* const fp      = &eNB->frame_parms;
-  LTE_eNB_COMMON* const common_vars = &eNB->common_vars;
-  LTE_eNB_PUSCH** const pusch_vars  = eNB->pusch_vars;
-  LTE_eNB_SRS* const srs_vars       = eNB->srs_vars;
-  LTE_eNB_PRACH* const prach_vars   = &eNB->prach_vars;
-
+  LTE_DL_FRAME_PARMS* const fp       = &eNB->frame_parms;
+  LTE_eNB_COMMON* const common_vars  = &eNB->common_vars;
+  LTE_eNB_PUSCH** const pusch_vars   = eNB->pusch_vars;
+  LTE_eNB_SRS* const srs_vars        = eNB->srs_vars;
+  LTE_eNB_PRACH* const prach_vars    = &eNB->prach_vars;
+#ifdef Rel14
+  LTE_eNB_PRACH* const prach_vars_br = &eNB->prach_vars_br;
+#endif
   int i,  eNB_id, UE_id; 
 
 
@@ -1680,55 +1732,61 @@ int phy_init_lte_eNB(PHY_VARS_eNB *eNB,
   
 
 
-  if (abstraction_flag==0) {
     
-    common_vars->rxdata  = (int32_t **)NULL;
-    common_vars->txdataF = (int32_t **)malloc16(NB_ANTENNA_PORTS_ENB*sizeof(int32_t*));
-    common_vars->rxdataF = (int32_t **)malloc16(64*sizeof(int32_t*));
-
-    for (i=0; i<NB_ANTENNA_PORTS_ENB; i++) {
-      if (i<fp->nb_antenna_ports_eNB || i==5) {
-	common_vars->txdataF[i] = (int32_t*)malloc16_clear(fp->ofdm_symbol_size*fp->symbols_per_tti*10*sizeof(int32_t) );
-
-	LOG_D(PHY,"[INIT] common_vars->txdataF[%d] = %p (%lu bytes)\n",
-	       i,common_vars->txdataF[i],
-	       fp->ofdm_symbol_size*fp->symbols_per_tti*10*sizeof(int32_t));
-      }
+  common_vars->rxdata  = (int32_t **)NULL;
+  common_vars->txdataF = (int32_t **)malloc16(NB_ANTENNA_PORTS_ENB*sizeof(int32_t*));
+  common_vars->rxdataF = (int32_t **)malloc16(64*sizeof(int32_t*));
+  
+  for (i=0; i<NB_ANTENNA_PORTS_ENB; i++) {
+    if (i<fp->nb_antenna_ports_eNB || i==5) {
+      common_vars->txdataF[i] = (int32_t*)malloc16_clear(fp->ofdm_symbol_size*fp->symbols_per_tti*10*sizeof(int32_t) );
+      
+      LOG_D(PHY,"[INIT] common_vars->txdataF[%d] = %p (%lu bytes)\n",
+	    i,common_vars->txdataF[i],
+	    fp->ofdm_symbol_size*fp->symbols_per_tti*10*sizeof(int32_t));
+    }
+  }  
+  
+  
+  // Channel estimates for SRS
+  for (UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) {
+    
+    srs_vars[UE_id].srs_ch_estimates      = (int32_t**)malloc16( 64*sizeof(int32_t*) );
+    srs_vars[UE_id].srs_ch_estimates_time = (int32_t**)malloc16( 64*sizeof(int32_t*) );
+    
+    for (i=0; i<64; i++) {
+      srs_vars[UE_id].srs_ch_estimates[i]      = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->ofdm_symbol_size );
+      srs_vars[UE_id].srs_ch_estimates_time[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->ofdm_symbol_size*2 );
     }
-        
+  } //UE_id
 
 
-    // Channel estimates for SRS
-    for (UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) {
-      
-      srs_vars[UE_id].srs_ch_estimates      = (int32_t**)malloc16( 64*sizeof(int32_t*) );
-      srs_vars[UE_id].srs_ch_estimates_time = (int32_t**)malloc16( 64*sizeof(int32_t*) );
-      
-      for (i=0; i<64; i++) {
-	srs_vars[UE_id].srs_ch_estimates[i]      = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->ofdm_symbol_size );
-	srs_vars[UE_id].srs_ch_estimates_time[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->ofdm_symbol_size*2 );
-      }
-    } //UE_id
-  } // abstraction_flag = 0
-  else { //UPLINK abstraction = 1
-    eNB->sinr_dB = (double*) malloc16_clear( fp->N_RB_DL*12*sizeof(double) );
+  generate_ul_ref_sigs_rx();
+  
+  // SRS
+  for (UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) {
+    srs_vars[UE_id].srs = (int32_t*)malloc16_clear(2*fp->ofdm_symbol_size*sizeof(int32_t));
   }
 
+  // PRACH
+  prach_vars->prachF = (int16_t*)malloc16_clear( 1024*2*sizeof(int16_t) );
+
+  // assume maximum of 64 RX antennas for PRACH receiver
+  prach_vars->prach_ifft       = (int16_t***)malloc16_clear(4*sizeof(int32_t**));
+  prach_vars->prach_ifft[0]    = (int16_t**)malloc16_clear(2*sizeof(int32_t*)); 
+  prach_vars->prach_ifft[0][0] = (int16_t*)malloc16_clear(1024*2*sizeof(int32_t));
   
-  if (abstraction_flag==0) {
-    generate_ul_ref_sigs_rx();
-    
-    // SRS
-    for (UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) {
-      srs_vars[UE_id].srs = (int32_t*)malloc16_clear(2*fp->ofdm_symbol_size*sizeof(int32_t));
-    }
+  // PRACH BR
+#ifdef Rel14
+  prach_vars_br->prachF = (int16_t*)malloc16_clear( 1024*2*sizeof(int32_t) );
+
+  // assume maximum of 64 RX antennas for PRACH receiver
+  prach_vars_br->prach_ifft    = (int32_t***)malloc16_clear(4*sizeof(int32_t**));
+  for (int ce_level=0;ce_level<4;ce_level++) {
+    prach_vars_br->prach_ifft[ce_level] = (int32_t**)malloc16_clear(64*sizeof(int32_t*)); 
+    for (i=0; i<64; i++) prach_vars_br->prach_ifft[ce_level][i] = (int32_t*)malloc16_clear(1024*2*sizeof(int32_t));
   }
-  
-  
-  
-  
-  
-  prach_vars->prachF = (int16_t*)malloc16_clear( 1024*2*sizeof(int16_t) );
+#endif
   
   /* number of elements of an array X is computed as sizeof(X) / sizeof(X[0]) 
   AssertFatal(fp->nb_antennas_rx <= sizeof(prach_vars->rxsigF) / sizeof(prach_vars->rxsigF[0]),
@@ -1738,40 +1796,35 @@ int phy_init_lte_eNB(PHY_VARS_eNB *eNB,
     LOG_D(PHY,"[INIT] prach_vars->rxsigF[%d] = %p\n",i,prach_vars->rxsigF[i]);
     }*/
   
-
-
-  
   for (UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) {
     
     //FIXME
     pusch_vars[UE_id] = (LTE_eNB_PUSCH*)malloc16_clear( NUMBER_OF_UE_MAX*sizeof(LTE_eNB_PUSCH) );
     
-    if (abstraction_flag==0) {
-      pusch_vars[UE_id]->rxdataF_ext      = (int32_t**)malloc16( 2*sizeof(int32_t*) );
-      pusch_vars[UE_id]->rxdataF_ext2     = (int32_t**)malloc16( 2*sizeof(int32_t*) );
-      pusch_vars[UE_id]->drs_ch_estimates = (int32_t**)malloc16( 2*sizeof(int32_t*) );
-      pusch_vars[UE_id]->drs_ch_estimates_time = (int32_t**)malloc16( 2*sizeof(int32_t*) );
-      pusch_vars[UE_id]->rxdataF_comp     = (int32_t**)malloc16( 2*sizeof(int32_t*) );
-      pusch_vars[UE_id]->ul_ch_mag  = (int32_t**)malloc16( 2*sizeof(int32_t*) );
-      pusch_vars[UE_id]->ul_ch_magb = (int32_t**)malloc16( 2*sizeof(int32_t*) );
-
-      AssertFatal(fp->ofdm_symbol_size > 127, "fp->ofdm_symbol_size %d<128\n",fp->ofdm_symbol_size);
-      AssertFatal(fp->symbols_per_tti > 11, "fp->symbols_per_tti %d < 12\n",fp->symbols_per_tti);
-      AssertFatal(fp->N_RB_UL > 5, "fp->N_RB_UL %d < 6\n",fp->N_RB_UL);
-      for (i=0; i<2; i++) {
-	// RK 2 times because of output format of FFT!
-	// FIXME We should get rid of this
-	pusch_vars[UE_id]->rxdataF_ext[i]      = (int32_t*)malloc16_clear( 2*sizeof(int32_t)*fp->N_RB_UL*12*fp->symbols_per_tti );
-	pusch_vars[UE_id]->rxdataF_ext2[i]     = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->N_RB_UL*12*fp->symbols_per_tti );
-	pusch_vars[UE_id]->drs_ch_estimates[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->N_RB_UL*12*fp->symbols_per_tti );
-	pusch_vars[UE_id]->drs_ch_estimates_time[i] = (int32_t*)malloc16_clear( 2*2*sizeof(int32_t)*fp->ofdm_symbol_size );
-	pusch_vars[UE_id]->rxdataF_comp[i]     = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->N_RB_UL*12*fp->symbols_per_tti );
-	pusch_vars[UE_id]->ul_ch_mag[i]  = (int32_t*)malloc16_clear( fp->symbols_per_tti*sizeof(int32_t)*fp->N_RB_UL*12 );
-	pusch_vars[UE_id]->ul_ch_magb[i] = (int32_t*)malloc16_clear( fp->symbols_per_tti*sizeof(int32_t)*fp->N_RB_UL*12 );
+    pusch_vars[UE_id]->rxdataF_ext      = (int32_t**)malloc16( 2*sizeof(int32_t*) );
+    pusch_vars[UE_id]->rxdataF_ext2     = (int32_t**)malloc16( 2*sizeof(int32_t*) );
+    pusch_vars[UE_id]->drs_ch_estimates = (int32_t**)malloc16( 2*sizeof(int32_t*) );
+    pusch_vars[UE_id]->drs_ch_estimates_time = (int32_t**)malloc16( 2*sizeof(int32_t*) );
+    pusch_vars[UE_id]->rxdataF_comp     = (int32_t**)malloc16( 2*sizeof(int32_t*) );
+    pusch_vars[UE_id]->ul_ch_mag  = (int32_t**)malloc16( 2*sizeof(int32_t*) );
+    pusch_vars[UE_id]->ul_ch_magb = (int32_t**)malloc16( 2*sizeof(int32_t*) );
+    
+    AssertFatal(fp->ofdm_symbol_size > 127, "fp->ofdm_symbol_size %d<128\n",fp->ofdm_symbol_size);
+    AssertFatal(fp->symbols_per_tti > 11, "fp->symbols_per_tti %d < 12\n",fp->symbols_per_tti);
+    AssertFatal(fp->N_RB_UL > 5, "fp->N_RB_UL %d < 6\n",fp->N_RB_UL);
+    for (i=0; i<2; i++) {
+      // RK 2 times because of output format of FFT!
+      // FIXME We should get rid of this
+      pusch_vars[UE_id]->rxdataF_ext[i]      = (int32_t*)malloc16_clear( 2*sizeof(int32_t)*fp->N_RB_UL*12*fp->symbols_per_tti );
+      pusch_vars[UE_id]->rxdataF_ext2[i]     = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->N_RB_UL*12*fp->symbols_per_tti );
+      pusch_vars[UE_id]->drs_ch_estimates[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->N_RB_UL*12*fp->symbols_per_tti );
+      pusch_vars[UE_id]->drs_ch_estimates_time[i] = (int32_t*)malloc16_clear( 2*2*sizeof(int32_t)*fp->ofdm_symbol_size );
+      pusch_vars[UE_id]->rxdataF_comp[i]     = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->N_RB_UL*12*fp->symbols_per_tti );
+      pusch_vars[UE_id]->ul_ch_mag[i]  = (int32_t*)malloc16_clear( fp->symbols_per_tti*sizeof(int32_t)*fp->N_RB_UL*12 );
+      pusch_vars[UE_id]->ul_ch_magb[i] = (int32_t*)malloc16_clear( fp->symbols_per_tti*sizeof(int32_t)*fp->N_RB_UL*12 );
       }
-      
-      pusch_vars[UE_id]->llr = (int16_t*)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) );
-    } // abstraction_flag
+    
+    pusch_vars[UE_id]->llr = (int16_t*)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) );
   } //UE_id
 
     
diff --git a/openair1/PHY/LTE_TRANSPORT/if4_tools.c b/openair1/PHY/LTE_TRANSPORT/if4_tools.c
index d832d7498c..1c77083deb 100644
--- a/openair1/PHY/LTE_TRANSPORT/if4_tools.c
+++ b/openair1/PHY/LTE_TRANSPORT/if4_tools.c
@@ -43,12 +43,15 @@ const uint8_t lin2alaw_if4p5[65536] = {213, 213, 213, 213, 213, 213, 213, 213, 2
 
 void send_IF4p5(RU_t *ru, int frame, int subframe, uint16_t packet_type) {
 
-  LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
-  int32_t **txdataF      = ru->common.txdataF_BF;
-  int32_t **rxdataF      = ru->common.rxdataF;
-  int16_t **prach_rxsigF = ru->prach_rxsigF;  
-  void *tx_buffer        = ru->ifbuffer.tx[subframe&1];
-  void *tx_buffer_prach  = ru->ifbuffer.tx_prach;
+  LTE_DL_FRAME_PARMS *fp     = &ru->frame_parms;
+  int32_t **txdataF          = ru->common.txdataF_BF;
+  int32_t **rxdataF          = ru->common.rxdataF;
+  int16_t **prach_rxsigF     = ru->prach_rxsigF;  
+#ifdef Rel14
+  int16_t ***prach_rxsigF_br = ru->prach_rxsigF_br;
+#endif
+  void *tx_buffer            = ru->ifbuffer.tx[subframe&1];
+  void *tx_buffer_prach      = ru->ifbuffer.tx_prach;
 
 
   uint16_t symbol_id=0, element_id=0;
@@ -175,7 +178,8 @@ void send_IF4p5(RU_t *ru, int frame, int subframe, uint16_t packet_type) {
 	perror("ETHERNET write for IF4p5_PULFFT\n");
       }
     }
-  } else if (packet_type == IF4p5_PRACH) {
+  } else if (packet_type >= IF4p5_PRACH && 
+	     packet_type <= IF4p5_PRACH+4) {
     // FIX: hard coded prach samples length
     LOG_D(PHY,"IF4p5_PRACH: frame %d, subframe %d\n",frame,subframe);
     db_fulllength = PRACH_NUM_SAMPLES;
@@ -189,13 +193,24 @@ void send_IF4p5(RU_t *ru, int frame, int subframe, uint16_t packet_type) {
     }  
     gen_IF4p5_prach_header(packet_header, frame, subframe);
 
+
+    int16_t *rxF;
+
+#ifdef Rel14
+    if (packet_type > IF4p5_PRACH)
+      rxF = &prach_rxsigF_br[packet_type - IF4p5_PRACH - 1][0][0];
+    else 
+#else
+      rxF = &prach_rxsigF[0][0];
+#endif    
+
     if (eth->flags == ETH_RAW_IF4p5_MODE) {
-      memcpy((int16_t*)(tx_buffer_prach + MAC_HEADER_SIZE_BYTES + sizeof_IF4p5_header_t),
-             (&prach_rxsigF[0][0]), 
-             PRACH_BLOCK_SIZE_BYTES);
+       memcpy((void *)(tx_buffer_prach + MAC_HEADER_SIZE_BYTES + sizeof_IF4p5_header_t),
+              (void*)rxF, 
+              PRACH_BLOCK_SIZE_BYTES);
     } else {
-      memcpy((int16_t*)(tx_buffer_prach + sizeof_IF4p5_header_t),
-             (&prach_rxsigF[0][0]),
+      memcpy((void *)(tx_buffer_prach + sizeof_IF4p5_header_t),
+             (void *)rxF,
              PRACH_BLOCK_SIZE_BYTES);
     }
     VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF, 1 );
@@ -204,7 +219,7 @@ void send_IF4p5(RU_t *ru, int frame, int subframe, uint16_t packet_type) {
 				     &tx_buffer_prach,
 				     db_fulllength,
 				     1,
-				     IF4p5_PRACH)) < 0) {
+				     packet_type)) < 0) {
       perror("ETHERNET write for IF4p5_PRACH\n");
     }
     VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF, 0 );      
@@ -217,11 +232,14 @@ void send_IF4p5(RU_t *ru, int frame, int subframe, uint16_t packet_type) {
 }
 
 void recv_IF4p5(RU_t *ru, int *frame, int *subframe, uint16_t *packet_type, uint32_t *symbol_number) {
-  LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
-  int32_t **txdataF      = ru->common.txdataF_BF;
-  int32_t **rxdataF      = ru->common.rxdataF;
-  int16_t **prach_rxsigF = ru->prach_rxsigF;  
-  void *rx_buffer        = ru->ifbuffer.rx;
+  LTE_DL_FRAME_PARMS *fp     = &ru->frame_parms;
+  int32_t **txdataF          = ru->common.txdataF_BF;
+  int32_t **rxdataF          = ru->common.rxdataF;
+  int16_t **prach_rxsigF     = ru->prach_rxsigF;  
+#ifdef Rel14
+  int16_t ***prach_rxsigF_br = ru->prach_rxsigF_br;
+#endif
+  void *rx_buffer            = ru->ifbuffer.rx;
 
   uint16_t element_id;
   uint16_t db_fulllength, db_halflength; 
@@ -308,18 +326,28 @@ void recv_IF4p5(RU_t *ru, int *frame, int *subframe, uint16_t *packet_type, uint
 	//if (element_id==0) LOG_I(PHY,"recv_if4p5: symbol %d rxdata0 = (%u,%u)\n",*symbol_number,*i,*(i+1));
     }
     VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_DECOMPR_IF, 0 );		
-  } else if (*packet_type == IF4p5_PRACH) {  
+  } else if (*packet_type >= IF4p5_PRACH &&
+	     *packet_type <= IF4p5_PRACH + 4) {  
 
+    int16_t *rxF;
+    
+#ifdef Rel14
+    if (*packet_type > IF4p5_PRACH)
+      rxF = &prach_rxsigF_br[*packet_type - IF4p5_PRACH - 1][0][0];
+    else 
+#else
+      rxF = &prach_rxsigF[0][0];
+#endif
 
     // FIX: hard coded prach samples length
     db_fulllength = PRACH_NUM_SAMPLES;
 
     if (eth->flags == ETH_RAW_IF4p5_MODE) {		
-      memcpy((&prach_rxsigF[0][0]), 
+      memcpy(rxF, 
              (int16_t*) (rx_buffer+MAC_HEADER_SIZE_BYTES+sizeof_IF4p5_header_t), 
              PRACH_BLOCK_SIZE_BYTES);
     } else {
-      memcpy((&prach_rxsigF[0][0]),
+      memcpy(rxF,
              (int16_t*) (rx_buffer+sizeof_IF4p5_header_t),
              PRACH_BLOCK_SIZE_BYTES);
     }
diff --git a/openair1/PHY/LTE_TRANSPORT/if4_tools.h b/openair1/PHY/LTE_TRANSPORT/if4_tools.h
index 7a084a4b51..830c580eb0 100644
--- a/openair1/PHY/LTE_TRANSPORT/if4_tools.h
+++ b/openair1/PHY/LTE_TRANSPORT/if4_tools.h
@@ -39,7 +39,11 @@
 #define IF4p5_PULFFT 0x0019 
 #define IF4p5_PDLFFT 0x0020
 #define IF4p5_PRACH 0x0021
-#define IF4p5_PULTICK 0x0022
+#define IF4p5_PRACH_BR_CE0 0x0021
+#define IF4p5_PRACH_BR_CE1 0x0022
+#define IF4p5_PRACH_BR_CE2 0x0023
+#define IF4p5_PRACH_BR_CE3 0x0024
+#define IF4p5_PULTICK 0x0025
 
 struct IF4p5_header {  
   /// Type
diff --git a/openair1/PHY/LTE_TRANSPORT/prach.c b/openair1/PHY/LTE_TRANSPORT/prach.c
index dff9c62d24..e616741e13 100644
--- a/openair1/PHY/LTE_TRANSPORT/prach.c
+++ b/openair1/PHY/LTE_TRANSPORT/prach.c
@@ -428,12 +428,14 @@ uint8_t get_prach_fmt(uint8_t prach_ConfigIndex,lte_frame_type_t frame_type)
   }
 }
 
-uint8_t get_prach_prb_offset(LTE_DL_FRAME_PARMS *frame_parms, uint8_t tdd_mapindex, uint16_t Nf) 
+uint8_t get_prach_prb_offset(LTE_DL_FRAME_PARMS *frame_parms, 
+			     uint8_t prach_ConfigIndex, 
+			     uint8_t n_ra_prboffset,
+			     uint8_t tdd_mapindex, uint16_t Nf) 
 {
   lte_frame_type_t frame_type         = frame_parms->frame_type;
   uint8_t tdd_config         = frame_parms->tdd_config;
-  uint8_t prach_ConfigIndex  = frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex;
-  uint8_t n_ra_prboffset     = frame_parms->prach_config_common.prach_ConfigInfo.prach_FreqOffset;
+
   uint8_t n_ra_prb;
   uint8_t f_ra,t1_ra;
   uint8_t prach_fmt = get_prach_fmt(prach_ConfigIndex,frame_type);
@@ -474,92 +476,90 @@ uint8_t get_prach_prb_offset(LTE_DL_FRAME_PARMS *frame_parms, uint8_t tdd_mapind
   return(n_ra_prb);
 }
 
-int is_prach_subframe(LTE_DL_FRAME_PARMS *frame_parms,uint32_t frame, uint8_t subframe)
+int is_prach_subframe0(LTE_DL_FRAME_PARMS *frame_parms,uint8_t prach_ConfigIndex,uint32_t frame, uint8_t subframe)
 {
-
-  uint8_t prach_ConfigIndex  = frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex;
+  //  uint8_t prach_ConfigIndex  = frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex;
   uint8_t tdd_config         = frame_parms->tdd_config;
   uint8_t t0_ra;
   uint8_t t1_ra;
   uint8_t t2_ra;
 
+  int prach_mask = 0;
 
   if (frame_parms->frame_type == FDD) { //FDD
     //implement Table 5.7.1-2 from 36.211 (Rel-10, p.41)
     if ((((frame&1) == 1) && (subframe < 9)) ||
         (((frame&1) == 0) && (subframe == 9)))  // This is an odd frame, ignore even-only PRACH frames
+
+      /*
       if (((prach_ConfigIndex&0xf)<3) || // 0,1,2,16,17,18,32,33,34,48,49,50
           ((prach_ConfigIndex&0x1f)==18) || // 18,50
           ((prach_ConfigIndex&0xf)==15))   // 15,47
         return(0);
+      */
 
     switch (prach_ConfigIndex&0x1f) {
     case 0:
     case 3:
-      return(subframe==1);
+      if (subframe==1) prach_mask = 1;
       break;
 
     case 1:
     case 4:
-      return(subframe==4);
+      if (subframe==4) prach_mask = 1;
       break;
 
     case 2:
     case 5:
-      return(subframe==7);
+      if (subframe==7) prach_mask = 1;
       break;
 
     case 6:
-      return((subframe==1) || (subframe==6));
+      if ((subframe==1) || (subframe==6)) prach_mask=1;
       break;
 
     case 7:
-      return((subframe==2) || (subframe==7));
+      if ((subframe==2) || (subframe==7)) prach_mask=1;
       break;
 
     case 8:
-      return((subframe==3) || (subframe==8));
+      if ((subframe==3) || (subframe==8)) prach_mask=1;
       break;
 
     case 9:
-      return((subframe==1) || (subframe==4) || (subframe==7));
+      if ((subframe==1) || (subframe==4) || (subframe==7)) prach_mask=1;
       break;
 
     case 10:
-      return((subframe==2) || (subframe==5) || (subframe==8));
+      if ((subframe==2) || (subframe==5) || (subframe==8)) prach_mask=1;
       break;
 
     case 11:
-      return((subframe==3) || (subframe==6) || (subframe==9));
+      if ((subframe==3) || (subframe==6) || (subframe==9)) prach_mask=1;
       break;
 
     case 12:
-      return((subframe&1)==0);
+      if ((subframe&1)==0) prach_mask=1;
       break;
 
     case 13:
-      return((subframe&1)==1);
+      if ((subframe&1)==1) prach_mask=1;
       break;
 
     case 14:
-      return(1==1);
+      prach_mask=1;
       break;
 
     case 15:
-      return(subframe==9);
+      if (subframe==9) prach_mask=1;
       break;
     }
   } else { // TDD
 
-    if (prach_ConfigIndex>=64) {
-      LOG_E(PHY,"[PHY] Illegal prach_ConfigIndex %d for ",prach_ConfigIndex);
-      return(0);
-    }
-
-    if (tdd_preamble_map[prach_ConfigIndex][tdd_config].num_prach==0) {
-      LOG_E(PHY,"[PHY] Illegal prach_ConfigIndex %d for ",prach_ConfigIndex);
-      return(0);
-    }
+    AssertFatal(prach_ConfigIndex<64,
+		"Illegal prach_ConfigIndex %d for ",prach_ConfigIndex);
+    AssertFatal(tdd_preamble_map[prach_ConfigIndex][tdd_config].num_prach>0,
+		"Illegal prach_ConfigIndex %d for ",prach_ConfigIndex);
 
     t0_ra = tdd_preamble_map[prach_ConfigIndex][tdd_config].map[0].t0_ra;
     t1_ra = tdd_preamble_map[prach_ConfigIndex][tdd_config].map[0].t1_ra;
@@ -576,16 +576,29 @@ int is_prach_subframe(LTE_DL_FRAME_PARMS *frame_parms,uint32_t frame, uint8_t su
          (t0_ra == 0)) &&                                // PRACH is in all frames
         (((subframe<5)&&(t1_ra==0)) ||                   // PRACH is in 1st half-frame
          (((subframe>4)&&(t1_ra==1))))) {                // PRACH is in 2nd half-frame
-      if (prach_ConfigIndex<48)                          // PRACH only in normal UL subframe
-        return((((subframe%5)-2)==t2_ra));
-      else                                               // PRACH can be in UpPTS
-        return((((subframe%5)-1)==t2_ra));
-    } else
-      return(1==2);
+      if ((prach_ConfigIndex<48) &&                          // PRACH only in normal UL subframe
+	  (((subframe%5)-2)==t2_ra)) prach_mask=1;
+      else if ((((subframe%5)-1)==t2_ra)) prach_mask=1;      // PRACH can be in UpPTS
+    }
   }
 
-  // shouldn't get here!
-  return(2==1);
+  return(prach_mask);
+}
+
+int is_prach_subframe(LTE_DL_FRAME_PARMS *frame_parms,uint32_t frame, uint8_t subframe) {
+  
+  uint8_t prach_ConfigIndex  = frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex;
+  int prach_mask             = is_prach_subframe0(frame_parms,prach_ConfigIndex,frame,subframe);
+
+#ifdef Rel14
+  int i;
+
+  for (i=0;i<4;i++) {
+    if (frame_parms->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[i] == 1) 
+      prach_mask|=(is_prach_subframe0(frame_parms,frame_parms->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[i],frame,subframe)<<(i+1));
+  }
+#endif
+  return(prach_mask);
 }
 
 int32_t generate_prach( PHY_VARS_UE *ue, uint8_t eNB_id, uint8_t subframe, uint16_t Nf )
@@ -665,7 +678,10 @@ int32_t generate_prach( PHY_VARS_UE *ue, uint8_t eNB_id, uint8_t subframe, uint1
     NCS = NCS_restricted[Ncs_config];
   }
 
-  n_ra_prb = get_prach_prb_offset(&(ue->frame_parms), tdd_mapindex, Nf);
+  n_ra_prb = get_prach_prb_offset(&(ue->frame_parms),
+				  ue->frame_parms.prach_config_common.prach_ConfigInfo.prach_ConfigIndex,
+				  ue->frame_parms.prach_config_common.prach_ConfigInfo.prach_FreqOffset,
+				  tdd_mapindex, Nf);
   prach_root_sequence_map = (prach_fmt<4) ? prach_root_sequence_map0_3 : prach_root_sequence_map4;
 
   /*
@@ -1077,12 +1093,18 @@ int32_t generate_prach( PHY_VARS_UE *ue, uint8_t eNB_id, uint8_t subframe, uint1
 }
 //__m128i mmtmpX0,mmtmpX1,mmtmpX2,mmtmpX3;
 
-void rx_prach(PHY_VARS_eNB *eNB,
-	      RU_t *ru,
-	      uint16_t *preamble_energy_list, 
-	      uint16_t *preamble_delay_list, 
-	      uint16_t Nf, 
-	      uint8_t tdd_mapindex)
+void rx_prach0(PHY_VARS_eNB *eNB,
+	       RU_t *ru,
+	       int16_t *max_preamble,
+	       int16_t *max_preamble_energy,
+	       int16_t *max_preamble_delay,
+	       uint16_t Nf, 
+	       uint8_t tdd_mapindex
+#ifdef Rel14
+	       ,uint8_t br_flag,
+	       uint8_t ce_level
+#endif
+	       )
 {
 
   int i;
@@ -1093,46 +1115,14 @@ void rx_prach(PHY_VARS_eNB *eNB,
   uint8_t            prach_ConfigIndex;   
   uint8_t            Ncs_config;          
   uint8_t            restricted_set;      
+  uint8_t            n_ra_prb;
 
   int                subframe;
   int16_t            *prachF=NULL;
   int16_t            **rxsigF=NULL;
-  int16_t            **prach_ifft=NULL;
   int                nb_rx;
 
-  if (ru) { 
-    fp    = &ru->frame_parms;
-    nb_rx = ru->nb_rx;
-  }
-  else if (eNB) {
-    fp    = &eNB->frame_parms;
-    nb_rx = fp->nb_antennas_rx;
-  }
-  else AssertFatal(1==0,"rx_prach called without valid RU or eNB descriptor\n");
-  
-  frame_type          = fp->frame_type;
-  rootSequenceIndex   = fp->prach_config_common.rootSequenceIndex;
-  prach_ConfigIndex   = fp->prach_config_common.prach_ConfigInfo.prach_ConfigIndex;
-  Ncs_config          = fp->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig;
-  restricted_set      = fp->prach_config_common.prach_ConfigInfo.highSpeedFlag;
-
-  int16_t *prach[nb_rx];
-
-  if (eNB) {
-    subframe          = eNB->proc.subframe_prach;
-    prachF            = eNB->prach_vars.prachF;
-    rxsigF            = eNB->prach_vars.rxsigF;
-    prach_ifft        = eNB->prach_vars.prach_ifft;
-  }
-  else {
-    subframe          = ru->proc.subframe_prach;
-    rxsigF            = ru->prach_rxsigF;
-    LOG_D(PHY,"PRACH (RU) : running rx_prach for subframe %d, prach_FreqOffset %d, prach_ConfigIndex %d\n",
-	  subframe,fp->prach_config_common.prach_ConfigInfo.prach_FreqOffset,prach_ConfigIndex);
-  }
-
   int16_t *prach2;
-  uint8_t n_ra_prb;
   uint8_t preamble_index;
   uint16_t NCS,NCS2;
   uint16_t preamble_offset=0,preamble_offset_old;
@@ -1156,12 +1146,96 @@ void rx_prach(PHY_VARS_eNB *eNB,
   int32_t lev;
   int16_t levdB;
   int fft_size,log2_ifft_size;
-
-
+  int16_t prach_ifft_tmp[2048*2] __attribute__((aligned(32)));
+  int32_t *prach_ifft;
+  int32_t **prach_ifftp;
+#ifdef Rel14
+  int prach_ifft_cnt=0;
+#endif
 #ifdef PRACH_DEBUG
   int en,en0=0;
 #endif
 
+  if (ru) { 
+    fp    = &ru->frame_parms;
+    nb_rx = ru->nb_rx;
+  }
+  else if (eNB) {
+    fp    = &eNB->frame_parms;
+    nb_rx = fp->nb_antennas_rx;
+  }
+  else AssertFatal(1==0,"rx_prach called without valid RU or eNB descriptor\n");
+  
+  frame_type          = fp->frame_type;
+
+#ifdef Rel14
+  if (br_flag == 1) {
+    AssertFatal(fp->prach_emtc_config_common.prach_Config_enabled==1,
+		"emtc prach_Config is not enabled\n");
+    AssertFatal(fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[ce_level]==1,
+		"ce_level %d is not active\n",ce_level);
+    rootSequenceIndex   = fp->prach_emtc_config_common.rootSequenceIndex;
+    prach_ConfigIndex   = fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[ce_level];
+    Ncs_config          = fp->prach_emtc_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig;
+    restricted_set      = fp->prach_emtc_config_common.prach_ConfigInfo.highSpeedFlag;
+    n_ra_prb            = get_prach_prb_offset(fp,prach_ConfigIndex,
+					       fp->prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[ce_level],
+					       tdd_mapindex,Nf);
+    // update pointers to results for ce_level
+    max_preamble        += ce_level;
+    max_preamble_energy += ce_level;
+    max_preamble_delay  += ce_level;
+  }
+  else 
+#endif
+    {
+      rootSequenceIndex   = fp->prach_config_common.rootSequenceIndex;
+      prach_ConfigIndex   = fp->prach_config_common.prach_ConfigInfo.prach_ConfigIndex;
+      Ncs_config          = fp->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig;
+      restricted_set      = fp->prach_config_common.prach_ConfigInfo.highSpeedFlag;
+      n_ra_prb            = get_prach_prb_offset(fp,prach_ConfigIndex,
+						 fp->prach_config_common.prach_ConfigInfo.prach_FreqOffset,
+						 tdd_mapindex,Nf);
+    }
+
+  int16_t *prach[nb_rx];
+  
+  if (eNB) {
+#ifdef Rel14
+    if (br_flag == 1) {
+      prach_ifftp         = eNB->prach_vars_br.prach_ifft[ce_level];
+      subframe            = eNB->proc.subframe_prach_br;
+      prachF              = eNB->prach_vars_br.prachF;
+      rxsigF              = eNB->prach_vars_br.rxsigF;
+    }
+    else
+#endif
+      {
+        prach_ifftp       = eNB->prach_vars.prach_ifft[0];
+        subframe          = eNB->proc.subframe_prach;
+        prachF            = eNB->prach_vars.prachF;
+        rxsigF            = eNB->prach_vars.rxsigF;
+      }
+  }
+  else {
+#ifdef Rel14
+    if (br_flag == 1) {
+        subframe          = ru->proc.subframe_prach_br;
+        rxsigF            = ru->prach_rxsigF_br[ce_level];
+        LOG_D(PHY,"PRACH (RU) : running rx_prach for subframe %d, prach_FreqOffset %d, prach_ConfigIndex %d\n",
+	      subframe,fp->prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[ce_level],prach_ConfigIndex);
+    }
+    else
+#endif
+      {
+        subframe          = ru->proc.subframe_prach;
+        rxsigF            = ru->prach_rxsigF;
+        LOG_D(PHY,"PRACH (RU) : running rx_prach for subframe %d, prach_FreqOffset %d, prach_ConfigIndex %d\n",
+	      subframe,fp->prach_config_common.prach_ConfigInfo.prach_FreqOffset,prach_ConfigIndex);
+      }
+
+  }
+
   AssertFatal(ru!=NULL,"ru is null\n");
 
   for (aa=0; aa<nb_rx; aa++) {
@@ -1186,7 +1260,7 @@ void rx_prach(PHY_VARS_eNB *eNB,
 
   if (eNB) start_meas(&eNB->rx_prach);
 
-  n_ra_prb = get_prach_prb_offset(fp,tdd_mapindex,Nf);
+
   prach_root_sequence_map = (prach_fmt < 4) ? prach_root_sequence_map0_3 : prach_root_sequence_map4;
 
   // PDP is oversampled, e.g. 1024 sample instead of 839
@@ -1371,8 +1445,13 @@ void rx_prach(PHY_VARS_eNB *eNB,
 
   if ((eNB==NULL) && (ru!=NULL) && ru->function == NGFI_RRU_IF4p5) {
 
-    /// **** send_IF4 of rxsigF to RAU **** ///    
-    send_IF4p5(ru, ru->proc.frame_prach, ru->proc.subframe_prach, IF4p5_PRACH);
+    /// **** send_IF4 of rxsigF to RAU **** ///
+#ifdef Rel14
+    if (br_flag == 1) send_IF4p5(ru, ru->proc.frame_prach, ru->proc.subframe_prach, IF4p5_PRACH+1+ce_level);      
+
+    else
+#endif
+      send_IF4p5(ru, ru->proc.frame_prach, ru->proc.subframe_prach, IF4p5_PRACH);
     
 #if 0
     if (dB_fixed(en0)>30) {
@@ -1402,6 +1481,30 @@ void rx_prach(PHY_VARS_eNB *eNB,
 
   preamble_offset_old = 99;
 
+  uint8_t update_TA  = 4;
+  uint8_t update_TA2 = 1;
+  switch (eNB->frame_parms.N_RB_DL) {
+  case 6:
+    update_TA = 16;
+    break;
+    
+  case 25:
+    update_TA = 4;
+    break;
+    
+  case 50:
+    update_TA = 2;
+    break;
+    
+  case 75:
+    update_TA  = 3;
+    update_TA2 = 2;
+  case 100:
+    update_TA  = 1;
+    break;
+  }
+  
+  *max_preamble_energy=0;
   for (preamble_index=0 ; preamble_index<64 ; preamble_index++) {
     if (restricted_set == 0) {
       // This is the relative offset in the root sequence table (5.7.2-4 from 36.211) for the given preamble index
@@ -1494,10 +1597,20 @@ void rx_prach(PHY_VARS_eNB *eNB,
     if (new_dft == 1) {
       new_dft = 0;
       Xu=(int16_t*)eNB->X_u[preamble_offset-first_nonzero_root_idx];
-      
 
+#ifdef Rel14
+      if (br_flag == 1) {
+	prach_ifft = prach_ifftp[prach_ifft_cnt++];
+	if (eNB->prach_vars_br.repetition_number[ce_level]==1) memset(prach_ifft,0,((N_ZC==839)?2048:256)*sizeof(int32_t));
+      }
+      else
+#endif
+	{
+	  prach_ifft = prach_ifftp[0];
+          memset(prach_ifft,0,((N_ZC==839) ? 2048 : 256)*sizeof(int32_t));
+	}
 
-      memset( prachF, 0, sizeof(int16_t)*2*1024 );
+      memset(prachF, 0, sizeof(int16_t)*2*1024 );
 #ifdef PRACH_DEBUG
       if (prach[0]!= NULL) write_output("prach_rx0.m","prach_rx0",prach[0],6144+792,1,1);
 #endif
@@ -1506,7 +1619,7 @@ void rx_prach(PHY_VARS_eNB *eNB,
       // write_output("prach_rxF1.m","prach_rxF1",rxsigF[1],6144,1,1);
 
       for (aa=0;aa<nb_rx; aa++) {
-      // Do componentwise product with Xu*
+      // Do componentwise product with Xu* on each antenna 
 
 	k=0;	
 	for (offset=0; offset<(N_ZC<<1); offset+=2) {
@@ -1520,11 +1633,18 @@ void rx_prach(PHY_VARS_eNB *eNB,
 	// Now do IFFT of size 1024 (N_ZC=839) or 256 (N_ZC=139)
 	if (N_ZC == 839) {
 	  log2_ifft_size = 10;
-	  idft1024(prachF,prach_ifft[aa],1);
+	  idft1024(prachF,prach_ifft_tmp,1);
+	  // compute energy and accumulate over receive antennas and repetitions for BR
+	  for (i=0;i<2048;i++)
+	    prach_ifft[i] += (prach_ifft_tmp[i<<1]*prach_ifft_tmp[i<<1] + prach_ifft_tmp[1+(i<<1)]*prach_ifft_tmp[1+(i<<1)])>>15;
 	} else {
-	  idft256(prachF,prach_ifft[aa],1);
+	  idft256(prachF,prach_ifft_tmp,1);
 	  log2_ifft_size = 8;
+	  // compute energy and accumulate over receive antennas and repetitions for BR
+	  for (i=0;i<256;i++)
+	    prach_ifft[i] += (prach_ifft_tmp[i<<1]*prach_ifft_tmp[(i<<1)] + prach_ifft_tmp[1+(i<<1)]*prach_ifft_tmp[1+(i<<1)])>>15;
 	}
+	
 #ifdef PRACH_DEBUG
 	if (aa==0) write_output("prach_rxF_comp0.m","prach_rxF_comp0",prachF,1024,1,1);
 #endif
@@ -1545,42 +1665,85 @@ void rx_prach(PHY_VARS_eNB *eNB,
 	write_output("rxsigF.m","prach_rxF",&rxsigF[0][0],12288,1,1);
 	write_output("prach_rxF_comp0.m","prach_rxF_comp0",prachF,1024,1,1);
 	write_output("Xu.m","xu",Xu,N_ZC,1,1);
-	write_output("prach_ifft0.m","prach_t0",prach_ifft[0],1024,1,1);
+	write_output("prach_ifft0.m","prach_t0",prach_ifft[0][0],1024,1,1);
 	exit(-1);
       }
 #endif
     } // new dft
     
-    // check energy in nth time shift
-    preamble_shift2 = ((preamble_shift==0) ? 0 : ((preamble_shift<<log2_ifft_size)/N_ZC));
-    preamble_energy_list[preamble_index] = 0;
-    
-    for (i=0; i<NCS2; i++) {
-      lev = 0;
-      
-      for (aa=0; aa<nb_rx; aa++) {
-	lev += (int32_t)prach_ifft[aa][(preamble_shift2+i)<<1]*prach_ifft[aa][(preamble_shift2+i)<<1] + (int32_t)prach_ifft[aa][1+((preamble_shift2+i)<<1)]*prach_ifft[aa][1+((preamble_shift2+i)<<1)];
-      }
-     
-      levdB = dB_fixed_times10(lev);
-      
-      if (levdB>preamble_energy_list[preamble_index] ) {
-	preamble_energy_list[preamble_index]  = levdB;
-	preamble_delay_list[preamble_index]   = (i*fft_size)>>log2_ifft_size;
-      }
-    }
-#ifdef PRACH_DEBUG
-    LOG_D(PHY,"[RAPROC] Preamble %d => %d dB, %d (shift %d (%d), NCS2 %d(%d), Ncp %d)\n",preamble_index,preamble_energy_list[preamble_index],preamble_delay_list[preamble_index],preamble_shift2,
-	  preamble_shift, NCS2,NCS,Ncp);
-    //  exit(-1);
+    // check energy in nth time shift, for 
+#ifdef Rel14
+    if ((br_flag==0) ||
+	(eNB->prach_vars_br.repetition_number[ce_level]==
+	 eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[ce_level]))
 #endif
+      {
+	preamble_shift2 = ((preamble_shift==0) ? 0 : ((preamble_shift<<log2_ifft_size)/N_ZC));
 
+    
+	for (i=0; i<NCS2; i++) {
+	  lev = (int32_t)prach_ifft[(preamble_shift2+i)<<1];
+	  levdB = dB_fixed_times10(lev);
+	  
+	  if (levdB>*max_preamble_energy) {
+	    *max_preamble_energy  = levdB;
+	    *max_preamble_delay   = ((i*fft_size)>>log2_ifft_size)*update_TA/update_TA2;
+	    *max_preamble         = preamble_index;
+	  }
+	}
+      }
   }// preamble_index
-  
+
   if (eNB) stop_meas(&eNB->rx_prach);
-  
+
 }
 
+
+
+#ifndef Rel14
+#define rx_prach rx_prach0
+#else
+void rx_prach(PHY_VARS_eNB *eNB,
+	      RU_t *ru,
+	      uint16_t *max_preamble,
+	      uint16_t *max_preamble_energy,
+	      uint16_t *max_preamble_delay,
+	      uint16_t Nf, 
+	      uint8_t tdd_mapindex,
+	      uint8_t br_flag) {
+
+  int i;
+  int prach_mask=0;
+
+  if (br_flag == 0) { 
+    rx_prach0(eNB,ru,max_preamble,max_preamble_energy,max_preamble_delay,Nf,tdd_mapindex,0,0);
+  }
+  else { // This is procedure for eMTC, basically handling the repetitions
+    prach_mask = is_prach_subframe(&eNB->frame_parms,eNB->proc.frame_prach_br,eNB->proc.subframe_prach_br);
+    for (i=0;i<4;i++) {
+      if ((eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[i]==1) &&
+	  ((prach_mask&(1<<(i+1))) > 0)) { // check that prach CE level is active now
+
+	// if first reception in group of repetitions store frame for later (in RA-RNTI for Msg2) 
+	if (eNB->prach_vars_br.repetition_number[i]==0) eNB->prach_vars_br.first_frame[i]=eNB->proc.frame_prach_br;
+
+	// increment repetition number
+	eNB->prach_vars_br.repetition_number[i]++;
+
+	// do basic PRACH reception
+	rx_prach0(eNB,ru,max_preamble,max_preamble_energy,max_preamble_delay,Nf,tdd_mapindex,1,i);
+	
+	// if last repetition, clear counter
+	if (eNB->prach_vars_br.repetition_number[i] == eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[i]) {
+	  eNB->prach_vars_br.repetition_number[i]=0;
+
+	}
+      }
+    }
+  }
+}
+#endif
+
 void init_prach_tables(int N_ZC)
 {
 
diff --git a/openair1/PHY/LTE_TRANSPORT/proto.h b/openair1/PHY/LTE_TRANSPORT/proto.h
index c1e3148ee4..024da7a810 100644
--- a/openair1/PHY/LTE_TRANSPORT/proto.h
+++ b/openair1/PHY/LTE_TRANSPORT/proto.h
@@ -2074,14 +2074,21 @@ int32_t generate_prach(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t subframe,
   \brief Process PRACH waveform
   @param phy_vars_eNB Pointer to eNB top-level descriptor. If NULL, then this is an RRU
   @param ru Pointer to RU top-level descriptor. If NULL, then this is an eNB and we make use of the RU_list
-  @param preamble_energy_list List of energies for each candidate preamble
-  @param preamble_delay_list List of delays for each candidate preamble
+  @param max_preamble most likely preamble
+  @param max_preamble_energy Estimated Energy of most likely preamble
+  @param max_preamble_delay Estimated Delay of most likely preamble
   @param Nf System frame number
   @param tdd_mapindex Index of PRACH resource in Table 5.7.1-4 (TDD)
+  @param br_flag indicator to act on eMTC PRACH
   @returns 0 on success
 
 */
-void rx_prach(PHY_VARS_eNB *phy_vars_eNB,RU_t *ru,uint16_t *preamble_energy_list, uint16_t *preamble_delay_list, uint16_t Nf, uint8_t tdd_mapindex);
+void rx_prach(PHY_VARS_eNB *phy_vars_eNB,RU_t *ru,
+	      uint16_t *max_preamble, 
+	      uint16_t *max_preamble_energy, 
+	      uint16_t *max_preamble_delay, 
+	      uint16_t Nf, uint8_t tdd_mapindex,
+	      uint8_t br_flag);
 
 /*!
   \brief Helper for MAC, returns number of available PRACH in TDD for a particular configuration index
@@ -2169,7 +2176,10 @@ double computeRhoB_UE(PDSCH_CONFIG_DEDICATED  *pdsch_config_dedicated,
   LTE_UE_DLSCH_t *dlsch_ue);
 */
 
-uint8_t get_prach_prb_offset(LTE_DL_FRAME_PARMS *frame_parms, uint8_t tdd_mapindex, uint16_t Nf);
+uint8_t get_prach_prb_offset(LTE_DL_FRAME_PARMS *frame_parms, 
+			     uint8_t prach_ConfigIndex, 
+			     uint8_t n_ra_prboffset,
+			     uint8_t tdd_mapindex, uint16_t Nf);
 
 uint8_t ul_subframe2pdcch_alloc_subframe(LTE_DL_FRAME_PARMS *frame_parms,uint8_t n);
 
diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h
index 13c4ce22b4..22df648149 100644
--- a/openair1/PHY/defs.h
+++ b/openair1/PHY/defs.h
@@ -288,6 +288,10 @@ typedef struct RU_proc_t_s {
   int subframe_tx;
   /// subframe to act upon for reception of prach
   int subframe_prach;
+#ifdef Rel14
+  /// subframe to act upon for reception of prach BL/CE UEs
+  int subframe_prach_br;
+#endif
   /// frame to act upon for reception
   int frame_rx;
   /// frame to act upon for transmission
@@ -296,6 +300,10 @@ typedef struct RU_proc_t_s {
   int frame_tx_unwrap;
   /// frame to act upon for reception of prach
   int frame_prach;
+#ifdef Rel14
+  /// frame to act upon for reception of prach
+  int frame_prach_br;
+#endif
   /// frame offset for slave RUs (to correct for frame asynchronism at startup)
   int frame_offset;
   /// \brief Instance count for FH processing thread.
@@ -303,6 +311,10 @@ typedef struct RU_proc_t_s {
   int instance_cnt_FH;
   /// \internal This variable is protected by \ref mutex_prach.
   int instance_cnt_prach;
+#ifdef Rel14
+  /// \internal This variable is protected by \ref mutex_prach.
+  int instance_cnt_prach_br;
+#endif
   /// \internal This variable is protected by \ref mutex_synch.
   int instance_cnt_synch;
   /// \internal This variable is protected by \ref mutex_eNBs.
@@ -316,6 +328,10 @@ typedef struct RU_proc_t_s {
   pthread_t pthread_FH;
   /// pthread structure for RU prach processing thread
   pthread_t pthread_prach;
+#ifdef Rel14
+  /// pthread structure for RU prach processing thread BL/CE UEs
+  pthread_t pthread_prach_br;
+#endif
   /// pthread struct for RU synch thread
   pthread_t pthread_synch;
   /// pthread struct for RU RX FEP thread
@@ -330,6 +346,10 @@ typedef struct RU_proc_t_s {
   pthread_attr_t attr_FH;
   /// pthread attributes for RU prach
   pthread_attr_t attr_prach;
+#ifdef Rel14
+  /// pthread attributes for RU prach BL/CE UEs
+  pthread_attr_t attr_prach_br;
+#endif
   /// pthread attributes for RU synch thread
   pthread_attr_t attr_synch;
   /// pthread attributes for asynchronous RX thread
@@ -340,6 +360,10 @@ typedef struct RU_proc_t_s {
   struct sched_param sched_param_FH;
   /// scheduling parameters for RU prach thread
   struct sched_param sched_param_prach;
+#ifdef Rel14
+  /// scheduling parameters for RU prach thread BL/CE UEs
+  struct sched_param sched_param_prach_br;
+#endif
   /// scheduling parameters for RU synch thread
   struct sched_param sched_param_synch;
   /// scheduling parameters for asynch_rxtx thread
@@ -348,6 +372,10 @@ typedef struct RU_proc_t_s {
   pthread_cond_t cond_FH;
   /// condition variable for RU prach thread
   pthread_cond_t cond_prach;
+#ifdef Rel14
+  /// condition variable for RU prach thread BL/CE UEs
+  pthread_cond_t cond_prach_br;
+#endif
   /// condition variable for RU synch thread
   pthread_cond_t cond_synch;
   /// condition variable for asynch RX/TX thread
@@ -360,6 +388,10 @@ typedef struct RU_proc_t_s {
   pthread_mutex_t mutex_FH;
   /// mutex for RU prach
   pthread_mutex_t mutex_prach;
+#ifdef Rel14
+  /// mutex for RU prach BL/CE UEs
+  pthread_mutex_t mutex_prach_br;
+#endif
   /// mutex for RU synch
   pthread_mutex_t mutex_synch;
   /// mutex for eNB signal
@@ -390,20 +422,30 @@ typedef struct eNB_proc_t_s {
   int subframe_rx;
   /// subframe to act upon for PRACH
   int subframe_prach;
+#ifdef Rel14
+  /// subframe to act upon for reception of prach BL/CE UEs
+  int subframe_prach_br;
+#endif
   /// frame to act upon for reception
   int frame_rx;
   /// frame to act upon for transmission
   int frame_tx;
   /// frame to act upon for PRACH
   int frame_prach;
+#ifdef Rel14
+  /// frame to act upon for PRACH BL/CE UEs
+  int frame_prach_br;
+#endif
   /// \internal This variable is protected by \ref mutex_td.
   int instance_cnt_td;
   /// \internal This variable is protected by \ref mutex_te.
   int instance_cnt_te;
-  /// \brief Instance count for FH processing thread.
-  /// \brief Instance count for rx processing thread.
   /// \internal This variable is protected by \ref mutex_prach.
   int instance_cnt_prach;
+#ifdef Rel14
+  /// \internal This variable is protected by \ref mutex_prach for BL/CE UEs.
+  int instance_cnt_prach_br;
+#endif
   // instance count for over-the-air eNB synchronization
   int instance_cnt_synch;
   /// \internal This variable is protected by \ref mutex_asynch_rxtx.
@@ -424,6 +466,10 @@ typedef struct eNB_proc_t_s {
   pthread_attr_t attr_single;
   /// pthread attributes for prach processing thread
   pthread_attr_t attr_prach;
+#ifdef Rel14
+  /// pthread attributes for prach processing thread BL/CE UEs
+  pthread_attr_t attr_prach_br;
+#endif
   /// pthread attributes for asynchronous RX thread
   pthread_attr_t attr_asynch_rxtx;
   /// scheduling parameters for parallel turbo-decoder thread
@@ -434,6 +480,10 @@ typedef struct eNB_proc_t_s {
   struct sched_param sched_param_single;
   /// scheduling parameters for prach thread
   struct sched_param sched_param_prach;
+#ifdef Rel14
+  /// scheduling parameters for prach thread
+  struct sched_param sched_param_prach_br;
+#endif
   /// scheduling parameters for asynch_rxtx thread
   struct sched_param sched_param_asynch_rxtx;
   /// pthread structure for parallel turbo-decoder thread
@@ -442,12 +492,20 @@ typedef struct eNB_proc_t_s {
   pthread_t pthread_te;
   /// pthread structure for PRACH thread
   pthread_t pthread_prach;
+#ifdef Rel14
+  /// pthread structure for PRACH thread BL/CE UEs
+  pthread_t pthread_prach_br;
+#endif
   /// condition variable for parallel turbo-decoder thread
   pthread_cond_t cond_td;
   /// condition variable for parallel turbo-encoder thread
   pthread_cond_t cond_te;
   /// condition variable for PRACH processing thread;
   pthread_cond_t cond_prach;
+#ifdef Rel14
+  /// condition variable for PRACH processing thread BL/CE UEs;
+  pthread_cond_t cond_prach_br;
+#endif
   /// condition variable for asynch RX/TX thread
   pthread_cond_t cond_asynch_rxtx;
   /// mutex for parallel turbo-decoder thread
@@ -456,16 +514,26 @@ typedef struct eNB_proc_t_s {
   pthread_mutex_t mutex_te;
   /// mutex for PRACH thread
   pthread_mutex_t mutex_prach;
+#ifdef Rel14
+  /// mutex for PRACH thread for BL/CE UEs
+  pthread_mutex_t mutex_prach_br;
+#endif
   /// mutex for asynch RX/TX thread
   pthread_mutex_t mutex_asynch_rxtx;
   /// mutex for RU access to eNB processing (PDSCH/PUSCH)
   pthread_mutex_t mutex_RU;
   /// mutex for RU access to eNB processing (PRACH)
   pthread_mutex_t mutex_RU_PRACH;
+  /// mutex for RU access to eNB processing (PRACH BR)
+  pthread_mutex_t mutex_RU_PRACH_br;
   /// mask for RUs serving eNB (PDSCH/PUSCH)
   int RU_mask;
   /// mask for RUs serving eNB (PRACH)
   int RU_mask_prach;
+#ifdef Rel14
+  /// mask for RUs serving eNB (PRACH)
+  int RU_mask_prach_br;
+#endif
   /// parameters for turbo-decoding worker thread
   td_params tdp;
   /// parameters for turbo-encoding worker thread
@@ -631,6 +699,8 @@ typedef struct RU_t_s{
   int (*wakeup_rxtx)(struct PHY_VARS_eNB_s *eNB,int frame_rx,int subframe_rx);
   /// function pointer to wakeup routine in lte-enb.
   int (*wakeup_prach_eNB)(struct PHY_VARS_eNB_s *eNB,struct RU_t_s *ru,int frame,int subframe);
+  /// function pointer to wakeup routine in lte-enb.
+  int (*wakeup_prach_eNB_br)(struct PHY_VARS_eNB_s *eNB,struct RU_t_s *ru,int frame,int subframe);
   /// function pointer to eNB entry routine
   void (*eNB_top)(struct PHY_VARS_eNB_s *eNB, int frame_rx, int subframe_rx, char *string);
   /// Timing statistics
@@ -642,6 +712,8 @@ typedef struct RU_t_s{
 
   /// received frequency-domain signal for PRACH (IF4p5 RRU) 
   int16_t              **prach_rxsigF;
+  /// received frequency-domain signal for PRACH BR (IF4p5 RRU) 
+  int16_t              **prach_rxsigF_br[4];
   /// sequence number for IF5
   uint8_t seqno;
   /// initial timestamp used as an offset make first real timestamp 0
@@ -829,12 +901,23 @@ typedef struct PHY_VARS_eNB_s {
   IF_Module_t          *if_inst;
   UL_IND_t             UL_INFO;
   pthread_mutex_t      UL_INFO_mutex;
+  /// NFAPI RX ULSCH information
   nfapi_rx_indication_pdu_t  rx_pdu_list[NFAPI_RX_IND_MAX_PDU];
+  /// NFAPI RX ULSCH CRC information
   nfapi_crc_indication_pdu_t crc_pdu_list[NFAPI_CRC_IND_MAX_PDU];
+  /// NFAPI PRACH information
+  nfapi_preamble_pdu_t preamble_list[MAX_NUM_RX_PRACH_PREAMBLES];
+#ifdef Rel14
+  /// NFAPI PRACH information BL/CE UEs
+  nfapi_preamble_pdu_t preamble_list_br[MAX_NUM_RX_PRACH_PREAMBLES];
+#endif
   Sched_Rsp_t          Sched_INFO;
   LTE_eNB_PDCCH        pdcch_vars[2];
+#ifdef Rel14
   LTE_eNB_EPDCCH       epdcch_vars[2];
   LTE_eNB_MPDCCH       mpdcch_vars[2];
+  LTE_eNB_PRACH        prach_vars_br;
+#endif
   LTE_eNB_COMMON       common_vars;
   LTE_eNB_SRS          srs_vars[NUMBER_OF_UE_MAX];
   LTE_eNB_PBCH         pbch;
@@ -1364,6 +1447,13 @@ typedef struct RRU_config_s {
   int prach_FreqOffset[MAX_BANDS_PER_RRU];
   /// prach_ConfigIndex for IF4p5
   int prach_ConfigIndex[MAX_BANDS_PER_RRU];
+#ifdef Rel14
+  int emtc_prach_CElevel_enable[MAX_BANDS_PER_RRU][4];
+  /// emtc_prach_FreqOffset for IF4p5 per CE Level
+  int emtc_prach_FreqOffset[MAX_BANDS_PER_RRU][4];
+  /// emtc_prach_ConfigIndex for IF4p5 per CE Level
+  int emtc_prach_ConfigIndex[MAX_BANDS_PER_RRU][4];
+#endif
 } RRU_config_t;
 
 
diff --git a/openair1/PHY/impl_defs_lte.h b/openair1/PHY/impl_defs_lte.h
index 4e6600acba..c0810f49f8 100644
--- a/openair1/PHY/impl_defs_lte.h
+++ b/openair1/PHY/impl_defs_lte.h
@@ -56,6 +56,8 @@
 
 #define MAX_MBSFN_AREA 8
 
+#define NB_RX_ANTENNAS_MAX 64
+
 #ifdef OCP_FRAMEWORK
 #include "enums.h"
 #else
@@ -99,6 +101,8 @@ typedef struct {
   uint8_t prach_FreqOffset;
 } PRACH_CONFIG_INFO;
 
+
+
 /// PRACH-ConfigSIB or PRACH-Config from 36.331 RRC spec
 typedef struct {
   /// Parameter: RACH_ROOT_SEQUENCE, see TS 36.211 (5.7.1). \vr{[0..837]}
@@ -109,6 +113,44 @@ typedef struct {
   PRACH_CONFIG_INFO prach_ConfigInfo;
 } PRACH_CONFIG_COMMON;
 
+#ifdef Rel14
+
+/// PRACH-eMTC-Config from 36.331 RRC spec
+typedef struct {
+  /// Parameter: High-speed-flag, see TS 36.211 (5.7.2). \vr{[0..1]} 1 corresponds to Restricted set and 0 to Unrestricted set.
+  uint8_t highSpeedFlag;
+/// Parameter: \f$N_\text{CS}\f$, see TS 36.211 (5.7.2). \vr{[0..15]}\n Refer to table 5.7.2-2 for preamble format 0..3 and to table 5.7.2-3 for preamble format 4.
+  uint8_t zeroCorrelationZoneConfig;
+  /// Parameter: prach-FrequencyOffset, see TS 36.211 (5.7.1). \vr{[0..94]}\n For TDD the value range is dependent on the value of \ref prach_ConfigIndex.
+
+  /// PRACH starting subframe periodicity, expressed in number of subframes available for preamble transmission (PRACH opportunities), see TS 36.211. Value 2 corresponds to 2 subframes, 4 corresponds to 4 subframes and so on. EUTRAN configures the PRACH starting subframe periodicity larger than or equal to the Number of PRACH repetitions per attempt for each CE level (numRepetitionPerPreambleAttempt).
+  uint8_t prach_starting_subframe_periodicity[4];
+  /// number of repetitions per preamble attempt per CE level
+  uint8_t prach_numRepetitionPerPreambleAttempt[4];
+  /// prach configuration index for each CE level
+  uint8_t prach_ConfigIndex[4];
+  /// indicator for CE level activation
+  uint8_t prach_CElevel_enable[4];
+  /// prach frequency offset for each CE level 
+  uint8_t prach_FreqOffset[4];
+  /// indicator for CE level hopping activation
+  uint8_t prach_hopping_enable[4];
+  /// indicator for CE level hopping activation
+  uint8_t prach_hopping_offset[4];
+} PRACH_eMTC_CONFIG_INFO;
+
+#endif
+
+/// PRACH-ConfigSIB or PRACH-Config from 36.331 RRC spec
+typedef struct {
+  /// Parameter: RACH_ROOT_SEQUENCE, see TS 36.211 (5.7.1). \vr{[0..837]}
+  uint16_t rootSequenceIndex;
+  /// prach_Config_enabled=1 means enabled. \vr{[0..1]}
+  uint8_t prach_Config_enabled;
+  /// PRACH Configuration Information
+  PRACH_eMTC_CONFIG_INFO prach_ConfigInfo;
+} PRACH_eMTC_CONFIG_COMMON;
+
 /// Enumeration for parameter \f$N_\text{ANRep}\f$ \ref PUCCH_CONFIG_DEDICATED::repetitionFactor.
 typedef enum {
   n2=0,
@@ -546,6 +588,10 @@ typedef struct {
   uint8_t nb_antenna_ports_eNB;
   /// PRACH_CONFIG
   PRACH_CONFIG_COMMON prach_config_common;
+#ifdef Rel14
+  /// PRACH_eMTC_CONFIG
+  PRACH_eMTC_CONFIG_COMMON prach_emtc_config_common;
+#endif
   /// PUCCH Config Common (from 36-331 RRC spec)
   PUCCH_CONFIG_COMMON pucch_config_common;
   /// PDSCH Config Common (from 36-331 RRC spec)
@@ -1138,13 +1184,19 @@ typedef struct {
   /// \brief ?.
   /// first index: rx antenna [0..63] (hard coded) \note Hard coded array size indexed by \c nb_antennas_rx.
   /// second index: ? [0..ofdm_symbol_size*12[
-  int16_t *rxsigF[64];
+  int16_t **rxsigF;
   /// \brief local buffer to compute prach_ifft (necessary in case of multiple CCs)
   /// first index: rx antenna [0..63] (hard coded) \note Hard coded array size indexed by \c nb_antennas_rx.
   /// second index: ? [0..2047] (hard coded)
-  int16_t *prach_ifft[64];
-  /// NFAPI PRACH information
-  nfapi_preamble_pdu_t preamble_list[MAX_NUM_RX_PRACH_PREAMBLES];
+  int32_t ***prach_ifft;
+
+  /// repetition number
+#ifdef Rel14
+  /// indicator of first frame in a group of PRACH repetitions
+  int first_frame[4];
+  /// current repetition for each CE level
+  int repetition_number[4];
+#endif
 } LTE_eNB_PRACH;
 
 typedef struct {
@@ -1162,6 +1214,7 @@ typedef struct {
   uint8_t *Msg3;
 } PRACH_RESOURCES_t;
 
+
 typedef struct {
   /// Downlink Power offset field
   uint8_t dl_pow_off;
diff --git a/openair1/SCHED/defs.h b/openair1/SCHED/defs.h
index 26859b6528..f414e28f63 100644
--- a/openair1/SCHED/defs.h
+++ b/openair1/SCHED/defs.h
@@ -199,10 +199,13 @@ void phy_procedures_eNB_S_RX(PHY_VARS_eNB *phy_vars_eNB,eNB_rxtx_proc_t *proc,re
 
 /*! \brief Scheduling for eNB PRACH RX procedures
   @param phy_vars_eNB Pointer to eNB variables on which to act
-  @param proc Pointer to RXn-TXnp4 proc information
+  @param br_flag indicator for eMTC PRACH
 */
-void prach_procedures(PHY_VARS_eNB *eNB);
-
+void prach_procedures(PHY_VARS_eNB *eNB,
+#ifdef Rel14
+		      int br_flag
+#endif
+		      );
 /*! \brief Function to compute subframe type as a function of Frame type and TDD Configuration (implements Table 4.2.2 from 36.211, p.11 from version 8.6) and subframe index.
   @param frame_parms Pointer to DL frame parameter descriptor
   @param subframe Subframe index
diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c
index 2ef387cf5d..546e6b7abf 100644
--- a/openair1/SCHED/phy_procedures_lte_eNb.c
+++ b/openair1/SCHED/phy_procedures_lte_eNb.c
@@ -1179,7 +1179,7 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) {
       handle_nfapi_dlsch_pdu(eNB,proc,dl_config_pdu,
 			     dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks-1,
 			     TX_req->tx_request_body.tx_pdu_list[dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index].segments[0].segment_data);
-      if (dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti == eNB->prach_vars.preamble_list[0].preamble_rel8.rnti) {// is RAR pdu
+      if (dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti == eNB->preamble_list[0].preamble_rel8.rnti) {// is RAR pdu
 	
 	generate_eNB_ulsch_params_from_rar(eNB,
 					   TX_req->tx_request_body.tx_pdu_list[dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index].segments[0].segment_data,
@@ -1917,107 +1917,136 @@ void get_n1_pucch_eNB(PHY_VARS_eNB *eNB,
   }
 }
 
-void prach_procedures(PHY_VARS_eNB *eNB) {
+void prach_procedures(PHY_VARS_eNB *eNB,
+#ifdef Rel14
+		      int br_flag
+#endif
+		      ) {
 
   LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
-  uint16_t preamble_energy_list[64],preamble_delay_list[64];
-  uint16_t preamble_max,preamble_energy_max;
+  uint16_t max_preamble[4],max_preamble_energy[4],max_preamble_delay[4];
   uint16_t i;
-  int subframe = eNB->proc.subframe_prach;
-  int frame = eNB->proc.frame_prach;
+  int frame,subframe;
+#ifdef Rel14
+  if (br_flag==1) {
+    subframe = eNB->proc.subframe_prach_br;
+    frame = eNB->proc.frame_prach_br;
+  }
+  else
+#endif
+    {
+      subframe = eNB->proc.subframe_prach;
+      frame = eNB->proc.frame_prach;
+    }
   uint8_t CC_id = eNB->CC_id;
   RU_t *ru;
   int aa=0;
   int ru_aa;
+  LTE_eNB_PRACH *prach_vars;
 
+ 
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,1);
-  memset(&preamble_energy_list[0],0,64*sizeof(uint16_t));
-  memset(&preamble_delay_list[0],0,64*sizeof(uint16_t));
-
 
   for (i=0;i<eNB->num_RU;i++) {
     ru=eNB->RU_list[i];
-    for (ru_aa=0;ru_aa<ru->nb_rx;ru_aa++) eNB->prach_vars.rxsigF[aa++] = eNB->RU_list[i]->prach_rxsigF[ru_aa];
+    for (ru_aa=0,aa=0;ru_aa<ru->nb_rx;ru_aa++,aa++) {
+      eNB->prach_vars.rxsigF[aa] = eNB->RU_list[i]->prach_rxsigF[ru_aa];
+#ifdef Rel14
+      int ce_level;
+
+      if (br_flag==1)
+	for (ce_level=0;ce_level<4;ce_level++) eNB->prach_vars_br.rxsigF[aa] = eNB->RU_list[i]->prach_rxsigF_br[ce_level][ru_aa];
+#endif
+    }
   }
+
   rx_prach(eNB,
 	   eNB->RU_list[0],
-	   preamble_energy_list,
-	   preamble_delay_list,
+	   &max_preamble[0],
+	   &max_preamble_energy[0],
+	   &max_preamble_delay[0],
 	   frame,
-	   0);
-  preamble_energy_max = preamble_energy_list[0];
-  preamble_max = 0;
-
-  for (i=1; i<64; i++) {
-    if (preamble_energy_max < preamble_energy_list[i]) {
-      preamble_energy_max = preamble_energy_list[i];
-      preamble_max = i;
-    }
-  }
+	   0
+#ifdef Rel14
+	   ,br_flag
+#endif
+	   );
 
   //#ifdef DEBUG_PHY_PROC
   LOG_D(PHY,"[RAPROC] Frame %d, subframe %d : Most likely preamble %d, energy %d dB delay %d\n",
         frame,subframe,
-	preamble_max,
-        preamble_energy_list[preamble_max],
-        preamble_delay_list[preamble_max]);
+	max_preamble[0],
+        max_preamble_energy[0],
+        max_preamble_delay[0]);
   //#endif
 
-  if (preamble_energy_list[preamble_max] > 580) {
+#ifdef Rel14
+  if (br_flag==1) {
 
-    //    UE_id = find_next_ue_index(eNB);
- 
-    //    if (UE_id>=0) {
-      //      eNB->UE_stats[(uint32_t)UE_id].UE_timing_offset = preamble_delay_list[preamble_max]&0x1FFF; //limit to 13 (=11+2) bits
-
-      //      eNB->UE_stats[(uint32_t)UE_id].sector = 0;
-    LOG_D(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n",
-	  eNB->Mod_id,
-	  eNB->CC_id,
-	  frame,
-	  subframe,
-	  preamble_max,
-	  preamble_energy_max/10,
-	  preamble_energy_max%10,
-	  preamble_delay_list[preamble_max]);
+    prach_vars = &eNB->prach_vars_br;
+    int prach_mask;
+      
+    prach_mask = is_prach_subframe(&eNB->frame_parms,eNB->proc.frame_prach_br,eNB->proc.subframe_prach_br);
+    
+    eNB->UL_INFO.rach_ind_br.preamble_list                              = eNB->preamble_list_br;
     
-    T(T_ENB_PHY_INITIATE_RA_PROCEDURE, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), 0,
-      T_INT(preamble_max), T_INT(preamble_energy_max), T_INT(preamble_delay_list[preamble_max]));
+    for (int ind=0,ce_level=0;ce_level<4;ce_level++) {
+      if ((prach_mask&(1<<(1+ce_level)) > 0) && // prach is active and CE level has finished its repetitions
+	  (eNB->prach_vars_br.repetition_number[ce_level]==
+	   eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[ce_level])) {
+	if (max_preamble_energy[ind] > 580) {
+	  eNB->UL_INFO.rach_ind_br.number_of_preambles++;
+	  
+	  eNB->preamble_list_br[ind].preamble_rel8.timing_advance        = max_preamble_delay[ind];//
+	  eNB->preamble_list_br[ind].preamble_rel8.preamble              = max_preamble[ind];
+	  // note: fid is implicitly 0 here, this is the rule for eMTC RA-RNTI from 36.321, Section 5.1.4
+	  eNB->preamble_list_br[ind].preamble_rel8.rnti                  = 1+subframe+(eNB->prach_vars_br.first_frame[ce_level]%40);  
+	  eNB->preamble_list_br[ind].instance_length                     = 0; //don't know exactly what this is
+	  eNB->preamble_list_br[ind].preamble_rel13.rach_resource_type   = 1+ce_level;  // CE Level
+	}
+	ind++;
+      }
+    } // ce_level
+  }
+  else
+#endif
 
-    if (eNB->mac_enabled==1) {
-      LTE_eNB_PRACH *prach_vars = &eNB->prach_vars;
-      
-      uint8_t update_TA  = 4;
-      uint8_t update_TA2 = 1;
-      switch (fp->N_RB_DL) {
-      case 6:
-	update_TA = 16;
-	break;
-	
-      case 25:
-	update_TA = 4;
-	break;
-	
-      case 50:
-	update_TA = 2;
-	break;
+    {
+      if (max_preamble_energy[0] > 580) {
+
+	LOG_D(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n",
+	      eNB->Mod_id,
+	      eNB->CC_id,
+	      frame,
+	      subframe,
+	      max_preamble[0],
+	      max_preamble_energy[0]/10,
+	      max_preamble_energy[0]%10,
+	      max_preamble_delay[0]);
 	
-      case 75:
-	update_TA  = 3;
-	update_TA2 = 2;
-      case 100:
-	update_TA  = 1;
-	break;
-      }
-      pthread_mutex_lock(&eNB->UL_INFO_mutex);
-      eNB->UL_INFO.rach_ind.number_of_preambles                        = 1;
-      eNB->UL_INFO.rach_ind.preamble_list                              = prach_vars->preamble_list;
-      
-      prach_vars->preamble_list[0].preamble_rel8.timing_advance        = preamble_delay_list[preamble_max]*update_TA/update_TA2;
-      prach_vars->preamble_list[0].preamble_rel8.preamble              = preamble_max;
-      prach_vars->preamble_list[0].preamble_rel8.rnti                  = 1+subframe;  // note: fid is implicitly 0 here
-      prach_vars->preamble_list[0].instance_length                     = 0; //don't know exactly what this is
-      pthread_mutex_unlock(&eNB->UL_INFO_mutex);
+	    T(T_ENB_PHY_INITIATE_RA_PROCEDURE, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), 0,
+	      T_INT(max_preamble[0]), T_INT(max_preamble_energy[0]), T_INT(max_preamble_delay[0]));
+	    
+	    if (eNB->mac_enabled==1) {
+	      
+	      prach_vars = &eNB->prach_vars;
+	      
+	      
+	      pthread_mutex_lock(&eNB->UL_INFO_mutex);
+	      
+	      eNB->UL_INFO.rach_ind.number_of_preambles                 = 1;
+	      eNB->UL_INFO.rach_ind.preamble_list                       = eNB->preamble_list;
+	      
+	      eNB->preamble_list[0].preamble_rel8.timing_advance        = max_preamble_delay[0];
+	      eNB->preamble_list[0].preamble_rel8.preamble              = max_preamble[0];
+	      eNB->preamble_list[0].preamble_rel8.rnti                  = 1+subframe;  // note: fid is implicitly 0 here
+	      eNB->preamble_list[0].preamble_rel13.rach_resource_type   = 0;
+	      eNB->preamble_list[0].instance_length                     = 0; //don't know exactly what this is
+	    
+	      pthread_mutex_unlock(&eNB->UL_INFO_mutex);
+	    }
+      } // max_preamble_energy > 580
+    } // else br_flag
       /*
 	mac_xface->initiate_ra_proc(eNB->Mod_id,
 	eNB->CC_id,
@@ -2026,15 +2055,13 @@ void prach_procedures(PHY_VARS_eNB *eNB) {
 	preamble_delay_list[preamble_max]*update_TA/update_TA2,
 	0,subframe,0);*/
       
-      // fill eNB->UL_info with prach information
-    }      
     
     /*  } else {
     MSC_LOG_EVENT(MSC_PHY_ENB, "0 RA Failed add user, too many");
     LOG_I(PHY,"[eNB %d][RAPROC] frame %d, subframe %d: Unable to add user, max user count reached\n",
 	  eNB->Mod_id,frame, subframe);
 	  }*/
-  }
+
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,0);
 }
 
diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c
index c035490105..0d9980ed10 100644
--- a/openair2/LAYER2/MAC/config.c
+++ b/openair2/LAYER2/MAC/config.c
@@ -330,7 +330,7 @@ void config_sib2(int Mod_idP,
     cfg->emtc_config.prach_catm_zero_correlation_zone_configuration.value = radioResourceConfigCommon_BRP->prach_Config.prach_ConfigInfo.zeroCorrelationZoneConfig;
     cfg->emtc_config.prach_catm_high_speed_flag.value                     = radioResourceConfigCommon_BRP->prach_Config.prach_ConfigInfo.highSpeedFlag;
  
-    struct PRACH_ConfigSIB_v1310 *ext4_prach=radioResourceConfigCommonP->ext4->prach_ConfigCommon_v1310; 
+    struct PRACH_ConfigSIB_v1310 *ext4_prach=radioResourceConfigCommon_BRP->ext4->prach_ConfigCommon_v1310; 
 
     PRACH_ParametersListCE_r13_t	 *prach_ParametersListCE_r13 = &ext4_prach->prach_ParametersListCE_r13;
     int i;
@@ -342,40 +342,44 @@ void config_sib2(int Mod_idP,
     switch (prach_ParametersListCE_r13->list.count) {
     case 4:
       p=prach_ParametersListCE_r13->list.array[3];
-      cfg->emtc_config.prach_ce_level_3_enable.value                          = 1;
-      cfg->emtc_config.prach_ce_level_3_configuration_index.value             = p->prach_ConfigIndex_r13;
-      cfg->emtc_config.prach_ce_level_3_frequency_offset.value                = p->prach_FreqOffset_r13;
+      cfg->emtc_config.prach_ce_level_3_enable.value                            = 1;
+      cfg->emtc_config.prach_ce_level_3_configuration_index.value               = p->prach_ConfigIndex_r13;
+      cfg->emtc_config.prach_ce_level_3_frequency_offset.value                  = p->prach_FreqOffset_r13;
+      cfg->emtc_config.prach_ce_level_3_number_of_repetitions_per_attempt.value = p->numRepetitionPerPreambleAttempt_r13;
       if (p->prach_StartingSubframe_r13) 
-	cfg->emtc_config.prach_ce_level_3_starting_subframe_periodicity.value = *p->prach_StartingSubframe_r13;
-      cfg->emtc_config.prach_ce_level_3_hopping_enable.value                  = p->prach_HoppingConfig_r13;
-      cfg->emtc_config.prach_ce_level_3_hopping_offset.value                  = cfg->rf_config.ul_channel_bandwidth.value-6;
+	cfg->emtc_config.prach_ce_level_3_starting_subframe_periodicity.value   = *p->prach_StartingSubframe_r13;
+      cfg->emtc_config.prach_ce_level_3_hopping_enable.value                    = p->prach_HoppingConfig_r13;
+      cfg->emtc_config.prach_ce_level_3_hopping_offset.value                    = cfg->rf_config.ul_channel_bandwidth.value-6;
     case 3:
       p=prach_ParametersListCE_r13->list.array[2];
-      cfg->emtc_config.prach_ce_level_2_enable.value                          = 1;
-      cfg->emtc_config.prach_ce_level_2_configuration_index.value             = p->prach_ConfigIndex_r13;
-      cfg->emtc_config.prach_ce_level_2_frequency_offset.value                = p->prach_FreqOffset_r13;
+      cfg->emtc_config.prach_ce_level_2_enable.value                            = 1;
+      cfg->emtc_config.prach_ce_level_2_configuration_index.value               = p->prach_ConfigIndex_r13;
+      cfg->emtc_config.prach_ce_level_2_frequency_offset.value                  = p->prach_FreqOffset_r13;
+      cfg->emtc_config.prach_ce_level_2_number_of_repetitions_per_attempt.value = p->numRepetitionPerPreambleAttempt_r13;
       if (p->prach_StartingSubframe_r13) 
-	cfg->emtc_config.prach_ce_level_2_starting_subframe_periodicity.value = *p->prach_StartingSubframe_r13;
-      cfg->emtc_config.prach_ce_level_2_hopping_enable.value                  = p->prach_HoppingConfig_r13;
-      cfg->emtc_config.prach_ce_level_2_hopping_offset.value                  = cfg->rf_config.ul_channel_bandwidth.value-6;
+	cfg->emtc_config.prach_ce_level_2_starting_subframe_periodicity.value   = *p->prach_StartingSubframe_r13;
+      cfg->emtc_config.prach_ce_level_2_hopping_enable.value                    = p->prach_HoppingConfig_r13;
+      cfg->emtc_config.prach_ce_level_2_hopping_offset.value                    = cfg->rf_config.ul_channel_bandwidth.value-6;
     case 2:
       p=prach_ParametersListCE_r13->list.array[1];
-      cfg->emtc_config.prach_ce_level_1_enable.value                          = 1;
-      cfg->emtc_config.prach_ce_level_1_configuration_index.value             = p->prach_ConfigIndex_r13;
-      cfg->emtc_config.prach_ce_level_1_frequency_offset.value                = p->prach_FreqOffset_r13;
+      cfg->emtc_config.prach_ce_level_1_enable.value                            = 1;
+      cfg->emtc_config.prach_ce_level_1_configuration_index.value               = p->prach_ConfigIndex_r13;
+      cfg->emtc_config.prach_ce_level_1_frequency_offset.value                  = p->prach_FreqOffset_r13;
+      cfg->emtc_config.prach_ce_level_1_number_of_repetitions_per_attempt.value = p->numRepetitionPerPreambleAttempt_r13;
       if (p->prach_StartingSubframe_r13) 
-	cfg->emtc_config.prach_ce_level_1_starting_subframe_periodicity.value = *p->prach_StartingSubframe_r13;
-      cfg->emtc_config.prach_ce_level_1_hopping_enable.value                  = p->prach_HoppingConfig_r13;
-      cfg->emtc_config.prach_ce_level_1_hopping_offset.value                  = cfg->rf_config.ul_channel_bandwidth.value-6;
+	cfg->emtc_config.prach_ce_level_1_starting_subframe_periodicity.value   = *p->prach_StartingSubframe_r13;
+      cfg->emtc_config.prach_ce_level_1_hopping_enable.value                    = p->prach_HoppingConfig_r13;
+      cfg->emtc_config.prach_ce_level_1_hopping_offset.value                    = cfg->rf_config.ul_channel_bandwidth.value-6;
     case 1:
       p=prach_ParametersListCE_r13->list.array[0];
-      cfg->emtc_config.prach_ce_level_0_enable.value                          = 1;
-      cfg->emtc_config.prach_ce_level_0_configuration_index.value             = p->prach_ConfigIndex_r13;
-      cfg->emtc_config.prach_ce_level_0_frequency_offset.value                = p->prach_FreqOffset_r13;
+      cfg->emtc_config.prach_ce_level_0_enable.value                            = 1;
+      cfg->emtc_config.prach_ce_level_0_configuration_index.value               = p->prach_ConfigIndex_r13;
+      cfg->emtc_config.prach_ce_level_0_frequency_offset.value                  = p->prach_FreqOffset_r13;
+      cfg->emtc_config.prach_ce_level_0_number_of_repetitions_per_attempt.value = p->numRepetitionPerPreambleAttempt_r13;
       if (p->prach_StartingSubframe_r13) 
-	cfg->emtc_config.prach_ce_level_0_starting_subframe_periodicity.value = *p->prach_StartingSubframe_r13;
-      cfg->emtc_config.prach_ce_level_0_hopping_enable.value                  = p->prach_HoppingConfig_r13;
-      cfg->emtc_config.prach_ce_level_0_hopping_offset.value                  = cfg->rf_config.ul_channel_bandwidth.value-6;
+	cfg->emtc_config.prach_ce_level_0_starting_subframe_periodicity.value   = *p->prach_StartingSubframe_r13;
+      cfg->emtc_config.prach_ce_level_0_hopping_enable.value                    = p->prach_HoppingConfig_r13;
+      cfg->emtc_config.prach_ce_level_0_hopping_offset.value                    = cfg->rf_config.ul_channel_bandwidth.value-6;
     }
 
     struct FreqHoppingParameters_r13 *ext4_freqHoppingParameters = radioResourceConfigCommonP->ext4->freqHoppingParameters_r13;
diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h
index 45619246c4..2c8b613b1d 100644
--- a/openair2/LAYER2/MAC/defs.h
+++ b/openair2/LAYER2/MAC/defs.h
@@ -824,10 +824,18 @@ typedef struct {
   uint8_t generate_rar;
   /// Subframe where preamble was received
   uint8_t preamble_subframe;
+  /// Subframe where Msg2 is to be sent
+  uint8_t Msg2_subframe;
+  /// Frame where Msg2 is to be sent
+  uint8_t Msg2_frame;
   /// Subframe where Msg3 is to be sent
   uint8_t Msg3_subframe;
-  /// Subframe where Msg3 is to be sent
+  /// Frame where Msg3 is to be sent
   uint8_t Msg3_frame;
+  /// Subframe where Msg4 is to be sent
+  uint8_t Msg4_subframe;
+  /// Frame where Msg4 is to be sent
+  uint8_t Msg4_frame;
   /// Flag to indicate the eNB should generate Msg4 upon reception of SDU from RRC.  This is triggered by first ULSCH reception at eNB for new user.
   uint8_t generate_Msg4;
   /// Flag to indicate that eNB is waiting for ACK that UE has received Msg3.
@@ -846,6 +854,13 @@ typedef struct {
   int16_t RRC_timer;
   /// Round of Msg3 HARQ
   uint8_t msg3_round;
+#ifdef Rel14
+  uint8_t rach_resource_type;
+  uint8_t msg2_mpdcch_repetition_cnt;
+  uint8_t msg4_mpdcch_repetition_cnt;
+  uint8_t msg2_narrowband;
+  uint8_t msg34_narrowband;
+#endif
 } RA_TEMPLATE;
 
 
@@ -962,7 +977,7 @@ typedef struct eNB_MAC_INST_s {
   /// Ethernet parameters for fronthaul interface
   eth_params_t         eth_params_s;
   ///
-  uint16_t Node_id;
+  module_id_t Mod_id;
   /// frame counter
   frame_t frame;
   /// subframe counter
@@ -1030,6 +1045,15 @@ typedef struct eNB_MAC_INST_s {
  * UE part 
  */ 
 
+typedef enum {
+  TYPE0,
+  TYPE1,
+  TYPE1A,
+  TYPE2,
+  TYPE2A,
+  TYPEUESPEC
+} MPDCCH_TYPES_t;
+
 /*!\brief UE layer 2 status */
 typedef enum {
   CONNECTION_OK=0,
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_RA.c b/openair2/LAYER2/MAC/eNB_scheduler_RA.c
index d6e245d180..47a809f032 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler_RA.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_RA.c
@@ -174,6 +174,31 @@ void schedule_RA(module_id_t module_idP,frame_t frameP, sub_frame_t subframeP,un
   int round;
   nfapi_dl_config_request_body_t *dl_req;
 
+#ifdef Rel14
+  int rmax            = 0;
+  int rep             = 0; 
+  int reps            = 0;
+  int num_nb          = 0;
+  first_rb        = 0;
+
+  struct PRACH_ConfigSIB_v1310 *ext4_prach                 = cc[CC_id].radioResourceConfigCommon_BR->ext4->prach_ConfigCommon_v1310;
+  PRACH_ParametersListCE_r13_t *prach_ParametersListCE_r13 = &ext4_prach->prach_ParametersListCE_r13;
+  PRACH_ParametersCE_r13_t *p[3];
+
+  switch (prach_ParametersListCE_r13->list.count) {
+  case 4:
+    p[3]=prach_ParametersListCE_r13->list.array[3];
+  case 3:
+    p[2]=prach_ParametersListCE_r13->list.array[2];
+  case 2:
+    p[1]=prach_ParametersListCE_r13->list.array[1];
+  case 1:
+    p[0]=prach_ParametersListCE_r13->list.array[0];
+  default:
+    AssertFatal(1==0,"Illegal count for prach_ParametersListCE_r13 %d\n",prach_ParametersListCE_r13->list.count);
+  }
+#endif
+
   start_meas(&eNB->schedule_ra);
 
   for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
@@ -193,93 +218,248 @@ void schedule_RA(module_id_t module_idP,frame_t frameP, sub_frame_t subframeP,un
               module_idP,CC_id,i,RA_template->generate_rar,RA_template->generate_Msg4,RA_template->wait_ack_Msg4, RA_template->rnti);
 
         if (RA_template->generate_rar == 1) {
+  
+#ifdef Rel14
+	  if (RA_template->rach_resource_type > 0) {
+
+	    // This uses an MPDCCH Type 2 allocation according to Section 9.1.5 36-213
+	    // Parameters:
+	    //    p=2+4 PRB set (number of PRB pairs 6)
+	    //    rmax = mpdcch-NumRepetition-RA-r13 => Table 9.1.5-3
+	    //    if CELevel = 0,1 => Table 9.1.5-1b for MPDCCH candidates
+	    //    if CELevel = 2,3 => Table 9.1.5-2b for MPDCCH candidates
+	    //    distributed transmission
+	    
+	    // rmax from SIB2 information
+	    rmax           = p[RA_template->rach_resource_type-1]->mpdcch_NumRepetition_RA_r13;
+	    // choose r3 by default for RAR
+	    rep            = 2; 
+	    // get actual repetition count from Table 9.1.5-3
+	    reps           = (rmax<=8)?(1<<rep):(rmax>>(3-rep));
+	    // get narrowband according to higher-layer config 
+	    num_nb = p[RA_template->rach_resource_type-1]->mpdcch_NarrowbandsToMonitor_r13.list.count;
+	    RA_template->msg2_narrowband = *p[RA_template->rach_resource_type-1]->mpdcch_NarrowbandsToMonitor_r13.list.array[RA_template->preamble_index%num_nb];
+	    first_rb = RA_template->msg2_narrowband*6;
+
+	    if ((RA_template->msg2_mpdcch_repetition_cnt == 0) &&
+		(mpdcch_sf_condition(eNB,CC_id,frameP,subframeP,rmax,TYPE2)>0)){
+	      // MPDCCH configuration for RAR
 
-          LOG_D(MAC,"[eNB %d] CC_id %d Frame %d, subframeP %d: Generating RAR DCI (proc %d), RA_active %d format 1A (%d,%d))\n",
-                module_idP, CC_id, frameP, subframeP,i,
-                RA_template->RA_active,
-                RA_template->RA_dci_fmt1,
-                RA_template->RA_dci_size_bits1);
-
-          first_rb = 0;
-          vrb_map[first_rb] = 1;
-          vrb_map[first_rb+1] = 1;
-          vrb_map[first_rb+2] = 1;
-          vrb_map[first_rb+3] = 1;
-
-	  memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t));
-	  dl_config_pdu->pdu_type                                                          = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; 
-	  dl_config_pdu->pdu_size                                                          = (uint8_t)(2+sizeof(nfapi_dl_config_dci_dl_pdu));
-	  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format                             = NFAPI_DL_DCI_FORMAT_1A;
-	  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level                      = 4;
-	  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti                                   = RA_template->RA_rnti;
-	  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type                              = 2;    // RA-RNTI : see Table 4-10 from SCF082 - nFAPI specifications
-	  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power                     = 6000; // equal to RS power
-	  
-	  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process                           = 0;
-	  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc                                    = 1; // no TPC
-	  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1                   = 1;
-	  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                                  = 0;
-	  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1                   = 0;
-	  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.virtual_resource_block_assignment_flag = 0;
-
-	  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding                  = getRIV(N_RB_DL,first_rb,4);      
-
-	  if (!CCE_allocation_infeasible(module_idP,CC_id,1,subframeP,dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level,RA_template->RA_rnti)) {
-	    LOG_D(MAC,"Frame %d: Subframe %d : Adding common DCI for RA_RNTI %x\n",
-                  frameP,subframeP,RA_template->RA_rnti);
-	    dl_req->number_dci++;
-	    dl_req->number_pdu++;
-
-	    dl_config_pdu                                                                  = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; 
-	    memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t));
-	    dl_config_pdu->pdu_type                                                        = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; 
-	    dl_config_pdu->pdu_size                                                        = (uint8_t)(2+sizeof(nfapi_dl_config_dlsch_pdu));
-	    dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index                              = eNB->pdu_index[CC_id];
-	    dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti                                   = RA_template->RA_rnti;
-	    dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type               = 2;   // format 1A/1B/1D
-	    dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0;   // localized
-	    dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding                  = getRIV(N_RB_DL,first_rb,4);
-	    dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation                             = 2; //QPSK
-	    dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version                     = 0;
-	    dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks                       = 1;// first block
-	    dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag  = 0;
-	    dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme                    = (cc->p_eNB==1 ) ? 0 : 1;
-	    dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers                       = 1;
-	    dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands                     = 1;
-	    //	dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index                         = ;
-	    dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity                   = 1;
-	    dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa                                     = 4; // 0 dB
-	    dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index               = 0;
-	    dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap                                   = 0;
-	    dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb                                   = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored
-	    dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode                      = (cc->p_eNB==1 ) ? 1 : 2;
-	    dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband                 = 1;
-	    dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector                          = 1;
-	    //	dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector                    = ; 
-	    dl_req->number_pdu++;
-
-	    // Program UL processing for Msg3
-	    get_Msg3alloc(&cc[CC_id],subframeP,frameP,&RA_template->Msg3_frame,&RA_template->Msg3_subframe);
-
-
-	    fill_rar(module_idP,CC_id,frameP,cc[CC_id].RAR_pdu.payload,N_RB_DL,7);
-	    // DL request
-	    eNB->TX_req[CC_id].sfn_sf                                             = (frameP<<3)+subframeP;
-	    TX_req                                                                = &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB->TX_req[CC_id].tx_request_body.number_of_pdus]; 		     
-	    TX_req->pdu_length                                                    = 7;  // This should be changed if we have more than 1 preamble 
-	    TX_req->pdu_index                                                     = eNB->pdu_index[CC_id]++;
-	    TX_req->num_segments                                                  = 1;
-	    TX_req->segments[0].segment_length                                    = 7;
-	    TX_req->segments[0].segment_data                                      = cc[CC_id].RAR_pdu.payload;
-	    eNB->TX_req[CC_id].tx_request_body.number_of_pdus++;
-	  }
-        } else if (RA_template->generate_Msg4 == 1) {
-
-          // check for Msg4 Message
-          UE_id = find_UE_id(module_idP,RA_template->rnti);
-	  AssertFatal(UE_id>=0,"Can't find UE for t-crnti\n");
 
+	      
+	      memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t));
+	      dl_config_pdu->pdu_type                                                                  = NFAPI_DL_CONFIG_MPDCCH_PDU_TYPE; 
+	      dl_config_pdu->pdu_size                                                                  = (uint8_t)(2+sizeof(nfapi_dl_config_mpdcch_pdu));
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_format                                    = (RA_template->rach_resource_type > 1) ? 11 : 10;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_narrow_band                            = RA_template->msg2_narrowband;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.number_of_prb_pairs                           = 6;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_assignment                     = 0; // Note: this can be dynamic
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_tansmission_type                       = 1;
+	      AssertFatal(cc[CC_id].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13!=NULL,
+			  "cc[CC_id].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13 is null\n");
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.start_symbol                                  = cc[CC_id].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->startSymbolBR_r13;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ecce_index                                    = 0;  // Note: this should be dynamic
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.aggregation_level                             = 16; // OK for CEModeA r1-3 (9.1.5-1b) or CEModeB r1-4
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti_type                                     = 2;  // RA-RNTI
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti                                          = RA_template->RA_rnti;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ce_mode                                       = (RA_template->rach_resource_type < 3) ? 1 : 2;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.drms_scrambling_init                          = cc[CC_id].physCellId;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.initial_transmission_sf_io                    = (frameP*10)+subframeP;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.transmission_power                            = 6000; // 0dB
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_coding                         = getRIV(N_RB_DL,first_rb,6);
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mcs                                           = 4; // adjust according to size of RAR, 208 bits with N1A_PRB=3
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pdsch_reptition_levels                        = 4; // fix to 4 for now
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.redundancy_version                            = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.new_data_indicator                            = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_process                                  = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi_length                                   = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi                                          = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi_flag                                      = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi                                           = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_resource_offset                          = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_subframe_repetition_number                = rep; 
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpc                                           = 2;// N1A_PRB=3; => 208 bits
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.downlink_assignment_index_length              = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.downlink_assignment_index                     = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.allocate_prach_flag                           = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.preamble_index                                = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.prach_mask_index                              = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.starting_ce_level                             = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.srs_request                                   = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity_flag    = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity         = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.frequency_hopping_enabled_flag                = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.paging_direct_indication_differentiation_flag = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.direct_indication                             = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.total_dci_length_including_padding            = 0; // this is not needed by OAI L1, but should be filled in
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.number_of_tx_antenna_ports                    = 1;
+	      RA_template->msg2_mpdcch_repetition_cnt++;
+	      dl_req->number_pdu++;
+	       
+	    } //repetition_count==0 && SF condition met
+	    if (RA_template->msg2_mpdcch_repetition_cnt>0) { // we're in a stream of repetitions
+	      RA_template->msg2_mpdcch_repetition_cnt++;	      
+	      if (RA_template->msg2_mpdcch_repetition_cnt==reps) { // this is the last mpdcch repetition
+		if (cc[CC_id].tdd_Config==NULL) { // FDD case
+		  // wait 2 subframes for PDSCH transmission
+		  if (subframeP>7) RA_template->Msg2_frame = (frameP+1)&1023;
+		  else             RA_template->Msg2_frame = frameP;
+		  RA_template->Msg2_subframe               = (subframeP+2)%10; 
+		}
+		else {
+		  AssertFatal(1==0,"TDD case not done yet\n");
+		}
+	      } // mpdcch_repetition_count == reps
+	      if ((RA_template->Msg2_frame == frameP) && (RA_template->Msg2_subframe == subframeP)) {
+		// Program PDSCH
+		RA_template->generate_rar = 0;	      
+
+		dl_config_pdu                                                                  = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; 
+		memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t));
+		dl_config_pdu->pdu_type                                                        = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; 
+		dl_config_pdu->pdu_size                                                        = (uint8_t)(2+sizeof(nfapi_dl_config_dlsch_pdu));
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index                              = eNB->pdu_index[CC_id];
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti                                   = RA_template->RA_rnti;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type               = 2;   // format 1A/1B/1D
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0;   // localized
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding                  = getRIV(N_RB_DL,first_rb,6);
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation                             = 2; //QPSK
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version                     = 0;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks                       = 1;// first block
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag  = 0;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme                    = (cc->p_eNB==1 ) ? 0 : 1;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers                       = 1;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands                     = 1;
+		//	dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index                         = ;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity                   = 1;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa                                     = 4; // 0 dB
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index               = 0;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap                                   = 0;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb                                   = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode                      = (cc->p_eNB==1 ) ? 1 : 2;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband                 = 1;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector                          = 1;
+		//	dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector                    = ; 
+
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type                               = (RA_template->rach_resource_type < 3) ? 1 : 2;;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type                    = 2;  // not SI message
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io            = (10*frameP)+subframeP;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.drms_table_flag                       = 0;
+		dl_req->number_pdu++;
+
+		// Program UL processing for Msg3, same as regular LTE
+		get_Msg3alloc(&cc[CC_id],subframeP,frameP,&RA_template->Msg3_frame,&RA_template->Msg3_subframe);
+		
+		
+		fill_rar_br(eNB,CC_id,i,frameP,subframeP,cc[CC_id].RAR_pdu.payload,RA_template->rach_resource_type-1);
+		// DL request
+		eNB->TX_req[CC_id].sfn_sf                                             = (frameP<<3)+subframeP;
+		TX_req                                                                = &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB->TX_req[CC_id].tx_request_body.number_of_pdus]; 		     
+		TX_req->pdu_length                                                    = 7;  // This should be changed if we have more than 1 preamble 
+		TX_req->pdu_index                                                     = eNB->pdu_index[CC_id]++;
+		TX_req->num_segments                                                  = 1;
+		TX_req->segments[0].segment_length                                    = 7;
+		TX_req->segments[0].segment_data                                      = cc[CC_id].RAR_pdu.payload;
+		eNB->TX_req[CC_id].tx_request_body.number_of_pdus++;
+	      }
+	    }      
 
+	  }		
+	  else
+#endif
+	    {
+	      if ((RA_template->Msg2_frame == frameP) && (RA_template->Msg2_subframe == subframeP)) {
+		LOG_D(MAC,"[eNB %d] CC_id %d Frame %d, subframeP %d: Generating RAR DCI (proc %d), RA_active %d format 1A (%d,%d))\n",
+		      module_idP, CC_id, frameP, subframeP,i,
+		      RA_template->RA_active,
+		      
+		      RA_template->RA_dci_fmt1,
+		      RA_template->RA_dci_size_bits1);
+		
+		first_rb = 0;
+		vrb_map[first_rb] = 1;
+		vrb_map[first_rb+1] = 1;
+		vrb_map[first_rb+2] = 1;
+		vrb_map[first_rb+3] = 1;
+		
+		memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t));
+		dl_config_pdu->pdu_type                                                          = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; 
+		dl_config_pdu->pdu_size                                                          = (uint8_t)(2+sizeof(nfapi_dl_config_dci_dl_pdu));
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format                             = NFAPI_DL_DCI_FORMAT_1A;
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level                      = 4;
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti                                   = RA_template->RA_rnti;
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type                              = 2;    // RA-RNTI : see Table 4-10 from SCF082 - nFAPI specifications
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power                     = 6000; // equal to RS power
+		
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process                           = 0;
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc                                    = 1; // no TPC
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1                   = 1;
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                                  = 0;
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1                   = 0;
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.virtual_resource_block_assignment_flag = 0;
+		
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding                  = getRIV(N_RB_DL,first_rb,4);      
+		
+		if (!CCE_allocation_infeasible(module_idP,CC_id,1,subframeP,dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level,RA_template->RA_rnti)) {
+		  LOG_D(MAC,"Frame %d: Subframe %d : Adding common DCI for RA_RNTI %x\n",
+			frameP,subframeP,RA_template->RA_rnti);
+		  dl_req->number_dci++;
+		  dl_req->number_pdu++;
+		  
+		  dl_config_pdu                                                                  = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; 
+		  memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t));
+		  dl_config_pdu->pdu_type                                                        = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; 
+		  dl_config_pdu->pdu_size                                                        = (uint8_t)(2+sizeof(nfapi_dl_config_dlsch_pdu));
+		  dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index                              = eNB->pdu_index[CC_id];
+		  dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti                                   = RA_template->RA_rnti;
+		  dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type               = 2;   // format 1A/1B/1D
+		  dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0;   // localized
+		  dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding                  = getRIV(N_RB_DL,first_rb,4);
+		  dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation                             = 2; //QPSK
+		  dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version                     = 0;
+		  dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks                       = 1;// first block
+		  dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag  = 0;
+		  dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme                    = (cc->p_eNB==1 ) ? 0 : 1;
+		  dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers                       = 1;
+		  dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands                     = 1;
+		  //	dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index                         = ;
+		  dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity                   = 1;
+		  dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa                                     = 4; // 0 dB
+		  dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index               = 0;
+		  dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap                                   = 0;
+		  dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb                                   = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored
+		  dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode                      = (cc->p_eNB==1 ) ? 1 : 2;
+		  dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband                 = 1;
+		  dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector                          = 1;
+		  //	dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector                    = ; 
+		  dl_req->number_pdu++;
+		  
+		  // Program UL processing for Msg3
+		  get_Msg3alloc(&cc[CC_id],subframeP,frameP,&RA_template->Msg3_frame,&RA_template->Msg3_subframe);
+		  
+		  
+		  fill_rar(module_idP,CC_id,frameP,cc[CC_id].RAR_pdu.payload,N_RB_DL,7);
+		  // DL request
+		  eNB->TX_req[CC_id].sfn_sf                                             = (frameP<<3)+subframeP;
+		  TX_req                                                                = &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB->TX_req[CC_id].tx_request_body.number_of_pdus]; 		     
+		  TX_req->pdu_length                                                    = 7;  // This should be changed if we have more than 1 preamble 
+		  TX_req->pdu_index                                                     = eNB->pdu_index[CC_id]++;
+		  TX_req->num_segments                                                  = 1;
+		  TX_req->segments[0].segment_length                                    = 7;
+		  TX_req->segments[0].segment_data                                      = cc[CC_id].RAR_pdu.payload;
+		  eNB->TX_req[CC_id].tx_request_body.number_of_pdus++;
+		} // PDCCH CCE allocation is feasible
+	      } // Msg2 frame/subframe condition
+	    } // else BL/CE
+	} // state generate_rar == 1
+	else if (RA_template->generate_Msg4 == 1) {
+
+	  // check for Msg4 Message
+	  
+	  UE_id = find_UE_id(module_idP,RA_template->rnti);
+	  AssertFatal(UE_id>=0,"Can't find UE for t-crnti\n");
+	  
+	  
 	  // Get RRCConnectionSetup for Piggyback
 	  rrc_sdu_length = mac_rrc_data_req(module_idP,
 					    CC_id,
@@ -292,224 +472,436 @@ void schedule_RA(module_id_t module_idP,frame_t frameP, sub_frame_t subframeP,un
 					    0); // not used in this case
 	  
 	  AssertFatal(rrc_sdu_length>=0,
-			"[MAC][eNB Scheduler] CCCH not allocated\n");
-	
-
-          LOG_D(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d: UE_id %d, rrc_sdu_length %d\n",
-                module_idP, CC_id, frameP, subframeP,UE_id, rrc_sdu_length);
-
-          if (rrc_sdu_length>0) {
-            LOG_I(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d: Generating Msg4 with RRC Piggyback (RA proc %d, RNTI %x)\n",
-                  module_idP, CC_id, frameP, subframeP,i,RA_template->rnti);
-
-	    first_rb=0;
+		      "[MAC][eNB Scheduler] CCCH not allocated\n");
+	  
+	  
+	  LOG_D(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d: UE_id %d, rrc_sdu_length %d\n",
+		module_idP, CC_id, frameP, subframeP,UE_id, rrc_sdu_length);
 
-	    vrb_map[first_rb] = 1;
-	    vrb_map[first_rb+1] = 1;
-	    vrb_map[first_rb+2] = 1;
-	    vrb_map[first_rb+3] = 1;
 
+#ifdef Rel14
+	  if (RA_template->rach_resource_type>0) {
 
-	    memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t));
-	    dl_config_pdu->pdu_type                                                          = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; 
-	    dl_config_pdu->pdu_size                                                          = (uint8_t)(2+sizeof(nfapi_dl_config_dci_dl_pdu));
-	    dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format                             = NFAPI_DL_DCI_FORMAT_1A;
-	    dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level                      = 4;
-	    dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti                                   = RA_template->rnti;
-	    dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type                              = 1;    // C-RNTI : see Table 4-10 from SCF082 - nFAPI specifications
-	    dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power                     = 6000; // equal to RS power
+	    // Generate DCI + repetitions first
+	    // This uses an MPDCCH Type 2 allocation according to Section 9.1.5 36-213
+	    // Parameters:
+	    //    p=2+4 PRB set (number of PRB pairs 6)
+	    //    rmax = mpdcch-NumRepetition-RA-r13 => Table 9.1.5-3
+	    //    if CELevel = 0,1 => Table 9.1.5-1b for MPDCCH candidates
+	    //    if CELevel = 2,3 => Table 9.1.5-2b for MPDCCH candidates
+	    //    distributed transmission
 	    
-	    dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process                           = 0;
-	    dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc                                    = 1; // no TPC
-	    dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1                   = 1;
-	    dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1                   = 0;
-	    dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.virtual_resource_block_assignment_flag = 0;
-
-            // Compute MCS for 3 PRB
-            msg4_header = 1+6+1;  // CR header, CR CE, SDU header
-
-
-	    if ((rrc_sdu_length+msg4_header) <= 22) {
-	      dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = 4;
-	      TBsize = 22;
-	    } else if ((rrc_sdu_length+msg4_header) <= 28) {
-	      dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = 5;
-	      TBsize = 28;
-	    } else if ((rrc_sdu_length+msg4_header) <= 32) {
-	      dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = 6;
-	      TBsize = 32;
-	    } else if ((rrc_sdu_length+msg4_header) <= 41) {
-	      dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = 7;
-	      TBsize = 41;
-	    } else if ((rrc_sdu_length+msg4_header) <= 49) {
-	      dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = 8;
-	      TBsize = 49;
-	    } else if ((rrc_sdu_length+msg4_header) <= 57) {
-	      dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = 9;
-	      TBsize = 57;
-	    }
-
-	    dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding= getRIV(N_RB_DL,first_rb,4);
-
-	    if (!CCE_allocation_infeasible(module_idP,CC_id,0,subframeP,dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level,RA_template->rnti)) {
-	      dl_req->number_dci++;
-	      dl_req->number_pdu++;
-		      
-	      RA_template->generate_Msg4=0;
-	      RA_template->wait_ack_Msg4=1;
-	      RA_template->RA_active = FALSE;
-	      lcid=0;
-
-	      // set HARQ process 0 round to 0 for this UE
-	      UE_list->UE_sched_ctrl[UE_id].round[CC_id] = 0;
-
-	      if ((TBsize - rrc_sdu_length - msg4_header) <= 2) {
-		msg4_padding = TBsize - rrc_sdu_length - msg4_header;
-		msg4_post_padding = 0;
-	      } else {
-		msg4_padding = 0;
-		msg4_post_padding = TBsize - rrc_sdu_length - msg4_header -1;
-	      }
-	      
-	      LOG_I(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d subframeP %d Msg4 : TBS %d, sdu_len %d, msg4_header %d, msg4_padding %d, msg4_post_padding %d\n",
-		    module_idP,CC_id,frameP,subframeP,TBsize,rrc_sdu_length,msg4_header,msg4_padding,msg4_post_padding);
-	      DevAssert( UE_id != UE_INDEX_INVALID ); // FIXME not sure how to gracefully return
-	      // CHECK THIS: &cc[CC_id].CCCH_pdu.payload[0]
-	      offset = generate_dlsch_header((unsigned char*)eNB->UE_list.DLSCH_pdu[CC_id][0][(unsigned char)UE_id].payload[0],
-					     1,                           //num_sdus
-					     (unsigned short*)&rrc_sdu_length,             //
-					     &lcid,                       // sdu_lcid
-					     255,                         // no drx
-					     0,                           // no timing advance
-					     RA_template->cont_res_id,  // contention res id
-					     msg4_padding,                // no padding
-					     msg4_post_padding);
-	      
-	      memcpy((void*)&eNB->UE_list.DLSCH_pdu[CC_id][0][(unsigned char)UE_id].payload[0][(unsigned char)offset],
-		     &cc[CC_id].CCCH_pdu.payload[0],
-		     rrc_sdu_length);
-
-	    // DL request
-	      eNB->TX_req[CC_id].sfn_sf                                             = (frameP<<3)+subframeP;
-	      TX_req                                                                = &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB->TX_req[CC_id].tx_request_body.number_of_pdus]; 		     	      
-	      TX_req->pdu_length                                                    = rrc_sdu_length;
-	      TX_req->pdu_index                                                     = eNB->pdu_index[CC_id]++;
-	      TX_req->num_segments                                                  = 1;
-	      TX_req->segments[0].segment_length                                    = rrc_sdu_length;
-	      TX_req->segments[0].segment_data                                      = eNB->UE_list.DLSCH_pdu[CC_id][0][(unsigned char)UE_id].payload[0];
-	      eNB->TX_req[CC_id].tx_request_body.number_of_pdus++;
-	      
-              T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_idP), T_INT(CC_id), T_INT(RA_template->rnti), T_INT(frameP), T_INT(subframeP),
-                T_INT(0 /*harq_pid always 0?*/), T_BUFFER(&eNB->UE_list.DLSCH_pdu[CC_id][0][UE_id].payload[0], TBsize));
+	    // rmax from SIB2 information
+	    rmax           = p[RA_template->rach_resource_type-1]->mpdcch_NumRepetition_RA_r13;
+	    // choose r3 by default for Msg4
+	    rep            = 2; 
+	    // get actual repetition count from Table 9.1.5-3
+	    reps           = (rmax<=8)?(1<<rep):(rmax>>(3-rep));
+	    // get first narrowband
+	    first_rb = RA_template->msg34_narrowband*6;
+	    
+	    if ((RA_template->msg4_mpdcch_repetition_cnt == 0) &&
+		(mpdcch_sf_condition(eNB,CC_id,frameP,subframeP,rmax,TYPE2)>0)){
+	      // MPDCCH configuration for RAR
 	      
-	      if (opt_enabled==1) {
-		trace_pdu(1, (uint8_t *)eNB->UE_list.DLSCH_pdu[CC_id][0][(unsigned char)UE_id].payload[0],
-			  rrc_sdu_length, UE_id, 3, UE_RNTI(module_idP, UE_id),
-			  eNB->frame, eNB->subframe,0,0);
-		LOG_D(OPT,"[eNB %d][DLSCH] CC_id %d Frame %d trace pdu for rnti %x with size %d\n",
-		      module_idP, CC_id, frameP, UE_RNTI(module_idP,UE_id), rrc_sdu_length);
-	      }
+	      memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t));
+	      dl_config_pdu->pdu_type                                                                  = NFAPI_DL_CONFIG_MPDCCH_PDU_TYPE; 
+	      dl_config_pdu->pdu_size                                                                  = (uint8_t)(2+sizeof(nfapi_dl_config_mpdcch_pdu));
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_format                                    = (RA_template->rach_resource_type > 1) ? 11 : 10;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_narrow_band                            = RA_template->msg34_narrowband;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.number_of_prb_pairs                           = 6;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_assignment                     = 0; // Note: this can be dynamic
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mpdcch_tansmission_type                       = 1;
+	      AssertFatal(cc[CC_id].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13!=NULL,
+			  "cc[CC_id].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13 is null\n");
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.start_symbol                                  = cc[CC_id].sib1_v13ext->bandwidthReducedAccessRelatedInfo_r13->startSymbolBR_r13;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ecce_index                                    = 0;  // Note: this should be dynamic
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.aggregation_level                             = 16; // OK for CEModeA r1-3 (9.1.5-1b) or CEModeB r1-4
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti_type                                     = 2;  // RA-RNTI
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.rnti                                          = RA_template->RA_rnti;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.ce_mode                                       = (RA_template->rach_resource_type < 3) ? 1 : 2;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.drms_scrambling_init                          = cc[CC_id].physCellId;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.initial_transmission_sf_io                    = (frameP*10)+subframeP;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.transmission_power                            = 6000; // 0dB
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.resource_block_coding                         = getRIV(N_RB_DL,first_rb,6);
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.mcs                                           = 4; // adjust according to size of RAR, 208 bits with N1A_PRB=3
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pdsch_reptition_levels                        = 4; // fix to 4 for now
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.redundancy_version                            = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.new_data_indicator                            = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_process                                  = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi_length                                   = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpmi                                          = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi_flag                                      = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.pmi                                           = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.harq_resource_offset                          = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.dci_subframe_repetition_number                = rep; 
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.tpc                                           = 2;// N1A_PRB=3; => 208 bits
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.downlink_assignment_index_length              = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.downlink_assignment_index                     = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.allocate_prach_flag                           = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.preamble_index                                = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.prach_mask_index                              = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.starting_ce_level                             = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.srs_request                                   = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity_flag    = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.antenna_ports_and_scrambling_identity         = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.frequency_hopping_enabled_flag                = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.paging_direct_indication_differentiation_flag = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.direct_indication                             = 0;
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.total_dci_length_including_padding            = 0; // this is not needed by OAI L1, but should be filled in
+	      dl_config_pdu->mpdcch_pdu.mpdcch_pdu_rel13.number_of_tx_antenna_ports                    = 1;
+	      RA_template->msg4_mpdcch_repetition_cnt++;
+	      dl_req->number_pdu++;
 	      
-	    }
-	  }
-
-          //try here
-        }
-
-      } else if (RA_template->wait_ack_Msg4==1) {
+	    } //repetition_count==0 && SF condition met
+	    if (RA_template->msg4_mpdcch_repetition_cnt>0) { // we're in a stream of repetitions
+	      RA_template->msg4_mpdcch_repetition_cnt++;	      
+	      if (RA_template->msg4_mpdcch_repetition_cnt==reps) { // this is the last mpdcch repetition
+		if (cc[CC_id].tdd_Config==NULL) { // FDD case
+		  // wait 2 subframes for PDSCH transmission
+		  if (subframeP>7) RA_template->Msg4_frame = (frameP+1)&1023;
+		  else             RA_template->Msg4_frame = frameP;
+		  RA_template->Msg4_subframe               = (subframeP+2)%10; 
+		}
+		else {
+		  AssertFatal(1==0,"TDD case not done yet\n");
+		}
+	      } // mpdcch_repetition_count == reps
+	      if ((RA_template->Msg4_frame == frameP) && (RA_template->Msg4_subframe == subframeP)) {
+		// Program PDSCH
+		RA_template->generate_rar = 0;	 
+		
+		LOG_I(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d: Generating Msg4 BR with RRC Piggyback (RA proc %d, RNTI %x)\n",
+		      module_idP, CC_id, frameP, subframeP,i,RA_template->rnti);
+		
+		dl_config_pdu                                                                  = &dl_req->dl_config_pdu_list[dl_req->number_pdu]; 
+		memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t));
+		dl_config_pdu->pdu_type                                                        = NFAPI_DL_CONFIG_DLSCH_PDU_TYPE; 
+		dl_config_pdu->pdu_size                                                        = (uint8_t)(2+sizeof(nfapi_dl_config_dlsch_pdu));
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pdu_index                              = eNB->pdu_index[CC_id];
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.rnti                                   = RA_template->rnti;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_allocation_type               = 2;   // format 1A/1B/1D
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.virtual_resource_block_assignment_flag = 0;   // localized
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.resource_block_coding                  = getRIV(N_RB_DL,first_rb,6);
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.modulation                             = 2; //QPSK
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.redundancy_version                     = 0;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_blocks                       = 1;// first block
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transport_block_to_codeword_swap_flag  = 0;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_scheme                    = (cc->p_eNB==1 ) ? 0 : 1;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_layers                       = 1;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.number_of_subbands                     = 1;
+		//	dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.codebook_index                         = ;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ue_category_capacity                   = 1;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.pa                                     = 4; // 0 dB
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.delta_power_offset_index               = 0;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.ngap                                   = 0;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.nprb                                   = get_subbandsize(cc->mib->message.dl_Bandwidth); // ignored
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.transmission_mode                      = (cc->p_eNB==1 ) ? 1 : 2;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_prb_per_subband                 = 1;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector                          = 1;
+		//	dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector                    = ; 
+		
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.ue_type                               = (RA_template->rach_resource_type < 3) ? 1 : 2;;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.pdsch_payload_type                    = 2;  // not SI message
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.initial_transmission_sf_io            = (10*frameP)+subframeP;
+		dl_config_pdu->dlsch_pdu.dlsch_pdu_rel13.drms_table_flag                       = 0;
+		dl_req->number_pdu++;
+		
+		RA_template->generate_Msg4=0;
+		RA_template->wait_ack_Msg4=1;
+		RA_template->RA_active = FALSE;
+		lcid=0;
+		
+		// set HARQ process 0 round to 0 for this UE
+		UE_list->UE_sched_ctrl[UE_id].round[CC_id] = 0;
+		
+		if ((TBsize - rrc_sdu_length - msg4_header) <= 2) {
+		  msg4_padding = TBsize - rrc_sdu_length - msg4_header;
+		  msg4_post_padding = 0;
+		} else {
+		  msg4_padding = 0;
+		  msg4_post_padding = TBsize - rrc_sdu_length - msg4_header -1;
+		}
+		
+		LOG_I(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d subframeP %d Msg4 : TBS %d, sdu_len %d, msg4_header %d, msg4_padding %d, msg4_post_padding %d\n",
+		      module_idP,CC_id,frameP,subframeP,TBsize,rrc_sdu_length,msg4_header,msg4_padding,msg4_post_padding);
+		DevAssert( UE_id != UE_INDEX_INVALID ); // FIXME not sure how to gracefully return
+		// CHECK THIS: &cc[CC_id].CCCH_pdu.payload[0]
+		offset = generate_dlsch_header((unsigned char*)eNB->UE_list.DLSCH_pdu[CC_id][0][(unsigned char)UE_id].payload[0],
+					       1,                           //num_sdus
+					       (unsigned short*)&rrc_sdu_length,             //
+					       &lcid,                       // sdu_lcid
+					       255,                         // no drx
+					       0,                           // no timing advance
+					       RA_template->cont_res_id,  // contention res id
+					       msg4_padding,                // no padding
+					       msg4_post_padding);
+		
+		memcpy((void*)&eNB->UE_list.DLSCH_pdu[CC_id][0][(unsigned char)UE_id].payload[0][(unsigned char)offset],
+		       &cc[CC_id].CCCH_pdu.payload[0],
+		       rrc_sdu_length);
+		
+		// DL request
+		eNB->TX_req[CC_id].sfn_sf                                             = (frameP<<3)+subframeP;
+		TX_req                                                                = &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB->TX_req[CC_id].tx_request_body.number_of_pdus]; 		     	      
+		TX_req->pdu_length                                                    = rrc_sdu_length;
+		TX_req->pdu_index                                                     = eNB->pdu_index[CC_id]++;
+		TX_req->num_segments                                                  = 1;
+		TX_req->segments[0].segment_length                                    = rrc_sdu_length;
+		TX_req->segments[0].segment_data                                      = eNB->UE_list.DLSCH_pdu[CC_id][0][(unsigned char)UE_id].payload[0];
+		eNB->TX_req[CC_id].tx_request_body.number_of_pdus++;
+		
+		T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_idP), T_INT(CC_id), T_INT(RA_template->rnti), T_INT(frameP), T_INT(subframeP),
+		  T_INT(0 /*harq_pid always 0?*/), T_BUFFER(&eNB->UE_list.DLSCH_pdu[CC_id][0][UE_id].payload[0], TBsize));
+		
+		if (opt_enabled==1) {
+		  trace_pdu(1, (uint8_t *)eNB->UE_list.DLSCH_pdu[CC_id][0][(unsigned char)UE_id].payload[0],
+			    rrc_sdu_length, UE_id, 3, UE_RNTI(module_idP, UE_id),
+			    eNB->frame, eNB->subframe,0,0);
+		  LOG_D(OPT,"[eNB %d][DLSCH] CC_id %d Frame %d trace pdu for rnti %x with size %d\n",
+			module_idP, CC_id, frameP, UE_RNTI(module_idP,UE_id), rrc_sdu_length);
+		}
+	      } // Msg4 frame/subframe
+	    } // msg4_mpdcch_repetition_count
+	  } // rach_resource_type > 0 
+	  else
+#endif
+	    {
+	      if ((RA_template->Msg4_frame == frameP) && (RA_template->Msg4_subframe == subframeP)) {	      
+		LOG_I(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d: Generating Msg4 with RRC Piggyback (RA proc %d, RNTI %x)\n",
+		      module_idP, CC_id, frameP, subframeP,i,RA_template->rnti);
+		
+		first_rb=0;
+		
+		vrb_map[first_rb] = 1;
+		vrb_map[first_rb+1] = 1;
+		vrb_map[first_rb+2] = 1;
+		vrb_map[first_rb+3] = 1;
+		
+		
+		memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t));
+		dl_config_pdu->pdu_type                                                          = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; 
+		dl_config_pdu->pdu_size                                                          = (uint8_t)(2+sizeof(nfapi_dl_config_dci_dl_pdu));
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format                             = NFAPI_DL_DCI_FORMAT_1A;
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level                      = 4;
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti                                   = RA_template->rnti;
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type                              = 1;    // C-RNTI : see Table 4-10 from SCF082 - nFAPI specifications
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power                     = 6000; // equal to RS power
+		
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process                           = 0;
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc                                    = 1; // no TPC
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1                   = 1;
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1                   = 0;
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.virtual_resource_block_assignment_flag = 0;
+		
+		// Compute MCS for 3 PRB
+		msg4_header = 1+6+1;  // CR header, CR CE, SDU header
+		
+		
+		if ((rrc_sdu_length+msg4_header) <= 22) {
+		  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = 4;
+		  TBsize = 22;
+		} else if ((rrc_sdu_length+msg4_header) <= 28) {
+		  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = 5;
+		  TBsize = 28;
+		} else if ((rrc_sdu_length+msg4_header) <= 32) {
+		  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = 6;
+		  TBsize = 32;
+		} else if ((rrc_sdu_length+msg4_header) <= 41) {
+		  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = 7;
+		  TBsize = 41;
+		} else if ((rrc_sdu_length+msg4_header) <= 49) {
+		  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = 8;
+		  TBsize = 49;
+		} else if ((rrc_sdu_length+msg4_header) <= 57) {
+		  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = 9;
+		  TBsize = 57;
+		}
+		
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding= getRIV(N_RB_DL,first_rb,4);
+		
+		if (!CCE_allocation_infeasible(module_idP,CC_id,0,subframeP,dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level,RA_template->rnti)) {
+		  dl_req->number_dci++;
+		  dl_req->number_pdu++;
+		  
+		  RA_template->generate_Msg4=0;
+		  RA_template->wait_ack_Msg4=1;
+		  RA_template->RA_active = FALSE;
+		  lcid=0;
+		  
+		  // set HARQ process 0 round to 0 for this UE
+		  UE_list->UE_sched_ctrl[UE_id].round[CC_id] = 0;
+		  
+		  if ((TBsize - rrc_sdu_length - msg4_header) <= 2) {
+		    msg4_padding = TBsize - rrc_sdu_length - msg4_header;
+		    msg4_post_padding = 0;
+		  } else {
+		    msg4_padding = 0;
+		    msg4_post_padding = TBsize - rrc_sdu_length - msg4_header -1;
+		  }
+		  
+		  LOG_I(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d subframeP %d Msg4 : TBS %d, sdu_len %d, msg4_header %d, msg4_padding %d, msg4_post_padding %d\n",
+			module_idP,CC_id,frameP,subframeP,TBsize,rrc_sdu_length,msg4_header,msg4_padding,msg4_post_padding);
+		  DevAssert( UE_id != UE_INDEX_INVALID ); // FIXME not sure how to gracefully return
+		  // CHECK THIS: &cc[CC_id].CCCH_pdu.payload[0]
+		  offset = generate_dlsch_header((unsigned char*)eNB->UE_list.DLSCH_pdu[CC_id][0][(unsigned char)UE_id].payload[0],
+						 1,                           //num_sdus
+						 (unsigned short*)&rrc_sdu_length,             //
+						 &lcid,                       // sdu_lcid
+						 255,                         // no drx
+						 0,                           // no timing advance
+						 RA_template->cont_res_id,  // contention res id
+						 msg4_padding,                // no padding
+						 msg4_post_padding);
+		  
+		  memcpy((void*)&eNB->UE_list.DLSCH_pdu[CC_id][0][(unsigned char)UE_id].payload[0][(unsigned char)offset],
+			 &cc[CC_id].CCCH_pdu.payload[0],
+			 rrc_sdu_length);
+		  
+		  // DL request
+		  eNB->TX_req[CC_id].sfn_sf                                             = (frameP<<3)+subframeP;
+		  TX_req                                                                = &eNB->TX_req[CC_id].tx_request_body.tx_pdu_list[eNB->TX_req[CC_id].tx_request_body.number_of_pdus]; 		     	      
+		  TX_req->pdu_length                                                    = rrc_sdu_length;
+		  TX_req->pdu_index                                                     = eNB->pdu_index[CC_id]++;
+		  TX_req->num_segments                                                  = 1;
+		  TX_req->segments[0].segment_length                                    = rrc_sdu_length;
+		  TX_req->segments[0].segment_data                                      = eNB->UE_list.DLSCH_pdu[CC_id][0][(unsigned char)UE_id].payload[0];
+		  eNB->TX_req[CC_id].tx_request_body.number_of_pdus++;
+		  
+		  T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_idP), T_INT(CC_id), T_INT(RA_template->rnti), T_INT(frameP), T_INT(subframeP),
+		    T_INT(0 /*harq_pid always 0?*/), T_BUFFER(&eNB->UE_list.DLSCH_pdu[CC_id][0][UE_id].payload[0], TBsize));
+		  
+		  if (opt_enabled==1) {
+		    trace_pdu(1, (uint8_t *)eNB->UE_list.DLSCH_pdu[CC_id][0][(unsigned char)UE_id].payload[0],
+			      rrc_sdu_length, UE_id, 3, UE_RNTI(module_idP, UE_id),
+			      eNB->frame, eNB->subframe,0,0);
+		    LOG_D(OPT,"[eNB %d][DLSCH] CC_id %d Frame %d trace pdu for rnti %x with size %d\n",
+			  module_idP, CC_id, frameP, UE_RNTI(module_idP,UE_id), rrc_sdu_length);
+		  }
+		  
+		} // CCE Allocation feasible
+	      } // msg4 frame/subframe
+	    } // else rach_resource_type
+	} else if (RA_template->wait_ack_Msg4==1) {
 	// check HARQ status and retransmit if necessary
-	LOG_I(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d: Checking if Msg4 was acknowledged: \tn",
-	      module_idP,CC_id,frameP,subframeP);
-	// Get candidate harq_pid from PHY
-
-	UE_id = find_UE_id(module_idP,RA_template->rnti);
-	AssertFatal(UE_id>=0,"Can't find UE for t-crnti\n");
-	round = UE_list->UE_sched_ctrl[UE_id].round[CC_id];
-
-	if (round>0) {
-	  //RA_template->wait_ack_Msg4++;
-	  // we have to schedule a retransmission
+	  LOG_I(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d: Checking if Msg4 was acknowledged: \tn",
+		module_idP,CC_id,frameP,subframeP);
+	  // Get candidate harq_pid from PHY
 	  
-	  first_rb=0;
-	  vrb_map[first_rb] = 1;
-	  vrb_map[first_rb+1] = 1;
-	  vrb_map[first_rb+2] = 1;
-	  vrb_map[first_rb+3] = 1;
-
-	  memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t));
-	  dl_config_pdu->pdu_type                                                          = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; 
-	  dl_config_pdu->pdu_size                                                          = (uint8_t)(2+sizeof(nfapi_dl_config_dci_dl_pdu));
-	  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format                             = NFAPI_DL_DCI_FORMAT_1A;
-	  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level                      = 4;
-	  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti                                   = RA_template->rnti;
-	  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type                              = 1;    // C-RNTI : see Table 4-10 from SCF082 - nFAPI specifications
-	  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power                     = 6000; // equal to RS power
-	  
-	  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process                           = 0;
-	  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc                                    = 1; // no TPC
-	  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1                   = 1;
-	  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1                   = 0;
-	  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.virtual_resource_block_assignment_flag = 0;
-	  
-	  // Compute MCS for 3 PRB
-	  msg4_header = 1+6+1;  // CR header, CR CE, SDU header
-	  
-	  
-	  if ((rrc_sdu_length+msg4_header) <= 22) {
-	    dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = 4;
-	    TBsize = 22;
-	  } else if ((rrc_sdu_length+msg4_header) <= 28) {
-	    dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = 5;
-	    TBsize = 28;
-	  } else if ((rrc_sdu_length+msg4_header) <= 32) {
-	    dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = 6;
-	    TBsize = 32;
-	  } else if ((rrc_sdu_length+msg4_header) <= 41) {
-	    dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = 7;
-	    TBsize = 41;
-	  } else if ((rrc_sdu_length+msg4_header) <= 49) {
-	    dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = 8;
-	    TBsize = 49;
-	  } else if ((rrc_sdu_length+msg4_header) <= 57) {
-	    dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = 9;
-	    TBsize = 57;
-	  }
-	  
-	  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding= getRIV(N_RB_DL,first_rb,4);
+	  UE_id = find_UE_id(module_idP,RA_template->rnti);
+	  AssertFatal(UE_id>=0,"Can't find UE for t-crnti\n");
+	  round = UE_list->UE_sched_ctrl[UE_id].round[CC_id];
 	  
-	  if (!CCE_allocation_infeasible(module_idP,CC_id,0,subframeP,dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level,RA_template->rnti)) {
-	    dl_req->number_dci++;
-	    dl_req->number_pdu++;
+	  if (round>0) {
+
+#ifdef Rel14
+	    AssertFatal(1==0,"Msg4 Retransmissions not handled yet for BL/CE UEs\n");
+#endif 
+	    {
+	      if ( (RA_template->Msg4_frame == frameP) && (RA_template->Msg4_subframe == subframeP)) {	       
+
+		//RA_template->wait_ack_Msg4++;
+		// we have to schedule a retransmission
+		
+		first_rb=0;
+		vrb_map[first_rb] = 1;
+		vrb_map[first_rb+1] = 1;
+		vrb_map[first_rb+2] = 1;
+		vrb_map[first_rb+3] = 1;
+		
+		memset((void*)dl_config_pdu,0,sizeof(nfapi_dl_config_request_pdu_t));
+		dl_config_pdu->pdu_type                                                          = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; 
+		dl_config_pdu->pdu_size                                                          = (uint8_t)(2+sizeof(nfapi_dl_config_dci_dl_pdu));
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format                             = NFAPI_DL_DCI_FORMAT_1A;
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level                      = 4;
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti                                   = RA_template->rnti;
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type                              = 1;    // C-RNTI : see Table 4-10 from SCF082 - nFAPI specifications
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power                     = 6000; // equal to RS power
+		
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process                           = 0;
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc                                    = 1; // no TPC
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1                   = 1;
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1                   = 0;
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.virtual_resource_block_assignment_flag = 0;
+		
+		// Compute MCS for 3 PRB
+		msg4_header = 1+6+1;  // CR header, CR CE, SDU header
+		
+		
+		if ((rrc_sdu_length+msg4_header) <= 22) {
+		  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = 4;
+		  TBsize = 22;
+		} else if ((rrc_sdu_length+msg4_header) <= 28) {
+		  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = 5;
+		  TBsize = 28;
+		} else if ((rrc_sdu_length+msg4_header) <= 32) {
+		  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = 6;
+		  TBsize = 32;
+		} else if ((rrc_sdu_length+msg4_header) <= 41) {
+		  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = 7;
+		  TBsize = 41;
+		} else if ((rrc_sdu_length+msg4_header) <= 49) {
+		  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = 8;
+		  TBsize = 49;
+		} else if ((rrc_sdu_length+msg4_header) <= 57) {
+		  dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.mcs_1                       = 9;
+		  TBsize = 57;
+		}
+		
+		dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding= getRIV(N_RB_DL,first_rb,4);
+		
+		if (!CCE_allocation_infeasible(module_idP,CC_id,0,subframeP,dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level,RA_template->rnti)) {
+		  dl_req->number_dci++;
+		  dl_req->number_pdu++;
 		  
-	    LOG_I(MAC,"msg4 retransmission for rnti %x (round %d) fsf %d/%d\n", RA_template->rnti, round, frameP, subframeP);
+		  LOG_I(MAC,"msg4 retransmission for rnti %x (round %d) fsf %d/%d\n", RA_template->rnti, round, frameP, subframeP);
+		}
+		else
+		  LOG_I(MAC,"msg4 retransmission for rnti %x (round %d) fsf %d/%d CCE allocation failed!\n", RA_template->rnti, round, frameP, subframeP);
+		LOG_W(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d: Msg4 not acknowledged, adding ue specific dci (rnti %x) for RA (Msg4 Retransmission)\n",
+		      module_idP,CC_id,frameP,subframeP,RA_template->rnti);
+	      }
+	    }
+ 
+	  } else {
+	    LOG_I(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d : Msg4 acknowledged\n",module_idP,CC_id,frameP,subframeP);
+	    RA_template->wait_ack_Msg4=0;
+	    RA_template->RA_active=FALSE;
+	    UE_id = find_UE_id(module_idP,RA_template->rnti);
+	    DevAssert( UE_id != -1 );
+	    eNB->UE_list.UE_template[UE_PCCID(module_idP,UE_id)][UE_id].configured=TRUE;
 	  }
-	  else
-	    LOG_I(MAC,"msg4 retransmission for rnti %x (round %d) fsf %d/%d CCE allocation failed!\n", RA_template->rnti, round, frameP, subframeP);
-	  LOG_W(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d: Msg4 not acknowledged, adding ue specific dci (rnti %x) for RA (Msg4 Retransmission)\n",
-		module_idP,CC_id,frameP,subframeP,RA_template->rnti);
-	} else {
-	  LOG_I(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d, subframeP %d : Msg4 acknowledged\n",module_idP,CC_id,frameP,subframeP);
-	  RA_template->wait_ack_Msg4=0;
-	  RA_template->RA_active=FALSE;
-	  UE_id = find_UE_id(module_idP,RA_template->rnti);
-	  DevAssert( UE_id != -1 );
-	  eNB->UE_list.UE_template[UE_PCCID(module_idP,UE_id)][UE_id].configured=TRUE;
-	}
-      }
+	} //wait_ack_Msg4 == 1
+      } // RA_active == TRUE
     } // for i=0 .. N_RA_PROC-1 
   } // CC_id
-
+  
   stop_meas(&eNB->schedule_ra);
 }
 
+
 // handles the event of MSG1 reception
-void initiate_ra_proc(module_id_t module_idP, int CC_id,frame_t frameP, sub_frame_t subframeP,uint16_t preamble_index,int16_t timing_offset,uint16_t ra_rnti)
+void initiate_ra_proc(module_id_t module_idP, 
+		      int CC_id,
+		      frame_t frameP, 
+		      sub_frame_t subframeP,
+		      uint16_t preamble_index,
+		      int16_t timing_offset,
+		      uint16_t ra_rnti
+#ifdef Rel14
+		      ,
+		      uint8_t rach_resource_type
+#endif
+		      )
 {
 
   uint8_t i;
   RA_TEMPLATE *RA_template = (RA_TEMPLATE *)&RC.mac[module_idP]->common_channels[CC_id].RA_template[0];
 
   LOG_D(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d Initiating RA procedure for preamble index %d\n",module_idP,CC_id,frameP,preamble_index);
+#ifdef Rel14
+		      LOG_D(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d PRACH resource type %d\n",module_idP,CC_id,frameP,preamble_index,rach_resource_type);
+#endif
 
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_INITIATE_RA_PROC,1);
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_INITIATE_RA_PROC,0);
@@ -518,12 +910,17 @@ void initiate_ra_proc(module_id_t module_idP, int CC_id,frame_t frameP, sub_fram
     if (RA_template[i].RA_active==FALSE &&
         RA_template[i].wait_ack_Msg4 == 0) {
       int loop = 0;
-      RA_template[i].RA_active         = TRUE;
-      RA_template[i].generate_rar      = 1;
-      RA_template[i].generate_Msg4     = 0;
-      RA_template[i].wait_ack_Msg4     = 0;
-      RA_template[i].timing_offset     = timing_offset;
-      RA_template[i].preamble_subframe = subframeP;
+      RA_template[i].RA_active          = TRUE;
+      RA_template[i].generate_rar       = 1;
+      RA_template[i].generate_Msg4      = 0;
+      RA_template[i].wait_ack_Msg4      = 0;
+      RA_template[i].timing_offset      = timing_offset;
+      RA_template[i].preamble_subframe  = subframeP;
+#ifdef Rel14
+      RA_template[i].rach_resource_type = rach_resource_type;
+      RA_template[i].msg2_mpdcch_repetition_cnt = 0;		      
+      RA_template[i].msg4_mpdcch_repetition_cnt = 0;		      
+#endif
       /* TODO: find better procedure to allocate RNTI */
       do {
         RA_template[i].rnti = taus();
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c
index afffd90dd0..dceff068d3 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c
@@ -208,6 +208,8 @@ void get_Msg3alloc(COMMON_channels_t *cc,
   }
 }
 
+
+
 void get_Msg3allocret(COMMON_channels_t *cc,
 		      unsigned char current_subframe,
 		      unsigned int current_frame,
@@ -401,6 +403,67 @@ uint8_t get_Msg3harqpid(COMMON_channels_t *cc,
 
 }
 
+#ifdef Rel14
+
+int get_numnarrowbands(long dl_Bandwidth) {
+  int nb_tab[6] = {1,2,4,8,12,16};
+
+  AssertFatal(dl_Bandwidth<7 || dl_Bandwidth>=0,"dl_Bandwidth not in [0..6]\n");
+  return(nb_tab[dl_Bandwidth]);
+}
+
+int get_numnarrowbandbits(long dl_Bandwidth) {
+  int nbbits_tab[6] = {0,1,2,3,4,4};
+
+  AssertFatal(dl_Bandwidth<7 || dl_Bandwidth>=0,"dl_Bandwidth not in [0..6]\n");
+  return(nbbits_tab[dl_Bandwidth]);
+}
+
+//This implements the frame/subframe condition for first subframe of MPDCCH transmission (Section 9.1.5 36.213, Rel 13/14)
+int startSF_fdd_RA_times2[8] = {2,3,4,5,8,10,16,20};
+int startSF_tdd_RA[7]        = {1,2,4,5,8,10,20};
+
+int mpdcch_sf_condition(eNB_MAC_INST *eNB,int CC_id, frame_t frameP,sub_frame_t subframeP,int rmax,MPDCCH_TYPES_t mpdcch_type) {
+
+  struct PRACH_ConfigSIB_v1310 *ext4_prach = eNB->common_channels[CC_id].radioResourceConfigCommon_BR->ext4->prach_ConfigCommon_v1310;
+  int T;
+
+  switch (mpdcch_type) {
+  case TYPE0:
+    AssertFatal(1==0,"MPDCCH Type 0 not handled yet\n");
+    break;
+  case TYPE1:
+    AssertFatal(1==0,"MPDCCH Type 1 not handled yet\n");
+    break;
+  case TYPE1A:
+    AssertFatal(1==0,"MPDCCH Type 1A not handled yet\n");
+    break;
+  case TYPE2: // RAR
+    AssertFatal(ext4_prach->mpdcch_startSF_CSS_RA_r13!=NULL,
+		"mpdcch_startSF_CSS_RA_r13 is null\n");
+    if (eNB->common_channels[CC_id].tdd_Config==NULL) //FDD
+      T = rmax*startSF_fdd_RA_times2[ext4_prach->mpdcch_startSF_CSS_RA_r13->choice.fdd_r13]>>1;
+    else //TDD
+      T = rmax*startSF_tdd_RA[ext4_prach->mpdcch_startSF_CSS_RA_r13->choice.tdd_r13];
+    break;
+  case TYPE2A:
+    AssertFatal(1==0,"MPDCCH Type 2A not handled yet\n");
+    break;
+  case TYPEUESPEC:
+    AssertFatal(1==0,"MPDCCH Type UESPEC not handled yet\n");
+    break;
+  default:
+    return(0);
+  }
+
+  if (((10*frameP) + subframeP)%T == 0) return(1);
+  else return(0);
+
+}
+
+
+#endif
+
 //------------------------------------------------------------------------------
 void init_ue_sched_info(void)
 //------------------------------------------------------------------------------
diff --git a/openair2/LAYER2/MAC/main.c b/openair2/LAYER2/MAC/main.c
index ef47b42736..6e5fa91f14 100644
--- a/openair2/LAYER2/MAC/main.c
+++ b/openair2/LAYER2/MAC/main.c
@@ -171,6 +171,7 @@ int mac_top_init_eNB()
 		  RC.nb_macrlc_inst*sizeof(eNB_MAC_INST*),RC.nb_macrlc_inst,sizeof(eNB_MAC_INST));
       LOG_D(MAC,"[MAIN] ALLOCATE %zu Bytes for %d eNB_MAC_INST @ %p\n",sizeof(eNB_MAC_INST),RC.nb_macrlc_inst,RC.mac);
       bzero(RC.mac[i],sizeof(eNB_MAC_INST));
+      RC.mac[i]->Mod_id = Mod_id;
       for (j=0;j<MAX_NUM_CCs;j++) {
 	RC.mac[i]->DL_req[j].dl_config_request_body.dl_config_pdu_list      = RC.mac[i]->dl_config_pdu_list[j];
 	RC.mac[i]->UL_req[j].ul_config_request_body.ul_config_pdu_list      = RC.mac[i]->ul_config_pdu_list[j];
@@ -187,6 +188,7 @@ int mac_top_init_eNB()
   for(Mod_id=0; Mod_id<RC.nb_macrlc_inst; Mod_id++) {
     mac = RC.mac[Mod_id];
 
+
     mac->if_inst                = IF_Module_init(Mod_id);
 
     UE_list = &mac->UE_list;
diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h
index 83f07bd306..63e717f90e 100644
--- a/openair2/LAYER2/MAC/proto.h
+++ b/openair2/LAYER2/MAC/proto.h
@@ -205,8 +205,15 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP, uint8_t cooperation_flag,
 @param Mod_id Instance ID of eNB
 @param preamble_index index of the received RA request
 @param timing_offset Offset in samples of the received PRACH w.r.t. eNB timing. This is used to
+@param rnti RA rnti corresponding to this PRACH preamble
+@param rach_resource type (0=non BL/CE,1 CE level 0,2 CE level 1, 3 CE level 2,4 CE level 3)
 */
-void initiate_ra_proc(module_id_t module_idP,int CC_id,frame_t frameP, sub_frame_t subframeP, uint16_t preamble_index,int16_t timing_offset,uint16_t rnti);
+void initiate_ra_proc(module_id_t module_idP,int CC_id,frame_t frameP, sub_frame_t subframeP, uint16_t preamble_index,int16_t timing_offset,uint16_t rnti
+#ifdef Rel14
+		      ,
+		      uint8_t rach_resource_type
+#endif
+		      );
 
 /* \brief Function in eNB to fill RAR pdu when requested by PHY.  This provides a single RAR SDU for the moment and returns the t-CRNTI.
 @param Mod_id Instance ID of eNB
diff --git a/openair2/LAYER2/MAC/rar_tools.c b/openair2/LAYER2/MAC/rar_tools.c
index 8ccfa81ceb..d40c3280ef 100644
--- a/openair2/LAYER2/MAC/rar_tools.c
+++ b/openair2/LAYER2/MAC/rar_tools.c
@@ -129,6 +129,96 @@ unsigned short fill_rar(
   return(RC.mac[module_idP]->common_channels[CC_id].RA_template[ra_idx].rnti);
 }
 
+#ifdef Rel14
+//------------------------------------------------------------------------------
+unsigned short fill_rar_br(eNB_MAC_INST *eNB,
+			   const int          CC_id,
+			   const int          ra_idx,
+			   const frame_t      frameP,
+			   const sub_frame_t  subframeP,
+			   uint8_t*    const  dlsch_buffer,
+			   const uint8_t      ce_level
+)
+//------------------------------------------------------------------------------
+{
+
+  RA_HEADER_RAPID *rarh = (RA_HEADER_RAPID *)dlsch_buffer;
+
+  uint8_t *rar = (uint8_t *)(dlsch_buffer+1);
+  int i;
+  uint8_t nb,rballoc,reps;
+  uint8_t mcs,TPC,ULdelay,cqireq;
+  COMMON_channels_t *cc = &eNB->common_channels[CC_id];
+  int input_buffer_length;
+
+
+  AssertFatal(CC_id < MAX_NUM_CCs, "CC_id %u < MAX_NUM_CCs %u", CC_id, MAX_NUM_CCs);
+
+  AssertFatal(ra_idx >= 0 && ra_idx < 4, "RA index not in [0..3]\n");
+
+  // subheader fixed
+  rarh->E                     = 0; // First and last RAR
+  rarh->T                     = 1; // 0 for E/T/R/R/BI subheader, 1 for E/T/RAPID subheader
+  rarh->RAPID                 = cc->RA_template[ra_idx].preamble_index; // Respond to Preamble 0 only for the moment
+  cc->RA_template[ra_idx].timing_offset /= 16; //T_A = N_TA/16, where N_TA should be on a 30.72Msps
+  rar[0] = (uint8_t)(cc->RA_template[ra_idx].timing_offset>>(2+4)); // 7 MSBs of timing advance + divide by 4
+  rar[1] = (uint8_t)(cc->RA_template[ra_idx].timing_offset<<(4-2))&0xf0; // 4 LSBs of timing advance + divide by 4
+
+  int N_NB_index;
+
+  AssertFatal(1==0,"RAR for BL/CE Still to be finished ...\n"); 
+
+  // Copy the Msg2 narrowband
+  cc->RA_template[ra_idx].msg34_narrowband = cc->RA_template[ra_idx].msg2_narrowband; 
+
+  if (ce_level<2) { //CE Level 0,1, CEmodeA
+    input_buffer_length =6;
+
+    N_NB_index = get_numnarrowbandbits(cc->mib->message.dl_Bandwidth);
+
+    rar[4] = (uint8_t)(cc->RA_template[ra_idx].rnti>>8);
+    rar[5] = (uint8_t)(cc->RA_template[ra_idx].rnti&0xff);
+    //cc->RA_template[ra_idx].timing_offset = 0;
+    nb      = 0;
+    rballoc = mac_computeRIV(6,1+ra_idx,1); // one PRB only for UL Grant in position 1+ra_idx within Narrowband
+    rar[1] |= (rballoc&15)<<(4-N_NB_index); // Hopping = 0 (bit 3), 3 MSBs of rballoc
+
+    reps    = 4;
+    mcs     = 7;
+    TPC     = 3; // no power increase
+    ULdelay = 0;
+    cqireq = 0;
+    rar[2] |= ((mcs&0x8)>>3);  // mcs 10
+    rar[3] = (((mcs&0x7)<<5)) | ((TPC&7)<<2) | ((ULdelay&1)<<1) | (cqireq&1);
+  }
+  else { // CE level 2,3 => CEModeB
+
+    input_buffer_length =5;
+
+    rar[3] = (uint8_t)(cc->RA_template[ra_idx].rnti>>8);
+    rar[4] = (uint8_t)(cc->RA_template[ra_idx].rnti&0xff);
+  }
+  LOG_D(MAC,"[RAPROC] CC_id %d Frame %d Generating RAR BR (%02x|%02x.%02x.%02x.%02x.%02x.%02x) for ra_idx %d, CRNTI %x,preamble %d/%d,TIMING OFFSET %d\n",
+        CC_id,
+        frameP,
+        *(uint8_t*)rarh,rar[0],rar[1],rar[2],rar[3],rar[4],rar[5],
+        ra_idx,
+        cc->RA_template[ra_idx].rnti,
+        rarh->RAPID,cc->RA_template[0].preamble_index,
+        cc->RA_template[ra_idx].timing_offset);
+
+  if (opt_enabled) {
+    trace_pdu(1, dlsch_buffer, input_buffer_length, eNB->Mod_id, 2, 1,
+        eNB->frame, eNB->subframe, 0, 0);
+    LOG_D(OPT,"[eNB %d][RAPROC] CC_id %d RAR Frame %d trace pdu for rnti %x and  rapid %d size %d\n",
+          eNB->Mod_id, CC_id, frameP, cc->RA_template[ra_idx].rnti,
+          rarh->RAPID, input_buffer_length);
+  }
+
+  return(cc->RA_template[ra_idx].rnti);
+}
+#endif
+
 //------------------------------------------------------------------------------
 uint16_t
 ue_process_rar(
diff --git a/openair2/PHY_INTERFACE/IF_Module.c b/openair2/PHY_INTERFACE/IF_Module.c
index e52b52203d..bac5878ece 100644
--- a/openair2/PHY_INTERFACE/IF_Module.c
+++ b/openair2/PHY_INTERFACE/IF_Module.c
@@ -11,6 +11,7 @@ IF_Module_t *if_inst[MAX_IF_MODULES];
 Sched_Rsp_t Sched_INFO[MAX_IF_MODULES][MAX_NUM_CCs];
 
 void handle_rach(UL_IND_t *UL_info) {
+  int i;
 
   if (UL_info->rach_ind.number_of_preambles>0) {
 
@@ -23,8 +24,34 @@ void handle_rach(UL_IND_t *UL_info) {
 		     UL_info->subframe,
 		     UL_info->rach_ind.preamble_list[0].preamble_rel8.preamble,
 		     UL_info->rach_ind.preamble_list[0].preamble_rel8.timing_advance,
-		     UL_info->rach_ind.preamble_list[0].preamble_rel8.rnti);
+		     UL_info->rach_ind.preamble_list[0].preamble_rel8.rnti
+#ifdef Rel14
+		     ,0
+#endif
+		     );
+  }
+
+#ifdef Rel14
+  if (UL_info->rach_ind_br.number_of_preambles>0) {
+
+    AssertFatal(UL_info->rach_ind_br.number_of_preambles<5,"More than 4 preambles not supported\n");
+    for (i=0;i<UL_info->rach_ind_br.number_of_preambles;i++) {
+      AssertFatal(UL_info->rach_ind_br.preamble_list[i].preamble_rel13.rach_resource_type>0,
+		  "Got regular PRACH preamble, not BL/CE\n");
+      LOG_D(MAC,"Frame %d, Subframe %d Calling initiate_ra_proc (CE_level %d)\n",UL_info->frame,UL_info->subframe,
+	    UL_info->rach_ind_br.preamble_list[i].preamble_rel13.rach_resource_type-1);
+      initiate_ra_proc(UL_info->module_id,
+		       UL_info->CC_id,
+		       UL_info->frame,
+		       UL_info->subframe,
+		       UL_info->rach_ind_br.preamble_list[i].preamble_rel8.preamble,
+		       UL_info->rach_ind_br.preamble_list[i].preamble_rel8.timing_advance,
+		       UL_info->rach_ind_br.preamble_list[i].preamble_rel8.rnti,
+		       UL_info->rach_ind_br.preamble_list[i].preamble_rel13.rach_resource_type);
+    }
+    UL_info->rach_ind.number_of_preambles=0;
   }
+#endif
 }
 
 void handle_ulsch(UL_IND_t *UL_info) {
diff --git a/openair2/PHY_INTERFACE/IF_Module.h b/openair2/PHY_INTERFACE/IF_Module.h
index 9a6915b756..80844b10c8 100644
--- a/openair2/PHY_INTERFACE/IF_Module.h
+++ b/openair2/PHY_INTERFACE/IF_Module.h
@@ -89,6 +89,11 @@ typedef struct{
   /// RACH indication list
   nfapi_rach_indication_body_t rach_ind;
 
+#ifdef Rel14
+  /// RACH indication list for BR UEs
+  nfapi_rach_indication_body_t rach_ind_br;
+#endif
+
   /// SRS indication list
   nfapi_srs_indication_body_t srs_ind;
 
diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c
index 3ba16a32a8..a95342e8b6 100644
--- a/targets/RT/USER/lte-enb.c
+++ b/targets/RT/USER/lte-enb.c
@@ -144,6 +144,9 @@ void init_eNB(int,int);
 void stop_eNB(int nb_inst);
 
 void wakeup_prach_eNB(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe);
+#ifdef Rel14
+void wakeup_prach_eNB_br(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe);
+#endif
 
 static inline int rxtx(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, char *thread_name) {
 
@@ -153,8 +156,12 @@ static inline int rxtx(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, char *thread_nam
   // Common RX procedures subframe n
 
   // if this is IF5 or 3GPP_eNB
-  if (eNB->RU_list[0]->function < NGFI_RAU_IF4p5) wakeup_prach_eNB(eNB,NULL,proc->frame_rx,proc->subframe_rx);
-
+  if (eNB->RU_list[0]->function < NGFI_RAU_IF4p5) {
+    wakeup_prach_eNB(eNB,NULL,proc->frame_rx,proc->subframe_rx);
+#ifdef Rel14
+    wakeup_prach_eNB_br(eNB,NULL,proc->frame_rx,proc->subframe_rx);
+#endif
+  }
   // UE-specific RX processing for subframe n
   phy_procedures_eNB_uespec_RX(eNB, proc, no_relay );
 
@@ -432,6 +439,67 @@ void wakeup_prach_eNB(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) {
 
 }
 
+#ifdef Rel14
+void wakeup_prach_eNB_br(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) {
+
+  eNB_proc_t *proc = &eNB->proc;
+  LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
+  int i;
+
+  if (ru!=NULL) {
+    pthread_mutex_lock(&proc->mutex_RU_PRACH_br);
+    for (i=0;i<eNB->num_RU;i++) {
+      if (ru == eNB->RU_list[i]) {
+	LOG_I(PHY,"frame %d, subframe %d: RU %d for eNB %d signals PRACH BR (mask %x, num_RU %d)\n",frame,subframe,i,eNB->Mod_id,proc->RU_mask_prach_br,eNB->num_RU);
+	if ((proc->RU_mask_prach_br&(1<<i)) > 0)
+	  LOG_E(PHY,"eNB %d frame %d, subframe %d : previous information (PRACH BR) from RU %d (num_RU %d, mask %x) has not been served yet!\n",
+		eNB->Mod_id,frame,subframe,ru->idx,eNB->num_RU,proc->RU_mask_prach_br);
+	proc->RU_mask_prach_br |= (1<<i);
+      }
+    }
+    if (proc->RU_mask_prach_br != (1<<eNB->num_RU)-1) {  // not all RUs have provided their information so return
+      pthread_mutex_unlock(&proc->mutex_RU_PRACH_br);
+      return(0);
+    }
+    else { // all RUs have provided their information so continue on and wakeup eNB processing
+      proc->RU_mask_prach_br = 0;
+      pthread_mutex_unlock(&proc->mutex_RU_PRACH_br);
+    }
+  }
+    
+  // check if we have to detect PRACH first
+  if (is_prach_subframe(fp,frame,subframe)>0) { 
+    LOG_D(PHY,"Triggering prach br processing, frame %d, subframe %d\n",frame,subframe);
+    if (proc->instance_cnt_prach_br == 0) {
+      LOG_W(PHY,"[eNB] Frame %d Subframe %d, dropping PRACH BR\n", frame,subframe);
+      return;
+    }
+    
+    // wake up thread for PRACH RX
+    if (pthread_mutex_lock(&proc->mutex_prach_br) != 0) {
+      LOG_E( PHY, "[eNB] ERROR pthread_mutex_lock for eNB PRACH thread %d (IC %d)\n", proc->thread_index, proc->instance_cnt_prach_br);
+      exit_fun( "error locking mutex_prach" );
+      return;
+    }
+    
+    ++proc->instance_cnt_prach_br;
+    // set timing for prach thread
+    proc->frame_prach_br = frame;
+    proc->subframe_prach_br = subframe;
+    
+    // the thread can now be woken up
+    if (pthread_cond_signal(&proc->cond_prach_br) != 0) {
+      LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB PRACH BR thread %d\n", proc->thread_index);
+      exit_fun( "ERROR pthread_cond_signal" );
+      return;
+    }
+    
+    pthread_mutex_unlock( &proc->mutex_prach_br );
+  }
+
+}
+#endif
+
 /*!
  * \brief The prach receive thread of eNB.
  * \param param is a \ref eNB_proc_t structure which contains the info what to process.
@@ -457,7 +525,11 @@ static void* eNB_thread_prach( void* param ) {
     if (wait_on_condition(&proc->mutex_prach,&proc->cond_prach,&proc->instance_cnt_prach,"eNB_prach_thread") < 0) break;
 
     LOG_D(PHY,"Running eNB prach procedures\n");
-    prach_procedures(eNB);
+    prach_procedures(eNB
+#ifdef Rel14
+		     ,0
+#endif
+		     );
     
     if (release_thread(&proc->mutex_prach,&proc->instance_cnt_prach,"eNB_prach_thread") < 0) break;
   }
@@ -468,6 +540,44 @@ static void* eNB_thread_prach( void* param ) {
   return &eNB_thread_prach_status;
 }
 
+#ifdef Rel14
+/*!
+ * \brief The prach receive thread of eNB for BL/CE UEs.
+ * \param param is a \ref eNB_proc_t structure which contains the info what to process.
+ * \returns a pointer to an int. The storage is not on the heap and must not be freed.
+ */
+static void* eNB_thread_prach_br( void* param ) {
+  static int eNB_thread_prach_status;
+
+
+  PHY_VARS_eNB *eNB= (PHY_VARS_eNB *)param;
+  eNB_proc_t *proc = &eNB->proc;
+
+  // set default return value
+  eNB_thread_prach_status = 0;
+
+  thread_top_init("eNB_thread_prach_br",1,500000L,1000000L,20000000L);
+
+  while (!oai_exit) {
+    
+    if (oai_exit) break;
+    
+
+    if (wait_on_condition(&proc->mutex_prach_br,&proc->cond_prach_br,&proc->instance_cnt_prach_br,"eNB_prach_thread_br") < 0) break;
+
+    LOG_D(PHY,"Running eNB prach procedures for BL/CE UEs\n");
+    prach_procedures(eNB,1);
+    
+    if (release_thread(&proc->mutex_prach_br,&proc->instance_cnt_prach_br,"eNB_prach_thread_br") < 0) break;
+  }
+
+  LOG_I(PHY, "Exiting eNB thread PRACH BR\n");
+
+  eNB_thread_prach_status = 0;
+  return &eNB_thread_prach_status;
+}
+
+#endif
 
 
 extern void init_fep_thread(PHY_VARS_eNB *, pthread_attr_t *);
@@ -482,6 +592,9 @@ void init_eNB_proc(int inst) {
   eNB_proc_t *proc;
   eNB_rxtx_proc_t *proc_rxtx;
   pthread_attr_t *attr0=NULL,*attr1=NULL,*attr_FH=NULL,*attr_prach=NULL,*attr_asynch=NULL,*attr_single=NULL,*attr_fep=NULL,*attr_td=NULL,*attr_te=NULL,*attr_synch=NULL;
+#ifdef Rel14
+  pthread_attr_t *attr_prach_br=NULL;
+#endif
 
   for (CC_id=0; CC_id<RC.nb_CC[inst]; CC_id++) {
     eNB = RC.eNB[inst][CC_id];
@@ -523,10 +636,22 @@ void init_eNB_proc(int inst) {
     pthread_attr_init( &proc->attr_te);
     pthread_attr_init( &proc_rxtx[0].attr_rxtx);
     pthread_attr_init( &proc_rxtx[1].attr_rxtx);
+#ifdef Rel14
+    proc->instance_cnt_prach_br    = -1;
+    proc->RU_mask_prach_br=0;
+    pthread_mutex_init( &proc->mutex_prach_br, NULL);
+    pthread_mutex_init( &proc->mutex_RU_PRACH_br,NULL);
+    pthread_cond_init( &proc->cond_prach_br, NULL);
+    pthread_attr_init( &proc->attr_prach_br);
+#endif
 #ifndef DEADLINE_SCHEDULER
     attr0       = &proc_rxtx[0].attr_rxtx;
     attr1       = &proc_rxtx[1].attr_rxtx;
     attr_prach  = &proc->attr_prach;
+#ifdef Rel14
+    attr_prach_br  = &proc->attr_prach_br;
+#endif
+
     attr_asynch = &proc->attr_asynch_rxtx;
     attr_single = &proc->attr_single;
     attr_td     = &proc->attr_td;
@@ -538,7 +663,9 @@ void init_eNB_proc(int inst) {
       pthread_create( &proc_rxtx[1].pthread_rxtx, attr1, eNB_thread_rxtx, &proc_rxtx[1] );
     }
     pthread_create( &proc->pthread_prach, attr_prach, eNB_thread_prach, eNB );
-
+#ifdef Rel14
+    pthread_create( &proc->pthread_prach_br, attr_prach_br, eNB_thread_prach_br, eNB );
+#endif
     char name[16];
     if (eNB->single_thread_flag==0) {
       snprintf( name, sizeof(name), "RXTX0 %d", i );
@@ -601,10 +728,18 @@ void kill_eNB_proc(int inst) {
     pthread_cond_signal( &proc_rxtx[0].cond_rxtx );    
     pthread_cond_signal( &proc_rxtx[1].cond_rxtx );
     pthread_cond_signal( &proc->cond_prach );
+
     pthread_cond_broadcast(&sync_phy_proc.cond_phy_proc_tx);
     pthread_join( proc->pthread_prach, (void**)&status );    
+
     pthread_mutex_destroy( &proc->mutex_prach );
-    pthread_cond_destroy( &proc->cond_prach );         
+    pthread_cond_destroy( &proc->cond_prach );
+#ifdef Rel14
+    pthread_cond_signal( &proc->cond_prach_br );
+    pthread_join( proc->pthread_prach_br, (void**)&status );    
+    pthread_mutex_destroy( &proc->mutex_prach_br );
+    pthread_cond_destroy( &proc->cond_prach_br );
+#endif         
     pthread_mutex_destroy(&eNB->UL_INFO_mutex);
     int i;
     for (i=0;i<2;i++) {
@@ -756,11 +891,13 @@ void init_eNB_afterRU() {
 
     AssertFatal(RC.ru[ru_id]!=NULL,"ru_id %d is null\n",ru_id);
     
-    RC.ru[ru_id]->wakeup_rxtx      = wakeup_rxtx;
-    RC.ru[ru_id]->wakeup_prach_eNB = wakeup_prach_eNB;
-    RC.ru[ru_id]->eNB_top          = eNB_top;
+    RC.ru[ru_id]->wakeup_rxtx         = wakeup_rxtx;
+    RC.ru[ru_id]->wakeup_prach_eNB    = wakeup_prach_eNB;
+    RC.ru[ru_id]->wakeup_prach_eNB_br = wakeup_prach_eNB_br;
+    RC.ru[ru_id]->eNB_top             = eNB_top;
   }
 }
+
 void init_eNB(int single_thread_flag,int wait_for_sync) {
   
   int CC_id;
diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c
index 6ee6633b3e..2d72b1d745 100644
--- a/targets/RT/USER/lte-ru.c
+++ b/targets/RT/USER/lte-ru.c
@@ -479,15 +479,19 @@ void fh_if4p5_south_asynch_in(RU_t *ru,int *frame,int *subframe) {
 
   uint16_t packet_type;
   uint32_t symbol_number,symbol_mask,symbol_mask_full,prach_rx;
-
+  uint32_t got_prach_info=0;
 
   symbol_number = 0;
-  symbol_mask = 0;
-  symbol_mask_full = (1<<fp->symbols_per_tti)-1;
-  prach_rx = 0;
+  symbol_mask   = (1<<fp->symbols_per_tti)-1;
+  prach_rx      = 0;
 
   do {   // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!!
     recv_IF4p5(ru, &proc->frame_rx, &proc->subframe_rx, &packet_type, &symbol_number);
+    // grab first prach information for this new subframe
+    if (got_prach_info==0) {
+      prach_rx       = is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx);
+      got_prach_info = 1;
+    }
     if (proc->first_rx != 0) {
       *frame = proc->frame_rx;
       *subframe = proc->subframe_rx;
@@ -503,13 +507,15 @@ void fh_if4p5_south_asynch_in(RU_t *ru,int *frame,int *subframe) {
 	exit_fun("Exiting");
       }
     }
-    if (packet_type == IF4p5_PULFFT) {
-      symbol_mask = symbol_mask | (1<<symbol_number);
-      prach_rx = (is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx)>0) ? 1 : 0;                            
-    } else if (packet_type == IF4p5_PRACH) {
-      prach_rx = 0;
-    }
-  } while( (symbol_mask != symbol_mask_full) || (prach_rx == 1));    
+    if      (packet_type == IF4p5_PULFFT)       symbol_mask &= (~(1<<symbol_number));
+    else if (packet_type == IF4p5_PRACH)        prach_rx    &= (~0x1);
+#ifdef Rel14
+    else if (packet_type == IF4p5_PRACH_BR_CE0) prach_rx    &= (~0x2);
+    else if (packet_type == IF4p5_PRACH_BR_CE1) prach_rx    &= (~0x4);
+    else if (packet_type == IF4p5_PRACH_BR_CE2) prach_rx    &= (~0x8);
+    else if (packet_type == IF4p5_PRACH_BR_CE3) prach_rx    &= (~0x10);
+#endif
+  } while( (symbol_mask > 0) || (prach_rx >0));   // haven't received all PUSCH symbols and PRACH information 
 } 
 
 
@@ -895,19 +901,59 @@ static void* ru_thread_prach( void* param ) {
     VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 1 );      
     rx_prach(NULL,
 	     ru,
+	     NULL,
              NULL,
              NULL,
              proc->frame_prach,
-             0);
+             0
+#ifdef Rel14
+	     ,0
+#endif
+	     );
     VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 0 );      
     if (release_thread(&proc->mutex_prach,&proc->instance_cnt_prach,"ru_prach_thread") < 0) break;
   }
 
-  printf( "Exiting RU thread PRACH\n");
+  LOG_I(PHY, "Exiting RU thread PRACH\n");
+
+  ru_thread_prach_status = 0;
+  return &ru_thread_prach_status;
+}
+
+#ifdef Rel14
+static void* ru_thread_prach_br( void* param ) {
+
+  static int ru_thread_prach_status;
+
+  RU_t *ru        = (RU_t*)param;
+  RU_proc_t *proc = (RU_proc_t*)&ru->proc;
+
+  // set default return value
+  ru_thread_prach_status = 0;
+
+  thread_top_init("ru_thread_prach_br",1,500000L,1000000L,20000000L);
+
+  while (!oai_exit) {
+    
+    if (oai_exit) break;
+    if (wait_on_condition(&proc->mutex_prach_br,&proc->cond_prach_br,&proc->instance_cnt_prach_br,"ru_prach_thread_br") < 0) break;
+    rx_prach(NULL,
+	     ru,
+	     NULL,
+             NULL,
+             NULL,
+             proc->frame_prach_br,
+             0,
+	     1);
+    if (release_thread(&proc->mutex_prach_br,&proc->instance_cnt_prach_br,"ru_prach_thread_br") < 0) break;
+  }
+
+  LOG_I(PHY, "Exiting RU thread PRACH BR\n");
 
   ru_thread_prach_status = 0;
   return &ru_thread_prach_status;
 }
+#endif
 
 int wakeup_synch(RU_t *ru){
 
@@ -1058,6 +1104,35 @@ static inline int wakeup_prach_ru(RU_t *ru) {
   return(0);
 }
 
+#ifdef Rel14
+static inline int wakeup_prach_ru_br(RU_t *ru) {
+
+  struct timespec wait;
+  
+  wait.tv_sec=0;
+  wait.tv_nsec=5000000L;
+
+  if (pthread_mutex_timedlock(&ru->proc.mutex_prach_br,&wait) !=0) {
+    LOG_E( PHY, "[RU] ERROR pthread_mutex_lock for RU prach thread BR (IC %d)\n", ru->proc.instance_cnt_prach_br);
+    exit_fun( "error locking mutex_rxtx" );
+    return(-1);
+  }
+  if (ru->proc.instance_cnt_prach_br==-1) {
+    ++ru->proc.instance_cnt_prach_br;
+    ru->proc.frame_prach_br    = ru->proc.frame_rx;
+    ru->proc.subframe_prach_br = ru->proc.subframe_rx;
+
+    LOG_D(PHY,"RU %d: waking up PRACH thread\n",ru->idx);
+    // the thread can now be woken up
+    AssertFatal(pthread_cond_signal(&ru->proc.cond_prach_br) == 0, "ERROR pthread_cond_signal for RU prach thread BR\n");
+  }
+  else LOG_W(PHY,"RU prach thread busy, skipping\n");
+  pthread_mutex_unlock( &ru->proc.mutex_prach_br );
+
+  return(0);
+}
+#endif
+
 static void* ru_thread( void* param ) {
 
   static int ru_thread_status;
@@ -1150,10 +1225,10 @@ static void* ru_thread( void* param ) {
 	  is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx),
 	  proc->frame_rx,proc->subframe_rx);
  
-    if ((ru->do_prach>0) && (is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx)>0))
-      wakeup_prach_ru(ru);
-
-
+    if ((ru->do_prach>0) && (is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx)==1)) wakeup_prach_ru(ru);
+#ifdef Rel14
+    else if ((ru->do_prach>0) && (is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx)>1)) wakeup_prach_ru_br(ru);
+#endif
 
     // adjust for timing offset between RU
     if (ru->idx!=0) proc->frame_tx = (proc->frame_tx+proc->frame_offset)&1023;
@@ -1298,7 +1373,9 @@ void init_RU_proc(RU_t *ru) {
   RU_proc_t *proc;
   pthread_attr_t *attr_FH=NULL,*attr_prach=NULL,*attr_asynch=NULL,*attr_synch=NULL;
   //pthread_attr_t *attr_fep=NULL;
-
+#ifdef Rel14
+  pthread_attr_t *attr_prach_br=NULL;
+#endif
   char name[100];
 
 #ifndef OCP_FRAMEWORK
@@ -1335,32 +1412,37 @@ void init_RU_proc(RU_t *ru) {
   pthread_attr_init( &proc->attr_synch);
   pthread_attr_init( &proc->attr_asynch_rxtx);
   pthread_attr_init( &proc->attr_fep);
-  
+
+#ifdef Rel14
+  proc->instance_cnt_prach_br       = -1;
+  pthread_mutex_init( &proc->mutex_prach_br, NULL);
+  pthread_cond_init( &proc->cond_prach_br, NULL);
+  pthread_attr_init( &proc->attr_prach_br);
+#endif  
   
 #ifndef DEADLINE_SCHEDULER
-  attr_FH     = &proc->attr_FH;
-  attr_prach  = &proc->attr_prach;
-  attr_synch  = &proc->attr_synch;
-  attr_asynch = &proc->attr_asynch_rxtx;
-  //  attr_fep    = &proc->attr_fep;
+  attr_FH        = &proc->attr_FH;
+  attr_prach     = &proc->attr_prach;
+  attr_synch     = &proc->attr_synch;
+  attr_asynch    = &proc->attr_asynch_rxtx;
+#ifdef Rel14
+  attr_prach_br  = &proc->attr_prach_br;
+#endif
 #endif
   
   pthread_create( &proc->pthread_FH, attr_FH, ru_thread, (void*)ru );
 
   if (ru->function == NGFI_RRU_IF4p5) {
     pthread_create( &proc->pthread_prach, attr_prach, ru_thread_prach, (void*)ru );
-  
+#ifdef Rel14  
+    pthread_create( &proc->pthread_prach_br, attr_prach_br, ru_thread_prach_br, (void*)ru );
+#endif
     if (ru->is_slave == 1) pthread_create( &proc->pthread_synch, attr_synch, ru_thread_synch, (void*)ru);
     
     
     if ((ru->if_timing == synch_to_other) ||
 	(ru->function == NGFI_RRU_IF5) ||
-	(ru->function == NGFI_RRU_IF4p5))
-      
-      
-      pthread_create( &proc->pthread_asynch_rxtx, attr_asynch, ru_thread_asynch_rxtx, (void*)ru );
-    
-    
+	(ru->function == NGFI_RRU_IF4p5)) pthread_create( &proc->pthread_asynch_rxtx, attr_asynch, ru_thread_asynch_rxtx, (void*)ru );
     
     snprintf( name, sizeof(name), "ru_thread_FH %d", ru->idx );
     pthread_setname_np( proc->pthread_FH, name );
@@ -1563,6 +1645,7 @@ void configure_ru(int idx,
   RRU_config_t       *config       = (RRU_config_t *)arg;
   RRU_capabilities_t *capabilities = (RRU_capabilities_t*)arg;
   int ret;
+  int i;
 
   LOG_I(PHY, "Received capabilities from RRU %d\n",idx);
 
@@ -1588,6 +1671,13 @@ void configure_ru(int idx,
       LOG_I(PHY,"REMOTE_IF4p5: prach_FrequOffset %d, prach_ConfigIndex %d\n",
 	    config->prach_FreqOffset[0],config->prach_ConfigIndex[0]);
 
+#ifdef Rel14
+      for (i=0;i<4;i++) {
+	config->emtc_prach_CElevel_enable[0][i]  = ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[i];
+	config->emtc_prach_FreqOffset[0][i]      = ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[i];
+	config->emtc_prach_ConfigIndex[0][i]     = ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[i];
+      }
+#endif
     }
     // take antenna capabilities of RRU
     ru->nb_tx                      = capabilities->nb_tx[0];
@@ -1621,6 +1711,13 @@ void configure_rru(int idx,
 	  config->prach_FreqOffset[0],config->prach_ConfigIndex[0]);
     ru->frame_parms.prach_config_common.prach_ConfigInfo.prach_FreqOffset  = config->prach_FreqOffset[0]; 
     ru->frame_parms.prach_config_common.prach_ConfigInfo.prach_ConfigIndex = config->prach_ConfigIndex[0]; 
+#ifdef Rel14
+    for (int i=0;i<4;i++) {
+      ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[i] = config->emtc_prach_CElevel_enable[0][i];
+      ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[i]     = config->emtc_prach_FreqOffset[0][i];
+      ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[i]    = config->emtc_prach_ConfigIndex[0][i];
+    }
+#endif
   }
   
   init_frame_parms(&ru->frame_parms,1);
-- 
GitLab