diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index 50acfc4ce6c3a5524303050c1970b1da1e9fb6ff..f2a5163219851b5f39b32d68281be717e9ce1906 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -2115,6 +2115,40 @@ target_link_libraries (lte-softmodem
   NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB
   -Wl,--end-group z dl)
 
+
+add_executable(simple-softmodem
+  ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c
+  ${OPENAIR_DIR}/executables/simple_main.c
+  ${OPENAIR_TARGETS}/RT/USER/lte-softmodem.c
+  ${OPENAIR_TARGETS}/RT/USER/lte-softmodem-common.c
+  ${OPENAIR2_DIR}/ENB_APP/NB_IoT_interface.c
+  ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c
+  ${OPENAIR_TARGETS}/COMMON/create_tasks.c
+  ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c
+  ${OPENAIR2_DIR}/RRC/NAS/nas_config.c
+  ${OPENAIR2_DIR}/RRC/NAS/rb_config.c
+  ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c
+  ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/multicast_link.c
+  ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/socket.c
+  ${OPENAIR3_DIR}/NAS/UE/nas_ue_task.c
+  ${OPENAIR_DIR}/common/utils/utils.c
+  ${OPENAIR_DIR}/common/utils/system.c
+  ${GTPU_need_ITTI}
+  ${XFORMSINTERFACE_SOURCE}
+  ${T_SOURCE}
+  ${CONFIG_SOURCES}
+  ${SHLIB_LOADER_SOURCES}
+  )
+add_dependencies(simple-softmodem rrc_flag s1ap_flag x2_flag)
+
+target_link_libraries (simple-softmodem
+  -Wl,--start-group
+  RRC_LIB S1AP_LIB S1AP_ENB F1AP_LIB F1AP X2AP_LIB X2AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB SCHED_RU_LIB PHY_COMMON PHY PHY_RU LFDS L2
+  ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} ${FSPT_MSG_LIB} ${PROTO_AGENT_LIB} LFDS7
+  NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB
+  -Wl,--end-group z dl)
+target_link_libraries (simple-softmodem ${LIBXML2_LIBRARIES} pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${PROTOBUF_LIB}  ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES} ${LIB_LMS_LIBRARIES} ${T_LIB})
+
 add_executable(cu_test
   ${OPENAIR2_DIR}/LAYER2/PROTO_AGENT/cu_test.c
   ${OPENAIR2_DIR}/LAYER2/PROTO_AGENT/proto_agent_handler.c
diff --git a/executables/dl_fs6.c b/executables/dl_fs6.c
index 079f368f1d9d5d11fc4d3dafca6314839289fd27..c583a4bc451aa9354054782b82073fef31b95e97 100644
--- a/executables/dl_fs6.c
+++ b/executables/dl_fs6.c
@@ -8,7 +8,6 @@ void pdsch_procedures(PHY_VARS_eNB *eNB,
                       LTE_eNB_DLSCH_t *dlsch1,
                       LTE_eNB_UE_stats *ue_stats,
                       int ra_flag) {
-  
   int frame=proc->frame_tx;
   int subframe=proc->subframe_tx;
   LTE_DL_eNB_HARQ_t *dlsch_harq=dlsch->harq_processes[harq_pid];
@@ -16,24 +15,22 @@ void pdsch_procedures(PHY_VARS_eNB *eNB,
 
   // 36-212
   if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { // monolthic OR PNF - do not need turbo encoding on VNF
-
     // Replace dlsch_encoding
-    // data is in 
+    // data is in
     // dlsch->harq_processes[harq_pid]->e
     feedDlschBuffers(eNB,
-                       dlsch_harq->pdu,
-                       dlsch_harq->pdsch_start,
-                       dlsch,
-                       frame,
-                       subframe,
-                       &eNB->dlsch_rate_matching_stats,
-                       &eNB->dlsch_turbo_encoding_stats,
-                       &eNB->dlsch_turbo_encoding_waiting_stats,
-                       &eNB->dlsch_turbo_encoding_main_stats,
-                       &eNB->dlsch_turbo_encoding_wakeup_stats0,
-                       &eNB->dlsch_turbo_encoding_wakeup_stats1,
-                       &eNB->dlsch_interleaving_stats);
-
+                     dlsch_harq->pdu,
+                     dlsch_harq->pdsch_start,
+                     dlsch,
+                     frame,
+                     subframe,
+                     &eNB->dlsch_rate_matching_stats,
+                     &eNB->dlsch_turbo_encoding_stats,
+                     &eNB->dlsch_turbo_encoding_waiting_stats,
+                     &eNB->dlsch_turbo_encoding_main_stats,
+                     &eNB->dlsch_turbo_encoding_wakeup_stats0,
+                     &eNB->dlsch_turbo_encoding_wakeup_stats1,
+                     &eNB->dlsch_interleaving_stats);
     // 36-211
     dlsch_scrambling(fp,
                      0,
@@ -65,7 +62,6 @@ void pdsch_procedures(PHY_VARS_eNB *eNB,
 }
 
 phy_procedures_eNB_TX_fs6() {
-
   receiveSubFrame();
 
   // We got
@@ -74,10 +70,10 @@ phy_procedures_eNB_TX_fs6() {
 
   for (aa = 0; aa < fp->nb_antenna_ports_eNB; aa++) {
     memset (&eNB->common_vars.txdataF[aa][subframe * fp->ofdm_symbol_size * fp->symbols_per_tti],
-	    0,
-	    fp->ofdm_symbol_size * (fp->symbols_per_tti) * sizeof (int32_t));
+            0,
+            fp->ofdm_symbol_size * (fp->symbols_per_tti) * sizeof (int32_t));
   }
-  
+
   if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) {
     if (is_pmch_subframe(frame,subframe,fp)) {
       pmch_procedures(eNB,proc);
@@ -88,59 +84,60 @@ phy_procedures_eNB_TX_fs6() {
   }
 
   if (ul_subframe < 10)if (ul_subframe < 10) { // This means that there is a potential UL subframe that will be scheduled here
-    for (i=0; i<NUMBER_OF_UE_MAX; i++) {
+      for (i=0; i<NUMBER_OF_UE_MAX; i++) {
 #if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
 
-      if (eNB->ulsch[i] && eNB->ulsch[i]->ue_type >0) harq_pid = 0;
-      else 
+        if (eNB->ulsch[i] && eNB->ulsch[i]->ue_type >0) harq_pid = 0;
+        else
 #endif
-        harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe);
-
-      if (eNB->ulsch[i]) {
-        ulsch_harq = eNB->ulsch[i]->harq_processes[harq_pid];
-        /* Store first_rb and n_DMRS for correct PHICH generation below.
-         * For PHICH generation we need "old" values of last scheduling
-         * for this HARQ process. 'generate_eNB_dlsch_params' below will
-         * overwrite first_rb and n_DMRS and 'generate_phich_top', done
-         * after 'generate_eNB_dlsch_params', would use the "new" values
-         * instead of the "old" ones.
-         *
-         * This has been tested for FDD only, may be wrong for TDD.
-         *
-         * TODO: maybe we should restructure the code to be sure it
-         *       is done correctly. The main concern is if the code
-         *       changes and first_rb and n_DMRS are modified before
-         *       we reach here, then the PHICH processing will be wrong,
-         *       using wrong first_rb and n_DMRS values to compute
-         *       ngroup_PHICH and nseq_PHICH.
-         *
-         * TODO: check if that works with TDD.
-         */
-        ulsch_harq->previous_first_rb = ulsch_harq->first_rb;
-        ulsch_harq->previous_n_DMRS = ulsch_harq->n_DMRS;
+          harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe);
+
+        if (eNB->ulsch[i]) {
+          ulsch_harq = eNB->ulsch[i]->harq_processes[harq_pid];
+          /* Store first_rb and n_DMRS for correct PHICH generation below.
+           * For PHICH generation we need "old" values of last scheduling
+           * for this HARQ process. 'generate_eNB_dlsch_params' below will
+           * overwrite first_rb and n_DMRS and 'generate_phich_top', done
+           * after 'generate_eNB_dlsch_params', would use the "new" values
+           * instead of the "old" ones.
+           *
+           * This has been tested for FDD only, may be wrong for TDD.
+           *
+           * TODO: maybe we should restructure the code to be sure it
+           *       is done correctly. The main concern is if the code
+           *       changes and first_rb and n_DMRS are modified before
+           *       we reach here, then the PHICH processing will be wrong,
+           *       using wrong first_rb and n_DMRS values to compute
+           *       ngroup_PHICH and nseq_PHICH.
+           *
+           * TODO: check if that works with TDD.
+           */
+          ulsch_harq->previous_first_rb = ulsch_harq->first_rb;
+          ulsch_harq->previous_n_DMRS = ulsch_harq->n_DMRS;
+        }
       }
     }
-  }
 
   num_pdcch_symbols = eNB->pdcch_vars[subframe&1].num_pdcch_symbols;
   num_dci           = eNB->pdcch_vars[subframe&1].num_dci;
+
   if (num_dci > 0)
     if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) {
       generate_dci_top(num_pdcch_symbols,
-		       num_dci,
-		       &eNB->pdcch_vars[subframe&1].dci_alloc[0],
-		       0,
-		       AMP,
-		       fp,
-		       eNB->common_vars.txdataF,
-		       subframe);
+                       num_dci,
+                       &eNB->pdcch_vars[subframe&1].dci_alloc[0],
+                       0,
+                       AMP,
+                       fp,
+                       eNB->common_vars.txdataF,
+                       subframe);
       num_mdci = eNB->mpdcch_vars[subframe &1].num_dci;
-      
+
       if (num_mdci > 0) {
-	generate_mdci_top (eNB, frame, subframe, AMP, eNB->common_vars.txdataF);
+        generate_mdci_top (eNB, frame, subframe, AMP, eNB->common_vars.txdataF);
       }
     }
-  
+
   // Now scan UE specific DLSCH
   LTE_eNB_DLSCH_t *dlsch0,*dlsch1;
 
@@ -158,16 +155,16 @@ phy_procedures_eNB_TX_fs6() {
       if (harq_pid>=8) {
         if (dlsch0->ue_type==0)
           LOG_E(PHY,"harq_pid:%d corrupt must be 0-7 UE_id:%d frame:%d subframe:%d rnti:%x \n",
-		harq_pid,UE_id,frame,subframe,dlsch0->rnti);
+                harq_pid,UE_id,frame,subframe,dlsch0->rnti);
       } else {
         // generate pdsch
         pdsch_procedures_fs6(eNB,
-			     proc,
-			     harq_pid,
-			     dlsch0,
-			     dlsch1,
-			     &eNB->UE_stats[(uint32_t)UE_id],
-			     0);
+                             proc,
+                             harq_pid,
+                             dlsch0,
+                             dlsch1,
+                             &eNB->UE_stats[(uint32_t)UE_id],
+                             0);
       }
     } else if ((dlsch0)&&(dlsch0->rnti>0)&&
                (dlsch0->active == 0)
@@ -176,10 +173,10 @@ phy_procedures_eNB_TX_fs6() {
       dlsch0->subframe_tx[subframe]=0;
     }
   }
+
   generate_phich_top(eNB,
                      proc,
                      AMP);
-
 }
 
 DL_thread_fs6() {
@@ -194,5 +191,4 @@ DL_thread_fs6() {
 
 DL_thread_frequency() {
   frequency_t header;
-  
-  full_read(&header, 
+  full_read(&header,
\ No newline at end of file
diff --git a/executables/simple_main.c b/executables/simple_main.c
new file mode 100644
index 0000000000000000000000000000000000000000..04ab39e7a7ac3a9f31d6c03e2a1e072a01e4b106
--- /dev/null
+++ b/executables/simple_main.c
@@ -0,0 +1,1121 @@
+/*
+ * Author: Laurent Thomas
+ * Copyright: Open Cells Project company
+ */
+
+#include <common/utils/LOG/log.h>
+static int DEFBANDS[] = {7};
+static int DEFENBS[] = {0};
+#include <common/config/config_userapi.h>
+#include <targets/RT/USER/lte-softmodem.h>
+#include <openair1/PHY/defs_eNB.h>
+#include <openair1/PHY/phy_extern.h>
+#include <nfapi/oai_integration/vendor_ext.h>
+#include <openair1/SCHED/fapi_l1.h>
+#include <openair1/PHY/INIT/phy_init.h>
+#include <openair2/LAYER2/MAC/mac_extern.h>
+extern uint16_t sf_ahead;
+extern void oai_subframe_ind(uint16_t sfn, uint16_t sf);
+extern void fep_full(RU_t *ru);
+extern void feptx_ofdm(RU_t *ru);
+extern void feptx_prec(RU_t *ru);
+extern void  phy_init_RU(RU_t *);
+
+static void *ru_thread( void *param );
+void kill_RU_proc(RU_t *ru) {
+}
+void kill_eNB_proc(int inst) {
+}
+void free_transport(PHY_VARS_eNB *eNB) {
+}
+void reset_opp_meas(void) {
+}
+
+void init_eNB_proc(int inst) {
+  /*int i=0;*/
+  int CC_id;
+  PHY_VARS_eNB *eNB;
+  L1_proc_t *proc;
+  L1_rxtx_proc_t *L1_proc, *L1_proc_tx;
+
+  for (CC_id=0; CC_id<RC.nb_CC[inst]; CC_id++) {
+    eNB = RC.eNB[inst][CC_id];
+    proc = &eNB->proc;
+    L1_proc                        = &proc->L1_proc;
+    L1_proc_tx                     = &proc->L1_proc_tx;
+    L1_proc->instance_cnt          = -1;
+    L1_proc_tx->instance_cnt       = -1;
+    L1_proc->instance_cnt_RUs      = 0;
+    L1_proc_tx->instance_cnt_RUs   = 0;
+    proc->instance_cnt_prach       = -1;
+    proc->instance_cnt_asynch_rxtx = -1;
+    proc->instance_cnt_synch       = -1;
+    proc->CC_id                    = CC_id;
+    proc->first_rx                 =1;
+    proc->first_tx                 =1;
+    proc->RU_mask_tx               = (1<<eNB->num_RU)-1;
+    proc->RU_mask                  =0;
+    proc->RU_mask_prach            =0;
+    pthread_mutex_init( &eNB->UL_INFO_mutex, NULL);
+    pthread_mutex_init( &L1_proc->mutex, NULL);
+    pthread_mutex_init( &L1_proc_tx->mutex, NULL);
+    pthread_cond_init( &L1_proc->cond, NULL);
+    pthread_cond_init( &L1_proc_tx->cond, NULL);
+    pthread_mutex_init( &L1_proc->mutex_RUs, NULL);
+    pthread_mutex_init( &L1_proc_tx->mutex_RUs, NULL);
+    pthread_cond_init( &L1_proc->cond_RUs, NULL);
+    pthread_cond_init( &L1_proc_tx->cond_RUs, NULL);
+    pthread_mutex_init( &proc->mutex_prach, NULL);
+    pthread_mutex_init( &proc->mutex_asynch_rxtx, NULL);
+    pthread_mutex_init( &proc->mutex_RU,NULL);
+    pthread_mutex_init( &proc->mutex_RU_tx,NULL);
+    pthread_mutex_init( &proc->mutex_RU_PRACH,NULL);
+    pthread_cond_init( &proc->cond_prach, NULL);
+    pthread_cond_init( &proc->cond_asynch_rxtx, NULL);
+    pthread_attr_init( &proc->attr_prach);
+    pthread_attr_init( &proc->attr_asynch_rxtx);
+    pthread_attr_init( &L1_proc->attr);
+    pthread_attr_init( &L1_proc_tx->attr);
+    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);
+  }
+
+  //for multiple CCs: setup master and slaves
+  /*
+     for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
+     eNB = PHY_vars_eNB_g[inst][CC_id];
+
+     if (eNB->node_timing == synch_to_ext_device) { //master
+     eNB->proc.num_slaves = MAX_NUM_CCs-1;
+     eNB->proc.slave_proc = (L1_proc_t**)malloc(eNB->proc.num_slaves*sizeof(L1_proc_t*));
+
+     for (i=0; i< eNB->proc.num_slaves; i++) {
+     if (i < CC_id)  eNB->proc.slave_proc[i] = &(PHY_vars_eNB_g[inst][i]->proc);
+     if (i >= CC_id)  eNB->proc.slave_proc[i] = &(PHY_vars_eNB_g[inst][i+1]->proc);
+     }
+     }
+     }
+  */
+}
+
+void init_RU_proc(RU_t *ru) {
+  int i=0;
+  RU_proc_t *proc;
+  pthread_attr_t *attr_FH=NULL;
+  //pthread_attr_t *attr_fep=NULL;
+  proc = &ru->proc;
+  memset((void *)proc,0,sizeof(RU_proc_t));
+  proc->ru = ru;
+  proc->instance_cnt_prach       = -1;
+  proc->instance_cnt_synch       = -1;
+  proc->instance_cnt_FH          = -1;
+  proc->instance_cnt_FH1         = -1;
+  proc->instance_cnt_emulateRF   = -1;
+  proc->instance_cnt_asynch_rxtx = -1;
+  proc->instance_cnt_eNBs        = -1;
+  proc->first_rx                 = 1;
+  proc->first_tx                 = 1;
+  proc->frame_offset             = 0;
+  proc->num_slaves               = 0;
+  proc->frame_tx_unwrap          = 0;
+
+  for (i=0; i<10; i++) proc->symbol_mask[i]=0;
+
+  pthread_mutex_init( &proc->mutex_prach, NULL);
+  pthread_mutex_init( &proc->mutex_asynch_rxtx, NULL);
+  pthread_mutex_init( &proc->mutex_synch,NULL);
+  pthread_mutex_init( &proc->mutex_FH,NULL);
+  pthread_mutex_init( &proc->mutex_FH1,NULL);
+  pthread_mutex_init( &proc->mutex_emulateRF,NULL);
+  pthread_mutex_init( &proc->mutex_eNBs, NULL);
+  pthread_cond_init( &proc->cond_prach, NULL);
+  pthread_cond_init( &proc->cond_FH, NULL);
+  pthread_cond_init( &proc->cond_FH1, NULL);
+  pthread_cond_init( &proc->cond_emulateRF, NULL);
+  pthread_cond_init( &proc->cond_asynch_rxtx, NULL);
+  pthread_cond_init( &proc->cond_synch,NULL);
+  pthread_cond_init( &proc->cond_eNBs, NULL);
+  pthread_attr_init( &proc->attr_FH);
+  pthread_attr_init( &proc->attr_FH1);
+  pthread_attr_init( &proc->attr_emulateRF);
+  pthread_attr_init( &proc->attr_prach);
+  pthread_attr_init( &proc->attr_synch);
+  pthread_attr_init( &proc->attr_asynch_rxtx);
+  pthread_attr_init( &proc->attr_fep);
+  proc->instance_cnt_prach_br       = -1;
+  pthread_mutex_init( &proc->mutex_prach_br, NULL);
+  pthread_cond_init( &proc->cond_prach_br, NULL);
+  attr_FH        = &proc->attr_FH;
+  pthread_create( &proc->pthread_FH, attr_FH, ru_thread, (void *)ru );
+}
+
+void wakeup_prach_eNB(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) {
+  L1_proc_t *proc = &eNB->proc;
+  LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
+
+  // check if we have to detect PRACH first
+  if (is_prach_subframe(fp,frame,subframe)>0) {
+    // set timing for prach thread
+    proc->frame_prach = frame;
+    proc->subframe_prach = subframe;
+    prach_procedures(eNB
+                     ,0
+                    );
+  }
+}
+
+void wakeup_prach_eNB_br(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) {
+  L1_proc_t *proc = &eNB->proc;
+  LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
+
+  // 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);
+    // set timing for prach thread
+    proc->frame_prach_br = frame;
+    proc->subframe_prach_br = subframe;
+    prach_procedures(eNB,1);
+  }
+}
+
+static inline int wakeup_prach_ru(RU_t *ru) {
+  struct timespec wait;
+  wait.tv_sec=0;
+  wait.tv_nsec=5000000L;
+
+  if (pthread_mutex_timedlock(&ru->proc.mutex_prach,&wait) !=0) {
+    LOG_E( PHY, "[RU] ERROR pthread_mutex_lock for RU prach thread (IC %d)\n", ru->proc.instance_cnt_prach);
+    exit_fun( "error locking mutex_rxtx" );
+    return(-1);
+  }
+
+  if (ru->proc.instance_cnt_prach==-1) {
+    ++ru->proc.instance_cnt_prach;
+    ru->proc.frame_prach    = ru->proc.frame_rx;
+    ru->proc.subframe_prach = ru->proc.subframe_rx;
+
+    // DJP - think prach_procedures() is looking at eNB frame_prach
+    if (ru->eNB_list[0]) {
+      ru->eNB_list[0]->proc.frame_prach = ru->proc.frame_rx;
+      ru->eNB_list[0]->proc.subframe_prach = 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) == 0, "ERROR pthread_cond_signal for RU prach thread\n");
+  } else LOG_W(PHY,"RU prach thread busy, skipping\n");
+
+  pthread_mutex_unlock( &ru->proc.mutex_prach );
+  return(0);
+}
+
+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);
+}
+
+static inline int rxtx(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, char *thread_name) {
+  //L1_rxtx_proc_t *L1_proc_tx = &eNB->proc.L1_proc_tx;
+  // *******************************************************************
+  AssertFatal( eNB !=NULL, "");
+
+  if (NFAPI_MODE==NFAPI_MODE_PNF) {
+    // I am a PNF and I need to let nFAPI know that we have a (sub)frame tick
+    uint16_t frame = proc->frame_rx;
+    uint16_t subframe = proc->subframe_rx;
+    //add_subframe(&frame, &subframe, 4);
+    //oai_subframe_ind(proc->frame_tx, proc->subframe_tx);
+    //LOG_D(PHY, "oai_subframe_ind(frame:%u, subframe:%d) - NOT CALLED ********\n", frame, subframe);
+    oai_subframe_ind(frame, subframe);
+  }
+
+  AssertFatal( !(NFAPI_MODE==NFAPI_MODE_PNF && eNB->pdcch_vars[proc->subframe_tx&1].num_pdcch_symbols == 0), "");
+  wakeup_prach_eNB(eNB,NULL,proc->frame_rx,proc->subframe_rx);
+  wakeup_prach_eNB_br(eNB,NULL,proc->frame_rx,proc->subframe_rx);
+  release_UE_in_freeList(eNB->Mod_id);
+
+  // UE-specific RX processing for subframe n
+  if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) {
+    phy_procedures_eNB_uespec_RX(eNB, proc);
+  }
+
+  pthread_mutex_lock(&eNB->UL_INFO_mutex);
+  eNB->UL_INFO.frame     = proc->frame_rx;
+  eNB->UL_INFO.subframe  = proc->subframe_rx;
+  eNB->UL_INFO.module_id = eNB->Mod_id;
+  eNB->UL_INFO.CC_id     = eNB->CC_id;
+  eNB->if_inst->UL_indication(&eNB->UL_INFO);
+  pthread_mutex_unlock(&eNB->UL_INFO_mutex);
+  phy_procedures_eNB_TX(eNB, proc, 1);
+  return(0);
+}
+
+void eNB_top(PHY_VARS_eNB *eNB, int frame_rx, int subframe_rx, char *string,RU_t *ru) {
+  L1_proc_t *proc           = &eNB->proc;
+  L1_rxtx_proc_t *L1_proc = &proc->L1_proc;
+  LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
+  RU_proc_t *ru_proc=&ru->proc;
+  proc->frame_rx    = frame_rx;
+  proc->subframe_rx = subframe_rx;
+
+  if (!oai_exit) {
+    T(T_ENB_MASTER_TICK, T_INT(0), T_INT(proc->frame_rx), T_INT(proc->subframe_rx));
+    L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sf_ahead*fp->samples_per_tti);
+    L1_proc->frame_rx     = ru_proc->frame_rx;
+    L1_proc->subframe_rx  = ru_proc->subframe_rx;
+    L1_proc->frame_tx     = (L1_proc->subframe_rx > (9-sf_ahead)) ? (L1_proc->frame_rx+1)&1023 : L1_proc->frame_rx;
+    L1_proc->subframe_tx  = (L1_proc->subframe_rx + sf_ahead)%10;
+
+    if (rxtx(eNB,L1_proc,string) < 0) LOG_E(PHY,"eNB %d CC_id %d failed during execution\n",eNB->Mod_id,eNB->CC_id);
+
+    ru_proc->timestamp_tx = L1_proc->timestamp_tx;
+    ru_proc->subframe_tx  = L1_proc->subframe_tx;
+    ru_proc->frame_tx     = L1_proc->frame_tx;
+  }
+}
+void init_transport(PHY_VARS_eNB *eNB) {
+  int i;
+  int j;
+  LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;
+  LOG_I(PHY, "Initialise transport\n");
+
+  for (i=0; i<NUMBER_OF_UE_MAX; i++) {
+    LOG_D(PHY,"Allocating Transport Channel Buffers for DLSCH, UE %d\n",i);
+
+    for (j=0; j<2; j++) {
+      eNB->dlsch[i][j] = new_eNB_dlsch(1,8,NSOFT,fp->N_RB_DL,0,fp);
+
+      if (!eNB->dlsch[i][j]) {
+        LOG_E(PHY,"Can't get eNB dlsch structures for UE %d \n", i);
+        exit(-1);
+      } else {
+        eNB->dlsch[i][j]->rnti=0;
+        LOG_D(PHY,"dlsch[%d][%d] => %p rnti:%d\n",i,j,eNB->dlsch[i][j], eNB->dlsch[i][j]->rnti);
+      }
+    }
+
+    LOG_D(PHY,"Allocating Transport Channel Buffer for ULSCH, UE %d\n",i);
+    eNB->ulsch[1+i] = new_eNB_ulsch(MAX_TURBO_ITERATIONS,fp->N_RB_UL, 0);
+
+    if (!eNB->ulsch[1+i]) {
+      LOG_E(PHY,"Can't get eNB ulsch structures\n");
+      exit(-1);
+    }
+
+    // this is the transmission mode for the signalling channels
+    // this will be overwritten with the real transmission mode by the RRC once the UE is connected
+    eNB->transmission_mode[i] = fp->nb_antenna_ports_eNB==1 ? 1 : 2;
+  }
+
+  // ULSCH for RA
+  eNB->ulsch[0] = new_eNB_ulsch(MAX_TURBO_ITERATIONS, fp->N_RB_UL, 0);
+
+  if (!eNB->ulsch[0]) {
+    LOG_E(PHY,"Can't get eNB ulsch structures\n");
+    exit(-1);
+  }
+
+  eNB->dlsch_SI  = new_eNB_dlsch(1,8,NSOFT,fp->N_RB_DL, 0, fp);
+  LOG_D(PHY,"eNB %d.%d : SI %p\n",eNB->Mod_id,eNB->CC_id,eNB->dlsch_SI);
+  eNB->dlsch_ra  = new_eNB_dlsch(1,8,NSOFT,fp->N_RB_DL, 0, fp);
+  LOG_D(PHY,"eNB %d.%d : RA %p\n",eNB->Mod_id,eNB->CC_id,eNB->dlsch_ra);
+  eNB->dlsch_MCH = new_eNB_dlsch(1,8,NSOFT,fp->N_RB_DL, 0, fp);
+  LOG_D(PHY,"eNB %d.%d : MCH %p\n",eNB->Mod_id,eNB->CC_id,eNB->dlsch_MCH);
+  eNB->rx_total_gain_dB=130;
+
+  for(i=0; i<NUMBER_OF_UE_MAX; i++)
+    eNB->mu_mimo_mode[i].dl_pow_off = 2;
+
+  eNB->check_for_total_transmissions = 0;
+  eNB->check_for_MUMIMO_transmissions = 0;
+  eNB->FULL_MUMIMO_transmissions = 0;
+  eNB->check_for_SUMIMO_transmissions = 0;
+  fp->pucch_config_common.deltaPUCCH_Shift = 1;
+}
+
+void init_eNB_afterRU(void) {
+  int inst,CC_id,ru_id,i,aa;
+  PHY_VARS_eNB *eNB;
+
+  for (inst=0; inst<RC.nb_inst; inst++) {
+    for (CC_id=0; CC_id<RC.nb_CC[inst]; CC_id++) {
+      eNB = RC.eNB[inst][CC_id];
+      phy_init_lte_eNB(eNB,0,0);
+      eNB->frame_parms.nb_antennas_rx       = 0;
+      eNB->prach_vars.rxsigF[0] = (int16_t **)malloc16(64*sizeof(int16_t *));
+
+      for (int ce_level=0; ce_level<4; ce_level++) {
+        LOG_I(PHY,"Overwriting eNB->prach_vars_br.rxsigF.rxsigF[0]:%p\n", eNB->prach_vars_br.rxsigF[ce_level]);
+        eNB->prach_vars_br.rxsigF[ce_level] = (int16_t **)malloc16(64*sizeof(int16_t *));
+      }
+
+      for (ru_id=0,aa=0; ru_id<eNB->num_RU; ru_id++) {
+        eNB->frame_parms.nb_antennas_rx    += eNB->RU_list[ru_id]->nb_rx;
+        AssertFatal(eNB->RU_list[ru_id]->common.rxdataF!=NULL,
+                    "RU %d : common.rxdataF is NULL\n",
+                    eNB->RU_list[ru_id]->idx);
+        AssertFatal(eNB->RU_list[ru_id]->prach_rxsigF!=NULL,
+                    "RU %d : prach_rxsigF is NULL\n",
+                    eNB->RU_list[ru_id]->idx);
+
+        for (i=0; i<eNB->RU_list[ru_id]->nb_rx; aa++,i++) {
+          LOG_I(PHY,"Attaching RU %d antenna %d to eNB antenna %d\n",eNB->RU_list[ru_id]->idx,i,aa);
+          eNB->prach_vars.rxsigF[0][aa]    =  eNB->RU_list[ru_id]->prach_rxsigF[i];
+
+          for (int ce_level=0; ce_level<4; ce_level++)
+            eNB->prach_vars_br.rxsigF[ce_level][aa] = eNB->RU_list[ru_id]->prach_rxsigF_br[ce_level][i];
+
+          eNB->common_vars.rxdataF[aa]     =  eNB->RU_list[ru_id]->common.rxdataF[i];
+        }
+      }
+
+      /* TODO: review this code, there is something wrong.
+       * In monolithic mode, we come here with nb_antennas_rx == 0
+       * (not tested in other modes).
+       */
+      if (eNB->frame_parms.nb_antennas_rx < 1) {
+        LOG_I(PHY, "%s() ************* DJP ***** eNB->frame_parms.nb_antennas_rx:%d - GOING TO HARD CODE TO 1", __FUNCTION__, eNB->frame_parms.nb_antennas_rx);
+        eNB->frame_parms.nb_antennas_rx = 1;
+      } else {
+        //LOG_I(PHY," Delete code\n");
+      }
+
+      if (eNB->frame_parms.nb_antennas_tx < 1) {
+        LOG_I(PHY, "%s() ************* DJP ***** eNB->frame_parms.nb_antennas_tx:%d - GOING TO HARD CODE TO 1", __FUNCTION__, eNB->frame_parms.nb_antennas_tx);
+        eNB->frame_parms.nb_antennas_tx = 1;
+      } else {
+        //LOG_I(PHY," Delete code\n");
+      }
+
+      AssertFatal(eNB->frame_parms.nb_antennas_rx >0,
+                  "inst %d, CC_id %d : nb_antennas_rx %d\n",inst,CC_id,eNB->frame_parms.nb_antennas_rx);
+      LOG_I(PHY,"inst %d, CC_id %d : nb_antennas_rx %d\n",inst,CC_id,eNB->frame_parms.nb_antennas_rx);
+      init_transport(eNB);
+      //init_precoding_weights(RC.eNB[inst][CC_id]);
+    }
+
+    init_eNB_proc(inst);
+  }
+}
+
+void init_eNB(int single_thread_flag,int wait_for_sync) {
+  int CC_id;
+  int inst;
+  PHY_VARS_eNB *eNB;
+
+  if (RC.eNB == NULL) RC.eNB = (PHY_VARS_eNB ** *) malloc(RC.nb_L1_inst*sizeof(PHY_VARS_eNB **));
+
+  for (inst=0; inst<RC.nb_L1_inst; inst++) {
+    if (RC.eNB[inst] == NULL) RC.eNB[inst] = (PHY_VARS_eNB **) malloc(RC.nb_CC[inst]*sizeof(PHY_VARS_eNB *));
+
+    for (CC_id=0; CC_id<RC.nb_L1_CC[inst]; CC_id++) {
+      if (RC.eNB[inst][CC_id] == NULL) RC.eNB[inst][CC_id] = (PHY_VARS_eNB *) malloc(sizeof(PHY_VARS_eNB));
+
+      eNB                     = RC.eNB[inst][CC_id];
+      eNB->abstraction_flag   = 0;
+      eNB->single_thread_flag = single_thread_flag;
+      AssertFatal((eNB->if_inst         = IF_Module_init(inst))!=NULL,"Cannot register interface");
+      eNB->if_inst->schedule_response   = schedule_response;
+      eNB->if_inst->PHY_config_req      = phy_config_request;
+      memset((void *)&eNB->UL_INFO,0,sizeof(eNB->UL_INFO));
+      memset((void *)&eNB->Sched_INFO,0,sizeof(eNB->Sched_INFO));
+      LOG_I(PHY,"Setting indication lists\n");
+      eNB->UL_INFO.rx_ind.rx_indication_body.rx_pdu_list   = eNB->rx_pdu_list;
+      eNB->UL_INFO.crc_ind.crc_indication_body.crc_pdu_list = eNB->crc_pdu_list;
+      eNB->UL_INFO.sr_ind.sr_indication_body.sr_pdu_list = eNB->sr_pdu_list;
+      eNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list = eNB->harq_pdu_list;
+      eNB->UL_INFO.cqi_ind.cqi_pdu_list = eNB->cqi_pdu_list;
+      eNB->UL_INFO.cqi_ind.cqi_raw_pdu_list = eNB->cqi_raw_pdu_list;
+      eNB->prach_energy_counter = 0;
+    }
+  }
+}
+
+void stop_eNB(int nb_inst) {
+  for (int inst=0; inst<nb_inst; inst++) {
+    LOG_I(PHY,"Killing eNB %d processing threads\n",inst);
+    kill_eNB_proc(inst);
+  }
+}
+
+void rx_rf(RU_t *ru,int *frame,int *subframe) {
+  RU_proc_t *proc = &ru->proc;
+  LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
+  void *rxp[ru->nb_rx];
+  unsigned int rxs;
+  int i;
+  openair0_timestamp ts=0,old_ts=0;
+
+  for (i=0; i<ru->nb_rx; i++)
+    rxp[i] = (void *)&ru->common.rxdata[i][*subframe*fp->samples_per_tti];
+
+  old_ts = proc->timestamp_rx;
+  rxs = ru->rfdevice.trx_read_func(&ru->rfdevice,
+                                   &ts,
+                                   rxp,
+                                   fp->samples_per_tti,
+                                   ru->nb_rx);
+  proc->timestamp_rx = ts-ru->ts_offset;
+
+  //  AssertFatal(rxs == fp->samples_per_tti,
+  //        "rx_rf: Asked for %d samples, got %d from SDR\n",fp->samples_per_tti,rxs);
+  if(rxs != fp->samples_per_tti) {
+    LOG_E(PHY,"rx_rf: Asked for %d samples, got %d from SDR\n",fp->samples_per_tti,rxs);
+  }
+
+  if (proc->first_rx == 1) {
+    ru->ts_offset = proc->timestamp_rx;
+    proc->timestamp_rx = 0;
+  } else {
+    if (proc->timestamp_rx - old_ts != fp->samples_per_tti) {
+      //LOG_I(PHY,"rx_rf: rfdevice timing drift of %"PRId64" samples (ts_off %"PRId64")\n",proc->timestamp_rx - old_ts - fp->samples_per_tti,ru->ts_offset);
+      ru->ts_offset += (proc->timestamp_rx - old_ts - fp->samples_per_tti);
+      proc->timestamp_rx = ts-ru->ts_offset;
+    }
+  }
+
+  proc->frame_rx     = (proc->timestamp_rx / (fp->samples_per_tti*10))&1023;
+  proc->subframe_rx  = (proc->timestamp_rx / fp->samples_per_tti)%10;
+  // synchronize first reception to frame 0 subframe 0
+  proc->timestamp_tx = proc->timestamp_rx+(sf_ahead*fp->samples_per_tti);
+  proc->subframe_tx  = (proc->subframe_rx+sf_ahead)%10;
+  proc->frame_tx     = (proc->subframe_rx>(9-sf_ahead)) ? (proc->frame_rx+1)&1023 : proc->frame_rx;
+
+  if (proc->first_rx == 0) {
+    if (proc->subframe_rx != *subframe) {
+      LOG_E(PHY,"Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->subframe_rx %d, subframe %d)\n",(long long unsigned int)proc->timestamp_rx,proc->subframe_rx,*subframe);
+      exit_fun("Exiting");
+    }
+
+    if (proc->frame_rx != *frame) {
+      LOG_E(PHY,"Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->frame_rx %d frame %d)\n",(long long unsigned int)proc->timestamp_rx,proc->frame_rx,*frame);
+      exit_fun("Exiting");
+    }
+  } else {
+    proc->first_rx = 0;
+    *frame = proc->frame_rx;
+    *subframe = proc->subframe_rx;
+  }
+
+  //printf("timestamp_rx %lu, frame %d(%d), subframe %d(%d)\n",ru->timestamp_rx,proc->frame_rx,frame,proc->subframe_rx,subframe);
+
+  if (rxs != fp->samples_per_tti) {
+#if defined(USRP_REC_PLAY)
+    exit_fun("Exiting IQ record/playback");
+#else
+    //exit_fun( "problem receiving samples" );
+    LOG_E(PHY, "problem receiving samples");
+#endif
+  }
+}
+
+
+void tx_rf(RU_t *ru) {
+  RU_proc_t *proc = &ru->proc;
+  LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
+  void *txp[ru->nb_tx];
+  int i;
+  lte_subframe_t SF_type     = subframe_select(fp,proc->subframe_tx%10);
+  lte_subframe_t prevSF_type = subframe_select(fp,(proc->subframe_tx+9)%10);
+  int sf_extension = 0;
+
+  if ((SF_type == SF_DL) ||
+      (SF_type == SF_S)) {
+    int siglen=fp->samples_per_tti,flags=1;
+
+    if (SF_type == SF_S) {
+      /* end_of_burst_delay is used to stop TX only "after a while".
+       * If we stop right after effective signal, with USRP B210 and
+       * B200mini, we observe a high EVM on the S subframe (on the
+       * PSS).
+       * A value of 400 (for 30.72MHz) solves this issue. This is
+       * the default.
+       */
+      siglen = (fp->ofdm_symbol_size + fp->nb_prefix_samples0)
+               + (fp->dl_symbols_in_S_subframe - 1) * (fp->ofdm_symbol_size + fp->nb_prefix_samples)
+               + ru->end_of_burst_delay;
+      flags=3; // end of burst
+    }
+
+    if (fp->frame_type == TDD &&
+        SF_type == SF_DL &&
+        prevSF_type == SF_UL) {
+      flags = 2; // start of burst
+      sf_extension = ru->sf_extension;
+    }
+
+#if defined(__x86_64) || defined(__i386__)
+#ifdef __AVX2__
+    sf_extension = (sf_extension)&0xfffffff8;
+#else
+    sf_extension = (sf_extension)&0xfffffffc;
+#endif
+#elif defined(__arm__)
+    sf_extension = (sf_extension)&0xfffffffc;
+#endif
+
+    for (i=0; i<ru->nb_tx; i++)
+      txp[i] = (void *)&ru->common.txdata[i][(proc->subframe_tx*fp->samples_per_tti)-sf_extension];
+
+    /* add fail safe for late command end */
+    // prepare tx buffer pointers
+    ru->rfdevice.trx_write_func(&ru->rfdevice,
+                                      proc->timestamp_tx+ru->ts_offset-ru->openair0_cfg.tx_sample_advance-sf_extension,
+                                      txp,
+                                      siglen+sf_extension,
+                                      ru->nb_tx,
+                                      flags);
+    LOG_D(PHY,"[TXPATH] RU %d tx_rf, writing to TS %llu, frame %d, unwrapped_frame %d, subframe %d\n",ru->idx,
+          (long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->frame_tx_unwrap,proc->subframe_tx);
+  }
+}
+// this is for RU with local RF unit
+void fill_rf_config(RU_t *ru, char *rf_config_file) {
+  int i;
+  LTE_DL_FRAME_PARMS *fp   = &ru->frame_parms;
+  openair0_config_t *cfg   = &ru->openair0_cfg;
+  //printf("////////////////numerology in config = %d\n",numerology);
+  int numerology = get_softmodem_params()->numerology;
+
+  if(fp->N_RB_DL == 100) {
+    if(numerology == 0) {
+      if (fp->threequarter_fs) {
+        cfg->sample_rate=23.04e6;
+        cfg->samples_per_frame = 230400;
+        cfg->tx_bw = 10e6;
+        cfg->rx_bw = 10e6;
+      } else {
+        cfg->sample_rate=30.72e6;
+        cfg->samples_per_frame = 307200;
+        cfg->tx_bw = 10e6;
+        cfg->rx_bw = 10e6;
+      }
+    } else if(numerology == 1) {
+      cfg->sample_rate=61.44e6;
+      cfg->samples_per_frame = 307200;
+      cfg->tx_bw = 20e6;
+      cfg->rx_bw = 20e6;
+    } else if(numerology == 2) {
+      cfg->sample_rate=122.88e6;
+      cfg->samples_per_frame = 307200;
+      cfg->tx_bw = 40e6;
+      cfg->rx_bw = 40e6;
+    } else {
+      printf("Wrong input for numerology %d\n setting to 20MHz normal CP configuration",numerology);
+      cfg->sample_rate=30.72e6;
+      cfg->samples_per_frame = 307200;
+      cfg->tx_bw = 10e6;
+      cfg->rx_bw = 10e6;
+    }
+  } else if(fp->N_RB_DL == 50) {
+    cfg->sample_rate=15.36e6;
+    cfg->samples_per_frame = 153600;
+    cfg->tx_bw = 5e6;
+    cfg->rx_bw = 5e6;
+  } else if (fp->N_RB_DL == 25) {
+    cfg->sample_rate=7.68e6;
+    cfg->samples_per_frame = 76800;
+    cfg->tx_bw = 2.5e6;
+    cfg->rx_bw = 2.5e6;
+  } else if (fp->N_RB_DL == 6) {
+    cfg->sample_rate=1.92e6;
+    cfg->samples_per_frame = 19200;
+    cfg->tx_bw = 1.5e6;
+    cfg->rx_bw = 1.5e6;
+  } else AssertFatal(1==0,"Unknown N_RB_DL %d\n",fp->N_RB_DL);
+
+  if (fp->frame_type==TDD)
+    cfg->duplex_mode = duplex_mode_TDD;
+  else //FDD
+    cfg->duplex_mode = duplex_mode_FDD;
+
+  cfg->Mod_id = 0;
+  cfg->num_rb_dl=fp->N_RB_DL;
+  cfg->tx_num_channels=ru->nb_tx;
+  cfg->rx_num_channels=ru->nb_rx;
+  cfg->clock_source=get_softmodem_params()->clock_source;
+
+  for (i=0; i<ru->nb_tx; i++) {
+    cfg->tx_freq[i] = (double)fp->dl_CarrierFreq;
+    cfg->rx_freq[i] = (double)fp->ul_CarrierFreq;
+    cfg->tx_gain[i] = (double)ru->att_tx;
+    cfg->rx_gain[i] = ru->max_rxgain-(double)ru->att_rx;
+    cfg->configFilename = rf_config_file;
+    printf("channel %d, Setting tx_gain offset %f, rx_gain offset %f, tx_freq %f, rx_freq %f\n",
+           i, cfg->tx_gain[i],
+           cfg->rx_gain[i],
+           cfg->tx_freq[i],
+           cfg->rx_freq[i]);
+  }
+}
+
+/* this function maps the RU tx and rx buffers to the available rf chains.
+   Each rf chain is is addressed by the card number and the chain on the card. The
+   rf_map specifies for each antenna port, on which rf chain the mapping should start. Multiple
+   antennas are mapped to successive RF chains on the same card. */
+int setup_RU_buffers(RU_t *ru) {
+  int i,j;
+  int card,ant;
+  //uint16_t N_TA_offset = 0;
+  LTE_DL_FRAME_PARMS *frame_parms;
+
+  if (ru) {
+    frame_parms = &ru->frame_parms;
+    printf("setup_RU_buffers: frame_parms = %p\n",frame_parms);
+  } else {
+    printf("RU not initialized (NULL pointer)\n");
+    return(-1);
+  }
+
+  if (frame_parms->frame_type == TDD) {
+    if      (frame_parms->N_RB_DL == 100) ru->N_TA_offset = 624;
+    else if (frame_parms->N_RB_DL == 50)  ru->N_TA_offset = 624/2;
+    else if (frame_parms->N_RB_DL == 25)  ru->N_TA_offset = 624/4;
+
+    if(IS_SOFTMODEM_BASICSIM)
+      /* this is required for the basic simulator in TDD mode
+       * TODO: find a proper cleaner solution
+       */
+      ru->N_TA_offset = 0;
+
+    if      (frame_parms->N_RB_DL == 100) /* no scaling to do */;
+    else if (frame_parms->N_RB_DL == 50) {
+      ru->sf_extension       /= 2;
+      ru->end_of_burst_delay /= 2;
+    } else if (frame_parms->N_RB_DL == 25) {
+      ru->sf_extension       /= 4;
+      ru->end_of_burst_delay /= 4;
+    } else {
+      printf("not handled, todo\n");
+      exit(1);
+    }
+  } else {
+    ru->N_TA_offset = 0;
+    ru->sf_extension = 0;
+    ru->end_of_burst_delay = 0;
+  }
+
+  if (ru->openair0_cfg.mmapped_dma == 1) {
+    // replace RX signal buffers with mmaped HW versions
+    for (i=0; i<ru->nb_rx; i++) {
+      card = i/4;
+      ant = i%4;
+      printf("Mapping RU id %d, rx_ant %d, on card %d, chain %d\n",ru->idx,i,ru->rf_map.card+card, ru->rf_map.chain+ant);
+      free(ru->common.rxdata[i]);
+      ru->common.rxdata[i] = ru->openair0_cfg.rxbase[ru->rf_map.chain+ant];
+      printf("rxdata[%d] @ %p\n",i,ru->common.rxdata[i]);
+
+      for (j=0; j<16; j++) {
+        printf("rxbuffer %d: %x\n",j,ru->common.rxdata[i][j]);
+        ru->common.rxdata[i][j] = 16-j;
+      }
+    }
+
+    for (i=0; i<ru->nb_tx; i++) {
+      card = i/4;
+      ant = i%4;
+      printf("Mapping RU id %d, tx_ant %d, on card %d, chain %d\n",ru->idx,i,ru->rf_map.card+card, ru->rf_map.chain+ant);
+      free(ru->common.txdata[i]);
+      ru->common.txdata[i] = ru->openair0_cfg.txbase[ru->rf_map.chain+ant];
+      printf("txdata[%d] @ %p\n",i,ru->common.txdata[i]);
+
+      for (j=0; j<16; j++) {
+        printf("txbuffer %d: %x\n",j,ru->common.txdata[i][j]);
+        ru->common.txdata[i][j] = 16-j;
+      }
+    }
+  } else { // not memory-mapped DMA
+    //nothing to do, everything already allocated in lte_init
+  }
+
+  return(0);
+}
+static void *ru_thread( void *param ) {
+  static int ru_thread_status;
+  RU_t               *ru      = (RU_t *)param;
+  RU_proc_t          *proc    = &ru->proc;
+  int                subframe =9;
+  int                frame    =1023;
+  // set default return value
+  ru_thread_status = 0;
+
+  if (ru->if_south == LOCAL_RF) { // configure RF parameters only
+    fill_rf_config(ru,ru->rf_config_file);
+    init_frame_parms(&ru->frame_parms,1);
+    phy_init_RU(ru);
+    openair0_device_load(&ru->rfdevice,&ru->openair0_cfg);
+  }
+
+  if (setup_RU_buffers(ru)!=0) {
+    printf("Exiting, cannot initialize RU Buffers\n");
+    exit(-1);
+  }
+
+  LOG_I(PHY, "Signaling main thread that RU %d is ready\n",ru->idx);
+  pthread_mutex_lock(&RC.ru_mutex);
+  RC.ru_mask &= ~(1<<ru->idx);
+  pthread_cond_signal(&RC.ru_cond);
+  pthread_mutex_unlock(&RC.ru_mutex);
+  pthread_mutex_lock(&proc->mutex_FH1);
+  proc->instance_cnt_FH1 = 0;
+  pthread_mutex_unlock(&proc->mutex_FH1);
+  pthread_cond_signal(&proc->cond_FH1);
+  wait_sync("ru_thread");
+
+  // Start RF device if any
+  if (ru->start_rf) {
+    if (ru->start_rf(ru) != 0)
+      LOG_E(HW,"Could not start the RF device\n");
+    else LOG_I(PHY,"RU %d rf device ready\n",ru->idx);
+  } else LOG_I(PHY,"RU %d no rf device\n",ru->idx);
+
+  // if an asnych_rxtx thread exists
+  // wakeup the thread because the devices are ready at this point
+
+  if ((ru->fh_south_asynch_in)||(ru->fh_north_asynch_in)) {
+    pthread_mutex_lock(&proc->mutex_asynch_rxtx);
+    proc->instance_cnt_asynch_rxtx=0;
+    pthread_mutex_unlock(&proc->mutex_asynch_rxtx);
+    pthread_cond_signal(&proc->cond_asynch_rxtx);
+  } else LOG_I(PHY,"RU %d no asynch_south interface\n",ru->idx);
+
+  // This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices
+  while (!oai_exit) {
+    // these are local subframe/frame counters to check that we are in synch with the fronthaul timing.
+    // They are set on the first rx/tx in the underly FH routines.
+    if (subframe==9) {
+      subframe=0;
+      frame++;
+      frame&=1023;
+    } else {
+      subframe++;
+    }
+
+    // synchronization on input FH interface, acquire signals/data and block
+    AssertFatal(ru->fh_south_in, "No fronthaul interface at south port");
+    ru->fh_south_in(ru,&frame,&subframe);
+
+    // adjust for timing offset between RU
+    if (ru->idx!=0) proc->frame_tx = (proc->frame_tx+proc->frame_offset)&1023;
+
+    // do RX front-end processing (frequency-shift, dft) if needed
+    if (ru->feprx) ru->feprx(ru);
+
+    // At this point, all information for subframe has been received on FH interface
+    // If this proc is to provide synchronization, do so
+    // Fixme: not used
+    // wakeup_slaves(proc);
+    for (int i=0; i<ru->num_eNB; i++) {
+      char string[20];
+      sprintf(string,"Incoming RU %d",ru->idx);
+      ru->eNB_top(ru->eNB_list[i],ru->proc.frame_rx,ru->proc.subframe_rx,string,ru);
+    }
+
+    // do TX front-end processing if needed (precoding and/or IDFTs)
+    if (ru->feptx_prec) ru->feptx_prec(ru);
+
+    // do OFDM if needed
+    if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru);
+
+    // do outgoing fronthaul (south) if needed
+    if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru);
+
+    if (ru->fh_north_out) ru->fh_north_out(ru);
+  }
+
+  printf( "Exiting ru_thread \n");
+
+  if (ru->stop_rf != NULL) {
+    if (ru->stop_rf(ru) != 0)
+      LOG_E(HW,"Could not stop the RF device\n");
+    else LOG_I(PHY,"RU %d rf device stopped\n",ru->idx);
+  }
+
+  ru_thread_status = 0;
+  return &ru_thread_status;
+}
+int start_if(struct RU_t_s *ru,struct PHY_VARS_eNB_s *eNB) {
+  return(ru->ifdevice.trx_start_func(&ru->ifdevice));
+}
+
+int start_rf(RU_t *ru) {
+  return(ru->rfdevice.trx_start_func(&ru->rfdevice));
+}
+
+int stop_rf(RU_t *ru) {
+  ru->rfdevice.trx_end_func(&ru->rfdevice);
+  return 0;
+}
+void init_precoding_weights(PHY_VARS_eNB *eNB) {
+  int layer,ru_id,aa,re,ue,tb;
+  LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
+  RU_t *ru;
+  LTE_eNB_DLSCH_t *dlsch;
+
+  // init precoding weigths
+  for (ue=0; ue<NUMBER_OF_UE_MAX; ue++) {
+    for (tb=0; tb<2; tb++) {
+      dlsch = eNB->dlsch[ue][tb];
+
+      for (layer=0; layer<4; layer++) {
+        int nb_tx=0;
+
+        for (ru_id=0; ru_id<RC.nb_RU; ru_id++) {
+          ru = RC.ru[ru_id];
+          nb_tx+=ru->nb_tx;
+        }
+
+        dlsch->ue_spec_bf_weights[layer] = (int32_t **)malloc16(nb_tx*sizeof(int32_t *));
+
+        for (aa=0; aa<nb_tx; aa++) {
+          dlsch->ue_spec_bf_weights[layer][aa] = (int32_t *)malloc16(fp->ofdm_symbol_size*sizeof(int32_t));
+
+          for (re=0; re<fp->ofdm_symbol_size; re++) {
+            dlsch->ue_spec_bf_weights[layer][aa][re] = 0x00007fff;
+          }
+        }
+      }
+    }
+  }
+}
+
+void set_function_spec_param(RU_t *ru) {
+
+  switch (ru->if_south) {
+    case LOCAL_RF: { // this is an RU with integrated RF (RRU, eNB)
+      ru->do_prach             = 0;                       // no prach processing in RU
+      ru->feprx                = fep_full;
+      ru->feptx_ofdm           = feptx_ofdm;
+      ru->feptx_prec           = feptx_prec;              // this is fep with idft and precoding
+      ru->fh_north_in          = NULL;                    // no incoming fronthaul from north
+      ru->fh_north_out         = NULL;                    // no outgoing fronthaul to north
+      ru->start_if             = NULL;                    // no if interface
+      ru->rfdevice.host_type   = RAU_HOST;
+    }
+
+    ru->fh_south_in            = rx_rf;                               // local synchronous RF RX
+    ru->fh_south_out           = tx_rf;                               // local synchronous RF TX
+    ru->start_rf               = start_rf;                            // need to start the local RF interface
+    ru->stop_rf                = stop_rf;
+    ru->eNB_top=eNB_top;
+    printf("configuring ru_id %d (start_rf %p)\n", ru->idx, start_rf);
+      /*
+          if (ru->function == eNodeB_3GPP) { // configure RF parameters only for 3GPP eNodeB, we need to get them from RAU otherwise
+            fill_rf_config(ru,rf_config_file);
+            init_frame_parms(&ru->frame_parms,1);
+            phy_init_RU(ru);
+          }
+
+          ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg);
+          if (setup_RU_buffers(ru)!=0) {
+            printf("Exiting, cannot initialize RU Buffers\n");
+            exit(-1);
+          }*/
+    break;
+
+    default:
+      LOG_E(PHY,"RU with invalid or unknown southbound interface type %d\n",ru->if_south);
+      break;
+  } // switch on interface type
+}
+
+//extern void RCconfig_RU(void);
+
+void init_RU(char *rf_config_file) {
+  int ru_id;
+  RU_t *ru;
+  PHY_VARS_eNB *eNB0= (PHY_VARS_eNB *)NULL;
+  int i;
+  int CC_id;
+  // create status mask
+  RC.ru_mask = 0;
+  pthread_mutex_init(&RC.ru_mutex,NULL);
+  pthread_cond_init(&RC.ru_cond,NULL);
+  // read in configuration file)
+  printf("configuring RU from file\n");
+  RCconfig_RU();
+  LOG_I(PHY,"number of L1 instances %d, number of RU %d, number of CPU cores %d\n",RC.nb_L1_inst,RC.nb_RU,get_nprocs());
+
+  if (RC.nb_CC != 0)
+    for (i=0; i<RC.nb_L1_inst; i++)
+      for (CC_id=0; CC_id<RC.nb_CC[i]; CC_id++) RC.eNB[i][CC_id]->num_RU=0;
+
+  LOG_D(PHY,"Process RUs RC.nb_RU:%d\n",RC.nb_RU);
+
+  for (ru_id=0; ru_id<RC.nb_RU; ru_id++) {
+    LOG_D(PHY,"Process RC.ru[%d]\n",ru_id);
+    ru               = RC.ru[ru_id];
+    ru->rf_config_file = rf_config_file;
+    ru->idx          = ru_id;
+    ru->ts_offset    = 0;
+    // use eNB_list[0] as a reference for RU frame parameters
+    // NOTE: multiple CC_id are not handled here yet!
+
+    if (ru->num_eNB > 0) {
+      LOG_D(PHY, "%s() RC.ru[%d].num_eNB:%d ru->eNB_list[0]:%p RC.eNB[0][0]:%p rf_config_file:%s\n", __FUNCTION__, ru_id, ru->num_eNB, ru->eNB_list[0], RC.eNB[0][0], ru->rf_config_file);
+
+      if (ru->eNB_list[0] == 0) {
+        LOG_E(PHY,"%s() DJP - ru->eNB_list ru->num_eNB are not initialized - so do it manually\n", __FUNCTION__);
+        ru->eNB_list[0] = RC.eNB[0][0];
+        ru->num_eNB=1;
+        //
+        // DJP - feptx_prec() / feptx_ofdm() parses the eNB_list (based on num_eNB) and copies the txdata_F to txdata in RU
+        //
+      } else {
+        LOG_E(PHY,"DJP - delete code above this %s:%d\n", __FILE__, __LINE__);
+      }
+    }
+
+    eNB0             = ru->eNB_list[0];
+    LOG_D(PHY, "RU FUnction:%d ru->if_south:%d\n", ru->function, ru->if_south);
+    LOG_D(PHY, "eNB0:%p\n", eNB0);
+
+    if (eNB0) {
+      if ((ru->function != NGFI_RRU_IF5) && (ru->function != NGFI_RRU_IF4p5))
+        AssertFatal(eNB0!=NULL,"eNB0 is null!\n");
+
+      if (eNB0) {
+        LOG_I(PHY,"Copying frame parms from eNB %d to ru %d\n",eNB0->Mod_id,ru->idx);
+        memcpy((void *)&ru->frame_parms,(void *)&eNB0->frame_parms,sizeof(LTE_DL_FRAME_PARMS));
+        // attach all RU to all eNBs in its list/
+        LOG_D(PHY,"ru->num_eNB:%d eNB0->num_RU:%d\n", ru->num_eNB, eNB0->num_RU);
+
+        for (i=0; i<ru->num_eNB; i++) {
+          eNB0 = ru->eNB_list[i];
+          eNB0->RU_list[eNB0->num_RU++] = ru;
+        }
+      }
+    }
+
+    LOG_I(PHY,"Initializing RRU descriptor %d : (%s,%s,%d)\n",ru_id,ru_if_types[ru->if_south],eNB_timing[ru->if_timing],ru->function);
+    set_function_spec_param(ru);
+    LOG_I(PHY,"Starting ru_thread %d\n",ru_id);
+    init_RU_proc(ru);
+  } // for ru_id
+
+  //  sleep(1);
+  LOG_D(HW,"[lte-softmodem.c] RU threads created\n");
+}
+
+void stop_RU(int nb_ru) {
+  for (int inst = 0; inst < nb_ru; inst++) {
+    LOG_I(PHY, "Stopping RU %d processing threads\n", inst);
+    kill_RU_proc(RC.ru[inst]);
+  }
+}
+/* --------------------------------------------------------*/
+/* from here function to use configuration module          */
+void RCconfig_RU(void) {
+  int               j                             = 0;
+  int               i                             = 0;
+  paramdef_t RUParams[] = RUPARAMS_DESC;
+  paramlist_def_t RUParamList = {CONFIG_STRING_RU_LIST,NULL,0};
+  config_getlist( &RUParamList,RUParams,sizeof(RUParams)/sizeof(paramdef_t), NULL);
+
+  if ( RUParamList.numelt > 0) {
+    RC.ru = (RU_t **)malloc(RC.nb_RU*sizeof(RU_t *));
+    RC.ru_mask=(1<<RC.nb_RU) - 1;
+    printf("Set RU mask to %lx\n",RC.ru_mask);
+
+    for (j = 0; j < RC.nb_RU; j++) {
+      RC.ru[j]                                    = (RU_t *)malloc(sizeof(RU_t));
+      memset((void *)RC.ru[j],0,sizeof(RU_t));
+      RC.ru[j]->idx                                 = j;
+      printf("Creating RC.ru[%d]:%p\n", j, RC.ru[j]);
+      RC.ru[j]->if_timing                           = synch_to_ext_device;
+
+      if (RC.nb_L1_inst >0)
+        RC.ru[j]->num_eNB                           = RUParamList.paramarray[j][RU_ENB_LIST_IDX].numelt;
+      else
+        RC.ru[j]->num_eNB                           = 0;
+
+      for (i=0; i<RC.ru[j]->num_eNB; i++) RC.ru[j]->eNB_list[i] = RC.eNB[RUParamList.paramarray[j][RU_ENB_LIST_IDX].iptr[i]][0];
+
+      if (config_isparamset(RUParamList.paramarray[j], RU_SDR_ADDRS)) {
+        RC.ru[j]->openair0_cfg.sdr_addrs = strdup(*(RUParamList.paramarray[j][RU_SDR_ADDRS].strptr));
+      }
+
+      if (config_isparamset(RUParamList.paramarray[j], RU_SDR_CLK_SRC)) {
+        if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "internal") == 0) {
+          RC.ru[j]->openair0_cfg.clock_source = internal;
+          LOG_D(PHY, "RU clock source set as internal\n");
+        } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "external") == 0) {
+          RC.ru[j]->openair0_cfg.clock_source = external;
+          LOG_D(PHY, "RU clock source set as external\n");
+        } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "gpsdo") == 0) {
+          RC.ru[j]->openair0_cfg.clock_source = gpsdo;
+          LOG_D(PHY, "RU clock source set as gpsdo\n");
+        } else {
+          LOG_E(PHY, "Erroneous RU clock source in the provided configuration file: '%s'\n", *(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr));
+        }
+      }
+
+      if (strcmp(*(RUParamList.paramarray[j][RU_LOCAL_RF_IDX].strptr), "yes") == 0) {
+        if ( !(config_isparamset(RUParamList.paramarray[j],RU_LOCAL_IF_NAME_IDX)) ) {
+          RC.ru[j]->if_south                        = LOCAL_RF;
+          RC.ru[j]->function                        = eNodeB_3GPP;
+          printf("Setting function for RU %d to eNodeB_3GPP\n",j);
+        } else {
+          RC.ru[j]->eth_params.local_if_name            = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr));
+          RC.ru[j]->eth_params.my_addr                  = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr));
+          RC.ru[j]->eth_params.remote_addr              = strdup(*(RUParamList.paramarray[j][RU_REMOTE_ADDRESS_IDX].strptr));
+          RC.ru[j]->eth_params.my_portc                 = *(RUParamList.paramarray[j][RU_LOCAL_PORTC_IDX].uptr);
+          RC.ru[j]->eth_params.remote_portc             = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr);
+          RC.ru[j]->eth_params.my_portd                 = *(RUParamList.paramarray[j][RU_LOCAL_PORTD_IDX].uptr);
+          RC.ru[j]->eth_params.remote_portd             = *(RUParamList.paramarray[j][RU_REMOTE_PORTD_IDX].uptr);
+        }
+
+        RC.ru[j]->max_pdschReferenceSignalPower     = *(RUParamList.paramarray[j][RU_MAX_RS_EPRE_IDX].uptr);;
+        RC.ru[j]->max_rxgain                        = *(RUParamList.paramarray[j][RU_MAX_RXGAIN_IDX].uptr);
+        RC.ru[j]->num_bands                         = RUParamList.paramarray[j][RU_BAND_LIST_IDX].numelt;
+        /* sf_extension is in unit of samples for 30.72MHz here, has to be scaled later */
+        RC.ru[j]->sf_extension                      = *(RUParamList.paramarray[j][RU_SF_EXTENSION_IDX].uptr);
+        RC.ru[j]->end_of_burst_delay                = *(RUParamList.paramarray[j][RU_END_OF_BURST_DELAY_IDX].uptr);
+
+        for (i=0; i<RC.ru[j]->num_bands; i++) RC.ru[j]->band[i] = RUParamList.paramarray[j][RU_BAND_LIST_IDX].iptr[i];
+      } //strcmp(local_rf, "yes") == 0
+      else {
+        printf("RU %d: Transport %s\n",j,*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr));
+        RC.ru[j]->eth_params.local_if_name        = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr));
+        RC.ru[j]->eth_params.my_addr          = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr));
+        RC.ru[j]->eth_params.remote_addr        = strdup(*(RUParamList.paramarray[j][RU_REMOTE_ADDRESS_IDX].strptr));
+        RC.ru[j]->eth_params.my_portc         = *(RUParamList.paramarray[j][RU_LOCAL_PORTC_IDX].uptr);
+        RC.ru[j]->eth_params.remote_portc       = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr);
+        RC.ru[j]->eth_params.my_portd         = *(RUParamList.paramarray[j][RU_LOCAL_PORTD_IDX].uptr);
+        RC.ru[j]->eth_params.remote_portd       = *(RUParamList.paramarray[j][RU_REMOTE_PORTD_IDX].uptr);
+      }  /* strcmp(local_rf, "yes") != 0 */
+
+      RC.ru[j]->nb_tx                             = *(RUParamList.paramarray[j][RU_NB_TX_IDX].uptr);
+      RC.ru[j]->nb_rx                             = *(RUParamList.paramarray[j][RU_NB_RX_IDX].uptr);
+      RC.ru[j]->att_tx                            = *(RUParamList.paramarray[j][RU_ATT_TX_IDX].uptr);
+      RC.ru[j]->att_rx                            = *(RUParamList.paramarray[j][RU_ATT_RX_IDX].uptr);
+    }// j=0..num_rus
+  } else {
+    RC.nb_RU = 0;
+  } // setting != NULL
+
+  return;
+}
diff --git a/executables/transport_split.c b/executables/transport_split.c
index a1e0738458ae69f58777de194af38c8b21c671ae..fe9e1a419ccaba3fbb9354cd018c644ee87c9414 100644
--- a/executables/transport_split.c
+++ b/executables/transport_split.c
@@ -3,63 +3,70 @@
 int createListner (port) {
   int sock;
   AssertFatal((sock=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) >= 0, "");
-    struct sockaddr_in addr = {
+  struct sockaddr_in addr = {
 sin_family:
     AF_INET,
 sin_port:
-htons(port),
+    htons(port),
 sin_addr:
     { s_addr: INADDR_ANY }
-    };
-    int enable=1;
-    AssertFatal(setsockopt(eth->sockfdc, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable))==0,"");
-    AssertFatal(bind(sock, const struct sockaddr *addr, socklen_t addrlen)==0,"");
-    struct timeval tv={0,UDP_TIMEOUT};
-    AssertFatal(setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(tv)) ==0,"");
-    // Make a send/recv buffer larger than a a couple of subframe
-    // so the kernel will store for us in and out paquets
-    int buff=1000*1000*10;
-    AssertFatal ( setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &buff, sizeof(buff)) == 0, "");
-    AssertFatal ( setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &buff, sizeof(buff)) == 0, "");
+  };
+  int enable=1;
+  AssertFatal(setsockopt(eth->sockfdc, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable))==0,"");
+  AssertFatal(bind(sock, const struct sockaddr *addr, socklen_t addrlen)==0,"");
+  struct timeval tv= {0,UDP_TIMEOUT};
+  AssertFatal(setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(tv)) ==0,"");
+  // Make a send/recv buffer larger than a a couple of subframe
+  // so the kernel will store for us in and out paquets
+  int buff=1000*1000*10;
+  AssertFatal ( setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &buff, sizeof(buff)) == 0, "");
+  AssertFatal ( setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &buff, sizeof(buff)) == 0, "");
 }
 
 // sock: udp socket
 // expectedTS: the expected timestamp, 0 if unknown
 // bufferZone: a reception area of bufferSize
-int receiveSubFrame(int sock, uint64_t expectedTS, void* bufferZone,  int bufferSize) {
+int receiveSubFrame(int sock, uint64_t expectedTS, void *bufferZone,  int bufferSize) {
   int rcved=0;
+
   do {
     //read all subframe data from the control unit
     int ret=recv(sock, bufferZone, bufferSize, 0);
+
     if ( ret==-1) {
       if ( errno == EWOULDBLOCK || errno== EINTR ) {
-	return  rcved; // Timeout, subframe incomplete
+        return  rcved; // Timeout, subframe incomplete
       } else {
-	LOG_E(HW,"Critical issue in socket: %s\n", strerror(errno));
-	return -1;
+        LOG_E(HW,"Critical issue in socket: %s\n", strerror(errno));
+        return -1;
       }
     } else {
-      commonUDP_t * tmp=(commonUDP_t *)bufferZone;
+      commonUDP_t *tmp=(commonUDP_t *)bufferZone;
+
       if ( expectedTS && tmp->timestamp != expectedTS) {
-	LOG_W(HW,"Received a paquet in mixed subframes, dropping it\n");
+        LOG_W(HW,"Received a paquet in mixed subframes, dropping it\n");
       } else {
-	rcved++;
-	bufferZone+=ret;
+        rcved++;
+        bufferZone+=ret;
       }
     }
   } while ( !recved || recved < tmp->nbBlocks);
+
   return recv;
 }
 
-int sendSubFrame(int sock, void* bufferZone, int nbBlocks) {
+int sendSubFrame(int sock, void *bufferZone, int nbBlocks) {
   do {
     int sz=alignedSize(bufferZone);
     int ret=send(sock, bufferZone, sz, 0);
+
     if ( ret != sz )
       LOG_W(HW,"Wrote socket doesn't return size %d (val: %d, errno:%d)\n",
-	    sz, ret, errno);
+            sz, ret, errno);
+
     bufferZone+=sz;
     nbBlocks--;
   } while (nbBlocks);
+
   return 0;
 }
diff --git a/targets/ARCH/rfsimulator/simulator.c b/targets/ARCH/rfsimulator/simulator.c
index e81e958184e4b73afbcd4782f26b15b724850492..1bb424d115f59133719c1f65014bb0ea29ee709b 100644
--- a/targets/ARCH/rfsimulator/simulator.c
+++ b/targets/ARCH/rfsimulator/simulator.c
@@ -135,9 +135,6 @@ void rxAddInput( struct complex16 *input_sig, struct complex16 *after_channel_si
     }
 
     out_ptr->r += round(rx_tmp.x*pathLossLinear + noise_per_sample*gaussdouble(0.0,1.0));
-      printf("in: %d, out %d= %f*%f + %f*%f\n",
-      input_sig[((TS+i)*nbTx)%CirSize].r, out_ptr->r , rx_tmp.x,
-      pathLossLinear, noise_per_sample,gaussdouble(0.0,1.0));
     out_ptr->i += round(rx_tmp.y*pathLossLinear + noise_per_sample*gaussdouble(0.0,1.0));
     out_ptr++;
   }
diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c
index 8ae3d8956c9f7154b45cc1cb9dc7772313d93026..b9c6b19f11b21dda50f768fc18c6ba38af4a004e 100644
--- a/targets/RT/USER/lte-enb.c
+++ b/targets/RT/USER/lte-enb.c
@@ -1146,7 +1146,7 @@ void init_eNB_afterRU(void) {
 
     for (CC_id=0; CC_id<RC.nb_CC[inst]; CC_id++) {
       LOG_I(PHY,"RC.nb_CC[inst:%d][CC_id:%d]:%p\n", inst, CC_id, RC.eNB[inst][CC_id]);
-      eNB                                  =  RC.eNB[inst][CC_id];
+      eNB = RC.eNB[inst][CC_id];
       phy_init_lte_eNB(eNB,0,0);
 
       // map antennas and PRACH signals to eNB RX
diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c
index 2537299a36c971718cfca8a1d7d99d2471c902d0..1b8e00aed407a3e93bfc430c540fb32e36dad107 100644
--- a/targets/RT/USER/lte-ru.c
+++ b/targets/RT/USER/lte-ru.c
@@ -983,11 +983,9 @@ void wakeup_slaves(RU_proc_t *proc) {
 
     // wake up slave FH thread
     // lock the FH mutex and make sure the thread is ready
-    if (pthread_mutex_timedlock(&slave_proc->mutex_FH,&wait) != 0) {
-      LOG_E( PHY, "ERROR pthread_mutex_lock for RU %d slave %d (IC %d)\n",proc->ru->idx,slave_proc->ru->idx,slave_proc->instance_cnt_FH);
-      exit_fun( "error locking mutex_rxtx" );
-      break;
-    }
+    AssertFatal(pthread_mutex_timedlock(&slave_proc->mutex_FH,&wait) == 0,
+		"ERROR pthread_mutex_lock for RU %d slave %d (IC %d)\n",
+		proc->ru->idx,slave_proc->ru->idx,slave_proc->instance_cnt_FH);
 
     int cnt_slave            = ++slave_proc->instance_cnt_FH;
     slave_proc->frame_rx     = proc->frame_rx;
@@ -1628,7 +1626,6 @@ static void *ru_thread( void *param ) {
   pthread_cond_signal(&proc->cond_FH1);
   wait_sync("ru_thread");
 
-  if(!(get_softmodem_params()->emulate_rf)) {
     // Start RF device if any
     if (ru->start_rf) {
       if (ru->start_rf(ru) != 0)
@@ -1648,12 +1645,9 @@ static void *ru_thread( void *param ) {
 
     // if this is a slave RRU, try to synchronize on the DL frequency
     if ((ru->is_slave) && (ru->if_south == LOCAL_RF)) do_ru_synch(ru);
-  }
 
   // This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices
   while (!oai_exit) {
-    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_CPUID_RU_THREAD,sched_getcpu());
-  LOG_ENTER(PHY);
     // these are local subframe/frame counters to check that we are in synch with the fronthaul timing.
     // They are set on the first rx/tx in the underly FH routines.
     if (subframe==9) {
@@ -1665,37 +1659,9 @@ static void *ru_thread( void *param ) {
     }
 
     // synchronization on input FH interface, acquire signals/data and block
-    if (ru->fh_south_in) ru->fh_south_in(ru,&frame,&subframe);
-    else AssertFatal(1==0, "No fronthaul interface at south port");
-
-#ifdef PHY_TX_THREAD
-
-    if(first_phy_tx == 0) {
-      phy_tx_end = 0;
-      phy_tx_txdataF_end = 0;
-
-      if(pthread_mutex_lock(&ru->proc.mutex_phy_tx) != 0) {
-        LOG_E( PHY, "[RU] ERROR pthread_mutex_lock for phy tx thread (IC %d)\n", ru->proc.instance_cnt_phy_tx);
-        exit_fun( "error locking mutex_rxtx" );
-      }
-
-      if (ru->proc.instance_cnt_phy_tx==-1) {
-        ++ru->proc.instance_cnt_phy_tx;
-        // the thread can now be woken up
-        AssertFatal(pthread_cond_signal(&ru->proc.cond_phy_tx) == 0, "ERROR pthread_cond_signal for phy_tx thread\n");
-      } else {
-        LOG_E(PHY,"phy tx thread busy, skipping\n");
-        ++ru->proc.instance_cnt_phy_tx;
-      }
-
-      pthread_mutex_unlock( &ru->proc.mutex_phy_tx );
-    } else {
-      phy_tx_end = 1;
-      phy_tx_txdataF_end = 1;
-    }
+    AssertFatal(ru->fh_south_in, "No fronthaul interface at south port");
+    ru->fh_south_in(ru,&frame,&subframe);
 
-    first_phy_tx = 0;
-#endif
     LOG_D(PHY,"RU thread (do_prach %d, is_prach_subframe %d), received frame %d, subframe %d\n",
           ru->do_prach,
           is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx),
@@ -1720,72 +1686,26 @@ static void *ru_thread( void *param ) {
 
     // At this point, all information for subframe has been received on FH interface
     // If this proc is to provide synchronization, do so
-    wakeup_slaves(proc);
-#if defined(PRE_SCD_THREAD)
-    new_dlsch_ue_select_tbl_in_use = dlsch_ue_select_tbl_in_use;
-    dlsch_ue_select_tbl_in_use = !dlsch_ue_select_tbl_in_use;
-    memcpy(&pre_scd_eNB_UE_stats,&RC.mac[ru->eNB_list[0]->Mod_id]->UE_list.eNB_UE_stats, sizeof(eNB_UE_STATS)*MAX_NUM_CCs*NUMBER_OF_UE_MAX);
-    memcpy(&pre_scd_activeUE, &RC.mac[ru->eNB_list[0]->Mod_id]->UE_list.active, sizeof(boolean_t)*NUMBER_OF_UE_MAX);
-
-    if (pthread_mutex_lock(&ru->proc.mutex_pre_scd)!= 0) {
-      LOG_E( PHY, "[eNB] error locking proc mutex for eNB pre scd\n");
-      exit_fun("error locking mutex_time");
-    }
-
-    ru->proc.instance_pre_scd++;
-
-    if (ru->proc.instance_pre_scd == 0) {
-      if (pthread_cond_signal(&ru->proc.cond_pre_scd) != 0) {
-        LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB pre scd\n" );
-        exit_fun( "ERROR pthread_cond_signal cond_pre_scd" );
-      }
-    } else {
-      LOG_E( PHY, "[eNB] frame %d subframe %d rxtx busy instance_pre_scd %d\n",
-             frame,subframe,ru->proc.instance_pre_scd );
-    }
-
-    if (pthread_mutex_unlock(&ru->proc.mutex_pre_scd)!= 0) {
-      LOG_E( PHY, "[eNB] error unlocking mutex_pre_scd mutex for eNB pre scd\n");
-      exit_fun("error unlocking mutex_pre_scd");
-    }
-
-#endif
-
-    // wakeup all eNB processes waiting for this RU
-    if (ru->num_eNB>0) wakeup_L1s(ru);
-
-#ifndef PHY_TX_THREAD
-
-    if(get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD || ru->num_eNB==0) {
-      // do TX front-end processing if needed (precoding and/or IDFTs)
-      if (ru->feptx_prec) ru->feptx_prec(ru);
-
-      // do OFDM if needed
-      if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru);
-
-      if(!(get_softmodem_params()->emulate_rf)) {
-        // do outgoing fronthaul (south) if needed
-        if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru);
-
-        if (ru->fh_north_out) ru->fh_north_out(ru);
-      }
-
-      proc->emulate_rf_busy = 0;
-    }
-
-#else
-    struct timespec time_req, time_rem;
-    time_req.tv_sec = 0;
-    time_req.tv_nsec = 10000;
-
-    while((!oai_exit)&&(phy_tx_end == 0)) {
-      nanosleep(&time_req,&time_rem);
-      continue;
-    }
-
-#endif
+    // Fixme: not used
+    // wakeup_slaves(proc);
+    for (int i=0; i<ru->num_eNB; i++) {
+      char string[20];
+      sprintf(string,"Incoming RU %d",ru->idx);
+      ru->eNB_top(ru->eNB_list[i],ru->proc.frame_rx,ru->proc.subframe_rx,string,ru);
+    }
+    
+    // do TX front-end processing if needed (precoding and/or IDFTs)
+    if (ru->feptx_prec) ru->feptx_prec(ru);
+    
+    // do OFDM if needed
+    if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru);
+    // do outgoing fronthaul (south) if needed
+    if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru);
+    
+    if (ru->fh_north_out) ru->fh_north_out(ru);
+    
   }
-
+  
   printf( "Exiting ru_thread \n");
 
   if (!(get_softmodem_params()->emulate_rf)) {
diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c
index 50e866358bd78aca5be4ebcc109ae4895d50db80..f8a42de069b0b46dee356e31be76dc02dd15001e 100644
--- a/targets/RT/USER/lte-softmodem.c
+++ b/targets/RT/USER/lte-softmodem.c
@@ -505,9 +505,7 @@ int main( int argc, char **argv ) {
     }
 
     for (int enb_id = 0; enb_id < RC.nb_inst; enb_id++) {
-      MessageDef *msg_p = itti_alloc_new_message (TASK_ENB_APP, RRC_CONFIGURATION_REQ);
-      RRC_CONFIGURATION_REQ(msg_p) = RC.rrc[enb_id]->configuration;
-      itti_send_msg_to_task (TASK_RRC_ENB, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p);
+      openair_rrc_eNB_configuration(enb_id, &RC.rrc[enb_id]->configuration);
     }
   } else {
     printf("RC.nb_inst = 0, Initializing L1\n");
@@ -530,12 +528,9 @@ int main( int argc, char **argv ) {
     // init UE_PF_PO and mutex lock
     pthread_mutex_init(&ue_pf_po_mutex, NULL);
     memset (&UE_PF_PO[0][0], 0, sizeof(UE_PF_PO_t)*MAX_MOBILES_PER_ENB*MAX_NUM_CCs);
-    mlockall(MCL_CURRENT | MCL_FUTURE);
     pthread_cond_init(&sync_cond,NULL);
     pthread_mutex_init(&sync_mutex, NULL);
 
-
-
     rt_sleep_ns(10*100000000ULL);
 
     if (NFAPI_MODE!=NFAPI_MONOLITHIC) {
@@ -563,9 +558,10 @@ int main( int argc, char **argv ) {
       //  for (CC_id=0;CC_id<RC.nb_L1_CC[inst];CC_id++) phy_init_lte_eNB(RC.eNB[inst][CC_id],0,0);
     }
 
-    printf("wait_eNBs()\n");
-    wait_eNBs();
-    printf("About to Init RU threads RC.nb_RU:%d\n", RC.nb_RU);
+    // no need to wait: openair_rrc_eNB_configuration() is called earlier from this thread
+    // openair_rrc_eNB_configuration()->init_SI()->rrc_mac_config_req_eNB ()->phy_config_request () sets the wait_eNBs() tested flag
+    // wait_eNBs();
+    // printf("About to Init RU threads RC.nb_RU:%d\n", RC.nb_RU);
 
     // RU thread and some L1 procedure aren't necessary in VNF or L2 FAPI simulator.
     // but RU thread deals with pre_scd and this is necessary in VNF and simulator.
@@ -588,6 +584,9 @@ int main( int argc, char **argv ) {
 
     printf("wait RUs\n");
     // end of CI modifications
+    // fixme: very weird usage of bitmask
+    // lack of mutex in: ru_thread_prach(),...
+    // wait_RUs() is wrong and over complex!
     wait_RUs();
     LOG_I(ENB_APP,"RC.nb_RU:%d\n", RC.nb_RU);
     // once all RUs are ready intiailize the rest of the eNBs ((dependence on final RU parameters after configuration)