From ec67c1c93c7a18d25875c05d9d36ad3ed7b4b759 Mon Sep 17 00:00:00 2001
From: matzakos <panagiotis.matzakos@eurecom.fr>
Date: Fri, 1 Dec 2017 20:05:40 +0100
Subject: [PATCH] Introduce new executable for the UE (nfapi pnf in stub mode)
 lte-softmodem-stub

---
 cmake_targets/CMakeLists.txt                  |   48 +-
 cmake_targets/build_oai                       |    1 +
 nfapi/nfapi_pnf.c                             |   13 +-
 openair1/PHY/defs.h                           |    1 +
 openair2/ENB_APP/enb_config.c                 |   18 +-
 openair2/ENB_APP/enb_config.h                 |    3 +
 .../CONF/oaiL1.nfapi.usrpb210.conf            |    6 +-
 targets/RT/USER/lte-enb.c                     |    3 +-
 targets/RT/USER/lte-softmodem-stub.c          | 1551 +++++++++++++++++
 targets/RT/USER/lte-softmodem.c               |    3 +-
 targets/RT/USER/lte-ue.c                      |   16 +-
 11 files changed, 1649 insertions(+), 14 deletions(-)
 create mode 100644 targets/RT/USER/lte-softmodem-stub.c

diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index b8ab24f9fa0..4346d758e6e 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -1889,6 +1889,52 @@ target_link_libraries (lte-softmodem pthread m ${CONFIG_LIBRARIES} rt crypt ${CR
 target_link_libraries (lte-softmodem ${LIB_LMS_LIBRARIES})
 target_link_libraries (lte-softmodem ${T_LIB})
 
+
+
+
+# lte-softmodem-stub is both eNB and UE implementation
+###################################################
+
+add_executable(lte-softmodem-stub
+  ${rrc_h}
+  ${s1ap_h}
+  ${OPENAIR_BIN_DIR}/messages_xml.h
+  ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c
+  ${OPENAIR_TARGETS}/RT/USER/lte-ue.c
+  ${OPENAIR_TARGETS}/RT/USER/lte-enb.c
+  ${OPENAIR_TARGETS}/RT/USER/lte-softmodem-stub.c
+  ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c
+  ${OPENAIR_TARGETS}/SIMU/USER/init_lte.c
+  ${OPENAIR_TARGETS}/COMMON/create_tasks.c
+  ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c
+  ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c
+  ${OPENAIR3_DIR}/NAS/UE/nas_ue_task.c
+  ${OPENAIR_DIR}/common/utils/utils.c
+  ${OPENAIR_DIR}/common/utils/system.c
+  ${GTPU_need_ITTI}
+  ${RTAI_SOURCE}
+  ${XFORMS_SOURCE}
+  ${XFORMS_SOURCE_SOFTMODEM}
+  ${T_SOURCE}
+  ${CONFIG_SOURCES}
+  ${SHLIB_LOADER_SOURCES}
+  )
+
+target_link_libraries (lte-softmodem-stub
+  -Wl,--start-group
+  RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${MIH_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_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 (lte-softmodem-stub ${LIBXML2_LIBRARIES})
+target_link_libraries (lte-softmodem-stub pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp  ${XFORMS_LIBRARIES} ${PROTOBUF_LIB}  ${CMAKE_DL_LIBS} ${LIBYAML_LIBRARIES})
+target_link_libraries (lte-softmodem-stub ${LIB_LMS_LIBRARIES})
+target_link_libraries (lte-softmodem-stub ${T_LIB})
+
+
+
+
 # lte-softmodem-nos1 is both eNB and UE implementation
 ###################################################
 add_executable(lte-softmodem-nos1
@@ -2181,7 +2227,7 @@ endforeach(myExe)
 if (${T_TRACER})
   foreach(i
         #all "add_executable" definitions (except tests, rb_tool, updatefw)
-        lte-softmodem lte-softmodem-nos1 rrh_gw oaisim oaisim_nos1
+        lte-softmodem lte-softmodem-stub lte-softmodem-nos1 rrh_gw oaisim oaisim_nos1
         dlsim_tm4 dlsim dlsim_tm7 ulsim pbchsim scansim mbmssim
         pdcchsim pucchsim prachsim syncsim
         #all "add_library" definitions
diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai
index 1ff853d58fb..a5d47a41587 100755
--- a/cmake_targets/build_oai
+++ b/cmake_targets/build_oai
@@ -506,6 +506,7 @@ function main() {
   else
       lte_build_dir=lte_build_oai
       lte_exec=lte-softmodem
+      #lte_exec=lte-softmodem-stub
   fi
 
 # configuration module libraries, one currently available, using libconfig 
diff --git a/nfapi/nfapi_pnf.c b/nfapi/nfapi_pnf.c
index 9ba66684a4a..3973315a6f8 100644
--- a/nfapi/nfapi_pnf.c
+++ b/nfapi/nfapi_pnf.c
@@ -38,8 +38,10 @@ extern pthread_mutex_t nfapi_sync_mutex;
 extern int nfapi_sync_var;
 
 extern int sync_var;
+char uecap_xer_in;
 
 extern void init_eNB_afterRU(void);
+extern void init_UE_stub(int nb_inst,int,int);
 extern void handle_nfapi_dci_dl_pdu(PHY_VARS_eNB *eNB, eNB_rxtx_proc_t *proc, nfapi_dl_config_request_pdu_t *dl_config_pdu);
 extern void handle_nfapi_ul_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, nfapi_ul_config_request_pdu_t *ul_config_pdu, uint16_t frame,uint8_t subframe,uint8_t srs_present);
 extern void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,  nfapi_dl_config_request_pdu_t *dl_config_pdu, uint8_t codeword_index, uint8_t *sdu);
@@ -1409,7 +1411,16 @@ int start_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi
     //phy_init_RU(RC.ru[0]);
 
     printf("[PNF] About to call init_eNB_afterRU()\n");
-    init_eNB_afterRU();
+
+    // Panos: Instead
+    /*if (nfapi_mode == 3) {
+    	init_UE_stub(1,0,uecap_xer_in);
+    }*/
+    //else{
+    if (nfapi_mode != 3) {
+    	// Panos
+    	init_eNB_afterRU();
+    }
 
     // Signal to main thread that it can carry on - otherwise RU will startup too quickly and it is not initialised
     {
diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h
index 462f5c45eb8..d10af0de34c 100644
--- a/openair1/PHY/defs.h
+++ b/openair1/PHY/defs.h
@@ -654,6 +654,7 @@ typedef struct {
 
 /// Panos: Structure holding timer_thread related elements (phy_stub_UE mode)
 typedef struct{
+	pthread_t pthread_timer;
 	/// Panos: mutex for waiting SF ticking
 	pthread_mutex_t mutex_ticking;
 	/// Panos: \brief ticking var for ticking thread.
diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c
index 0d6a5eb8990..1bcfce02927 100644
--- a/openair2/ENB_APP/enb_config.c
+++ b/openair2/ENB_APP/enb_config.c
@@ -253,17 +253,28 @@ void UE_config_stub_pnf(void) {
 		  // Panos: Right now that we have only one UE (thread) it is ok to put the eth_params in the UE_mac_inst.
 		  // Later I think we have to change that to attribute eth_params to a global element for all the UEs.
 		  else if (strcmp(*(L1_ParamList.paramarray[j][L1_TRANSPORT_N_PREFERENCE_IDX].strptr), "nfapi") == 0) {
-			  UE_mac_inst[0].eth_params_n.local_if_name            = strdup(*(L1_ParamList.paramarray[j][L1_LOCAL_N_IF_NAME_IDX].strptr));
+			  stub_eth_params.local_if_name            = strdup(*(L1_ParamList.paramarray[j][L1_LOCAL_N_IF_NAME_IDX].strptr));
+			  stub_eth_params.my_addr                  = strdup(*(L1_ParamList.paramarray[j][L1_LOCAL_N_ADDRESS_IDX].strptr));
+			  stub_eth_params.remote_addr              = strdup(*(L1_ParamList.paramarray[j][L1_REMOTE_N_ADDRESS_IDX].strptr));
+			  stub_eth_params.my_portc                 = *(L1_ParamList.paramarray[j][L1_LOCAL_N_PORTC_IDX].iptr);
+			  stub_eth_params.remote_portc             = *(L1_ParamList.paramarray[j][L1_REMOTE_N_PORTC_IDX].iptr);
+			  stub_eth_params.my_portd                 = *(L1_ParamList.paramarray[j][L1_LOCAL_N_PORTD_IDX].iptr);
+			  stub_eth_params.remote_portd             = *(L1_ParamList.paramarray[j][L1_REMOTE_N_PORTD_IDX].iptr);
+			  stub_eth_params.transp_preference        = ETH_UDP_MODE;
+
+
+			  /*UE_mac_inst[0].eth_params_n.local_if_name            = strdup(*(L1_ParamList.paramarray[j][L1_LOCAL_N_IF_NAME_IDX].strptr));
 			  UE_mac_inst[0].eth_params_n.my_addr                  = strdup(*(L1_ParamList.paramarray[j][L1_LOCAL_N_ADDRESS_IDX].strptr));
 			  UE_mac_inst[0].eth_params_n.remote_addr              = strdup(*(L1_ParamList.paramarray[j][L1_REMOTE_N_ADDRESS_IDX].strptr));
 			  UE_mac_inst[0].eth_params_n.my_portc                 = *(L1_ParamList.paramarray[j][L1_LOCAL_N_PORTC_IDX].iptr);
 			  UE_mac_inst[0].eth_params_n.remote_portc             = *(L1_ParamList.paramarray[j][L1_REMOTE_N_PORTC_IDX].iptr);
 			  UE_mac_inst[0].eth_params_n.my_portd                 = *(L1_ParamList.paramarray[j][L1_LOCAL_N_PORTD_IDX].iptr);
 			  UE_mac_inst[0].eth_params_n.remote_portd             = *(L1_ParamList.paramarray[j][L1_REMOTE_N_PORTD_IDX].iptr);
-			  UE_mac_inst[0].eth_params_n.transp_preference        = ETH_UDP_MODE;
+			  UE_mac_inst[0].eth_params_n.transp_preference        = ETH_UDP_MODE;*/
 
 			  sf_ahead = 4; // Cannot cope with 4 subframes betweem RX and TX - set it to 2
-			  configure_nfapi_pnf(UE_mac_inst[0].eth_params_n.remote_addr, UE_mac_inst[0].eth_params_n.remote_portc, UE_mac_inst[0].eth_params_n.my_addr, UE_mac_inst[0].eth_params_n.my_portd, UE_mac_inst[0].eth_params_n.remote_portd);
+			  //configure_nfapi_pnf(UE_mac_inst[0].eth_params_n.remote_addr, UE_mac_inst[0].eth_params_n.remote_portc, UE_mac_inst[0].eth_params_n.my_addr, UE_mac_inst[0].eth_params_n.my_portd, UE_mac_inst[0].eth_params_n.remote_portd);
+			  configure_nfapi_pnf(stub_eth_params.remote_addr, stub_eth_params.remote_portc, stub_eth_params.my_addr, stub_eth_params.my_portd, stub_eth_params.remote_portd);
 		  }
 		  else { // other midhaul
 		  }
@@ -2934,7 +2945,6 @@ void RCConfig(void) {
     RC.nb_macrlc_inst  = MACRLCParamList.numelt;
     // Get num L1 instances
     config_getlist( &L1ParamList,NULL,0, NULL);
-    //config_getlist( &L1_ParamList,L1_Params,sizeof(L1_Params)/sizeof(paramdef_t), NULL);
     RC.nb_L1_inst = L1ParamList.numelt;
 
     // Get num RU instances
diff --git a/openair2/ENB_APP/enb_config.h b/openair2/ENB_APP/enb_config.h
index 0406e11e4cd..758e35ce6c2 100644
--- a/openair2/ENB_APP/enb_config.h
+++ b/openair2/ENB_APP/enb_config.h
@@ -93,9 +93,12 @@ typedef struct ru_config_s {
   uint8_t   if_compress;
 } ru_config_t;
 
+eth_params_t         stub_eth_params;
+
 extern void RCconfig_RU(void);
 extern void RCconfig_L1(void);
 extern void RCconfig_macrlc(void);
+extern void UE_config_stub_pnf(void);
 extern int  RCconfig_gtpu(void );
 extern void RCConfig(void);
 
diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/oaiL1.nfapi.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/oaiL1.nfapi.usrpb210.conf
index 88d653b7b2e..251243c632e 100644
--- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/oaiL1.nfapi.usrpb210.conf
+++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/oaiL1.nfapi.usrpb210.conf
@@ -19,9 +19,9 @@ L1s = (
     	{
 	num_cc = 1;
 	tr_n_preference = "nfapi";
-      	local_n_if_name  = "eno1";
-      	remote_n_address = "192.168.1.28";
-    	local_n_address  = "192.168.1.74";
+      	local_n_if_name  = "eth0";
+      	remote_n_address = "10.0.0.20";
+    	local_n_address  = "10.0.0.10";
     	local_n_portc    = 50000;
     	remote_n_portc   = 50001;
     	local_n_portd    = 50010;
diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c
index 070a768ec53..e6778859e34 100644
--- a/targets/RT/USER/lte-enb.c
+++ b/targets/RT/USER/lte-enb.c
@@ -121,7 +121,8 @@ extern int transmission_mode;
 
 extern int oaisim_flag;
 
-uint16_t sf_ahead=4;
+//uint16_t sf_ahead=4;
+extern uint16_t sf_ahead;
 
 //pthread_t                       main_eNB_thread;
 
diff --git a/targets/RT/USER/lte-softmodem-stub.c b/targets/RT/USER/lte-softmodem-stub.c
new file mode 100644
index 00000000000..d9ed9f408f8
--- /dev/null
+++ b/targets/RT/USER/lte-softmodem-stub.c
@@ -0,0 +1,1551 @@
+/*
+ * lte-softmodem-stub.c
+ *
+ *  Created on: Nov 27, 2017
+ *      Author: montre
+ */
+
+
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+
+/*! \file lte-enb.c
+ * \brief Top-level threads for eNodeB
+ * \author R. Knopp, F. Kaltenberger, Navid Nikaein
+ * \date 2012
+ * \version 0.1
+ * \company Eurecom
+ * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr, navid.nikaein@eurecom.fr
+ * \note
+ * \warning
+ */
+
+
+#define _GNU_SOURCE             /* See feature_test_macros(7) */
+#include <sched.h>
+
+
+#include "T.h"
+
+#include "rt_wrapper.h"
+
+
+#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all
+
+#include "assertions.h"
+#include "msc.h"
+
+#include "PHY/types.h"
+
+#include "PHY/defs.h"
+#include "common/ran_context.h"
+#include "common/config/config_userapi.h"
+#include "common/utils/load_module_shlib.h"
+#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all
+//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all
+
+#include "../../ARCH/COMMON/common_lib.h"
+#include "../../ARCH/ETHERNET/USERSPACE/LIB/if_defs.h"
+
+//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all
+
+#include "PHY/vars.h"
+#include "SCHED/vars.h"
+#include "LAYER2/MAC/vars.h"
+
+#include "../../SIMU/USER/init_lte.h"
+
+#include "LAYER2/MAC/defs.h"
+#include "LAYER2/MAC/vars.h"
+#include "LAYER2/MAC/proto.h"
+#include "RRC/LITE/vars.h"
+#include "PHY_INTERFACE/vars.h"
+
+#ifdef SMBV
+#include "PHY/TOOLS/smbv.h"
+unsigned short config_frames[4] = {2,9,11,13};
+#endif
+#include "UTIL/LOG/log_extern.h"
+#include "UTIL/OTG/otg_tx.h"
+#include "UTIL/OTG/otg_externs.h"
+#include "UTIL/MATH/oml.h"
+#include "UTIL/LOG/vcd_signal_dumper.h"
+#include "UTIL/OPT/opt.h"
+#include "enb_config.h"
+//#include "PHY/TOOLS/time_meas.h"
+
+#ifndef OPENAIR2
+#include "UTIL/OTG/otg_vars.h"
+#endif
+
+#if defined(ENABLE_ITTI)
+#include "intertask_interface_init.h"
+#include "create_tasks.h"
+#endif
+
+#include "system.h"
+
+#ifdef XFORMS
+#include "PHY/TOOLS/lte_phy_scope.h"
+#include "stats.h"
+#endif
+#include "lte-softmodem.h"
+
+#ifdef XFORMS
+// current status is that every UE has a DL scope for a SINGLE eNB (eNB_id=0)
+// at eNB 0, an UL scope for every UE
+FD_lte_phy_scope_ue  *form_ue[NUMBER_OF_UE_MAX];
+FD_lte_phy_scope_enb *form_enb[MAX_NUM_CCs][NUMBER_OF_UE_MAX];
+FD_stats_form                  *form_stats=NULL,*form_stats_l2=NULL;
+char title[255];
+unsigned char                   scope_enb_num_ue = 2;
+static pthread_t                forms_thread; //xforms
+#endif //XFORMS
+
+pthread_cond_t nfapi_sync_cond;
+pthread_mutex_t nfapi_sync_mutex;
+int nfapi_sync_var=-1; //!< protected by mutex \ref nfapi_sync_mutex
+
+uint8_t nfapi_mode = 3;
+
+uint16_t sf_ahead=4;
+
+pthread_cond_t sync_cond;
+pthread_mutex_t sync_mutex;
+int sync_var=-1; //!< protected by mutex \ref sync_mutex.
+int config_sync_var=-1;
+
+uint16_t runtime_phy_rx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100]
+uint16_t runtime_phy_tx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100]
+
+#if defined(ENABLE_ITTI)
+volatile int             start_eNB = 0;
+volatile int             start_UE = 0;
+#endif
+volatile int             oai_exit = 0;
+
+static clock_source_t clock_source = internal;
+static int wait_for_sync = 0;
+
+static char              UE_flag=0;
+unsigned int                    mmapped_dma=0;
+int                             single_thread_flag=1;
+
+static char                     threequarter_fs=0;
+
+uint32_t                 downlink_frequency[MAX_NUM_CCs][4];
+int32_t                  uplink_frequency_offset[MAX_NUM_CCs][4];
+
+
+
+#if defined(ENABLE_ITTI)
+static char                    *itti_dump_file = NULL;
+#endif
+
+int UE_scan = 1;
+int UE_scan_carrier = 0;
+runmode_t mode = normal_txrx;
+
+FILE *input_fd=NULL;
+
+
+#if MAX_NUM_CCs == 1
+rx_gain_t                rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain}};
+double tx_gain[MAX_NUM_CCs][4] = {{20,0,0,0}};
+double rx_gain[MAX_NUM_CCs][4] = {{110,0,0,0}};
+#else
+rx_gain_t                rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain},{max_gain,max_gain,max_gain,max_gain}};
+double tx_gain[MAX_NUM_CCs][4] = {{20,0,0,0},{20,0,0,0}};
+double rx_gain[MAX_NUM_CCs][4] = {{110,0,0,0},{20,0,0,0}};
+#endif
+
+double rx_gain_off = 0.0;
+
+double sample_rate=30.72e6;
+double bw = 10.0e6;
+
+static int                      tx_max_power[MAX_NUM_CCs]; /* =  {0,0}*/;
+
+char   rf_config_file[1024];
+
+int chain_offset=0;
+int phy_test = 0;
+uint8_t usim_test = 0;
+
+uint8_t dci_Format = 0;
+uint8_t agregation_Level =0xFF;
+
+uint8_t nb_antenna_tx = 1;
+uint8_t nb_antenna_rx = 1;
+
+char ref[128] = "internal";
+char channels[128] = "0";
+
+int                      rx_input_level_dBm;
+
+#ifdef XFORMS
+extern int                      otg_enabled;
+static char                     do_forms=0;
+#else
+int                             otg_enabled;
+#endif
+//int                             number_of_cards =   1;
+
+
+static LTE_DL_FRAME_PARMS      *frame_parms[MAX_NUM_CCs];
+uint32_t target_dl_mcs = 28; //maximum allowed mcs
+uint32_t target_ul_mcs = 20;
+uint32_t timing_advance = 0;
+uint8_t exit_missed_slots=1;
+uint64_t num_missed_slots=0; // counter for the number of missed slots
+
+
+extern void reset_opp_meas(void);
+extern void print_opp_meas(void);
+
+extern PHY_VARS_UE* init_ue_vars(LTE_DL_FRAME_PARMS *frame_parms,
+			  uint8_t UE_id,
+			  uint8_t abstraction_flag);
+
+extern void init_eNB_afterRU(void);
+extern void init_UE_stub(int nb_inst,int,int);
+extern int init_timer_thread(void);
+
+int transmission_mode=1;
+
+
+
+/* struct for ethernet specific parameters given in eNB conf file */
+eth_params_t *eth_params;
+
+openair0_config_t openair0_cfg[MAX_CARDS];
+
+double cpuf;
+
+extern char uecap_xer[1024];
+char uecap_xer_in=0;
+
+int oaisim_flag=0;
+threads_t threads= {-1,-1,-1,-1,-1,-1,-1};
+
+/* see file openair2/LAYER2/MAC/main.c for why abstraction_flag is needed
+ * this is very hackish - find a proper solution
+ */
+uint8_t abstraction_flag=0;
+
+/*---------------------BMC: timespec helpers -----------------------------*/
+
+struct timespec min_diff_time = { .tv_sec = 0, .tv_nsec = 0 };
+struct timespec max_diff_time = { .tv_sec = 0, .tv_nsec = 0 };
+
+struct timespec clock_difftime(struct timespec start, struct timespec end) {
+  struct timespec temp;
+  if ((end.tv_nsec-start.tv_nsec)<0) {
+    temp.tv_sec = end.tv_sec-start.tv_sec-1;
+    temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
+  } else {
+    temp.tv_sec = end.tv_sec-start.tv_sec;
+    temp.tv_nsec = end.tv_nsec-start.tv_nsec;
+  }
+  return temp;
+}
+
+void print_difftimes(void) {
+#ifdef DEBUG
+  printf("difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec);
+#else
+  LOG_I(HW,"difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec);
+#endif
+}
+
+void update_difftimes(struct timespec start, struct timespec end) {
+  struct timespec diff_time = { .tv_sec = 0, .tv_nsec = 0 };
+  int             changed = 0;
+  diff_time = clock_difftime(start, end);
+  if ((min_diff_time.tv_nsec == 0) || (diff_time.tv_nsec < min_diff_time.tv_nsec)) {
+    min_diff_time.tv_nsec = diff_time.tv_nsec;
+    changed = 1;
+  }
+  if ((max_diff_time.tv_nsec == 0) || (diff_time.tv_nsec > max_diff_time.tv_nsec)) {
+    max_diff_time.tv_nsec = diff_time.tv_nsec;
+    changed = 1;
+  }
+#if 1
+  if (changed) print_difftimes();
+#endif
+}
+
+/*------------------------------------------------------------------------*/
+
+unsigned int build_rflocal(int txi, int txq, int rxi, int rxq) {
+  return (txi + (txq<<6) + (rxi<<12) + (rxq<<18));
+}
+unsigned int build_rfdc(int dcoff_i_rxfe, int dcoff_q_rxfe) {
+  return (dcoff_i_rxfe + (dcoff_q_rxfe<<8));
+}
+
+#if !defined(ENABLE_ITTI)
+void signal_handler(int sig) {
+  void *array[10];
+  size_t size;
+
+  if (sig==SIGSEGV) {
+    // get void*'s for all entries on the stack
+    size = backtrace(array, 10);
+
+    // print out all the frames to stderr
+    fprintf(stderr, "Error: signal %d:\n", sig);
+    backtrace_symbols_fd(array, size, 2);
+    exit(-1);
+  } else {
+    printf("trying to exit gracefully...\n");
+    oai_exit = 1;
+  }
+}
+#endif
+#define KNRM  "\x1B[0m"
+#define KRED  "\x1B[31m"
+#define KGRN  "\x1B[32m"
+#define KBLU  "\x1B[34m"
+#define RESET "\033[0m"
+
+
+
+void exit_fun(const char* s)
+{
+  int CC_id;
+  int ru_id;
+
+  if (s != NULL) {
+    printf("%s %s() Exiting OAI softmodem: %s\n",__FILE__, __FUNCTION__, s);
+  }
+
+  oai_exit = 1;
+
+  if (UE_flag==0) {
+    for (ru_id=0; ru_id<RC.nb_RU;ru_id++) {
+      if (RC.ru[ru_id]->rfdevice.trx_end_func)
+	RC.ru[ru_id]->rfdevice.trx_end_func(&RC.ru[ru_id]->rfdevice);
+      if (RC.ru[ru_id]->ifdevice.trx_end_func)
+	RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice);
+    }
+  }
+
+  for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
+
+    oai_exit = 1;
+
+    for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
+      if (UE_flag == 0) {
+      } else {
+	if (PHY_vars_UE_g[0][CC_id]->rfdevice.trx_end_func)
+	  PHY_vars_UE_g[0][CC_id]->rfdevice.trx_end_func(&PHY_vars_UE_g[0][CC_id]->rfdevice);
+      }
+    }
+
+#if defined(ENABLE_ITTI)
+    sleep(1); //allow lte-softmodem threads to exit first
+    itti_terminate_tasks (TASK_UNKNOWN);
+#endif
+
+  }
+
+}
+
+#ifdef XFORMS
+
+
+void reset_stats(FL_OBJECT *button, long arg)
+{
+  int i,j,k;
+  PHY_VARS_eNB *phy_vars_eNB = RC.eNB[0][0];
+
+  for (i=0; i<NUMBER_OF_UE_MAX; i++) {
+    for (k=0; k<8; k++) { //harq_processes
+      for (j=0; j<phy_vars_eNB->dlsch[i][0]->Mlimit; j++) {
+	phy_vars_eNB->UE_stats[i].dlsch_NAK[k][j]=0;
+	phy_vars_eNB->UE_stats[i].dlsch_ACK[k][j]=0;
+	phy_vars_eNB->UE_stats[i].dlsch_trials[k][j]=0;
+      }
+
+      phy_vars_eNB->UE_stats[i].dlsch_l2_errors[k]=0;
+      phy_vars_eNB->UE_stats[i].ulsch_errors[k]=0;
+      phy_vars_eNB->UE_stats[i].ulsch_consecutive_errors=0;
+
+
+      phy_vars_eNB->UE_stats[i].dlsch_sliding_cnt=0;
+      phy_vars_eNB->UE_stats[i].dlsch_NAK_round0=0;
+      phy_vars_eNB->UE_stats[i].dlsch_mcs_offset=0;
+    }
+  }
+}
+
+static void *scope_thread(void *arg) {
+  char stats_buffer[16384];
+# ifdef ENABLE_XFORMS_WRITE_STATS
+  FILE *UE_stats, *eNB_stats;
+# endif
+  struct sched_param sched_param;
+  int UE_id, CC_id;
+  int ue_cnt=0;
+
+  sched_param.sched_priority = sched_get_priority_min(SCHED_FIFO)+1;
+  sched_setscheduler(0, SCHED_FIFO,&sched_param);
+
+  printf("Scope thread has priority %d\n",sched_param.sched_priority);
+
+# ifdef ENABLE_XFORMS_WRITE_STATS
+
+  if (UE_flag==1)
+    UE_stats  = fopen("UE_stats.txt", "w");
+  else
+    eNB_stats = fopen("eNB_stats.txt", "w");
+
+#endif
+
+  while (!oai_exit) {
+    if (UE_flag==1) {
+      dump_ue_stats (PHY_vars_UE_g[0][0], &PHY_vars_UE_g[0][0]->proc.proc_rxtx[0],stats_buffer, 0, mode,rx_input_level_dBm);
+      //fl_set_object_label(form_stats->stats_text, stats_buffer);
+      fl_clear_browser(form_stats->stats_text);
+      fl_add_browser_line(form_stats->stats_text, stats_buffer);
+
+      phy_scope_UE(form_ue[0],
+		   PHY_vars_UE_g[0][0],
+		   0,
+		   0,7);
+
+
+    } else {
+      /*
+	if (RC.eNB[0][0]->mac_enabled==1) {
+	len = dump_eNB_l2_stats (stats_buffer, 0);
+	//fl_set_object_label(form_stats_l2->stats_text, stats_buffer);
+	fl_clear_browser(form_stats_l2->stats_text);
+	fl_add_browser_line(form_stats_l2->stats_text, stats_buffer);
+	}
+	len = dump_eNB_stats (RC.eNB[0][0], stats_buffer, 0);
+
+	if (MAX_NUM_CCs>1)
+	len += dump_eNB_stats (RC.eNB[0][1], &stats_buffer[len], 0);
+
+	//fl_set_object_label(form_stats->stats_text, stats_buffer);
+	fl_clear_browser(form_stats->stats_text);
+	fl_add_browser_line(form_stats->stats_text, stats_buffer);
+      */
+      ue_cnt=0;
+      for(UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) {
+	for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
+	  //	  if ((RC.eNB[0][CC_id]->dlsch[UE_id][0]->rnti>0) && (ue_cnt<scope_enb_num_ue)) {
+	  if ((ue_cnt<scope_enb_num_ue)) {
+	    phy_scope_eNB(form_enb[CC_id][ue_cnt],
+			  RC.eNB[0][CC_id],
+			  UE_id);
+	    ue_cnt++;
+	  }
+	}
+      }
+
+    }
+
+    //printf("doing forms\n");
+    //usleep(100000); // 100 ms
+    sleep(1);
+  }
+
+  //  printf("%s",stats_buffer);
+
+# ifdef ENABLE_XFORMS_WRITE_STATS
+
+  if (UE_flag==1) {
+    if (UE_stats) {
+      rewind (UE_stats);
+      fwrite (stats_buffer, 1, len, UE_stats);
+      fclose (UE_stats);
+    }
+  } else {
+    if (eNB_stats) {
+      rewind (eNB_stats);
+      fwrite (stats_buffer, 1, len, eNB_stats);
+      fclose (eNB_stats);
+    }
+  }
+
+# endif
+
+  pthread_exit((void*)arg);
+}
+#endif
+
+
+
+
+#if defined(ENABLE_ITTI)
+void *l2l1_task(void *arg) {
+  MessageDef *message_p = NULL;
+  int         result;
+
+  itti_set_task_real_time(TASK_L2L1);
+  itti_mark_task_ready(TASK_L2L1);
+
+  if (UE_flag == 0) {
+    /* Wait for the initialize message */
+    printf("Wait for the ITTI initialize message\n");
+    do {
+      if (message_p != NULL) {
+	result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p);
+	AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
+      }
+
+      itti_receive_msg (TASK_L2L1, &message_p);
+
+      switch (ITTI_MSG_ID(message_p)) {
+      case INITIALIZE_MESSAGE:
+	/* Start eNB thread */
+	LOG_D(EMU, "L2L1 TASK received %s\n", ITTI_MSG_NAME(message_p));
+	start_eNB = 1;
+	break;
+
+      case TERMINATE_MESSAGE:
+	printf("received terminate message\n");
+	oai_exit=1;
+	itti_exit_task ();
+	break;
+
+      default:
+	LOG_E(EMU, "Received unexpected message %s\n", ITTI_MSG_NAME(message_p));
+	break;
+      }
+    } while (ITTI_MSG_ID(message_p) != INITIALIZE_MESSAGE);
+
+    result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p);
+    AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
+  }
+
+  do {
+    // Wait for a message
+    itti_receive_msg (TASK_L2L1, &message_p);
+
+    switch (ITTI_MSG_ID(message_p)) {
+    case TERMINATE_MESSAGE:
+      oai_exit=1;
+      itti_exit_task ();
+      break;
+
+    case ACTIVATE_MESSAGE:
+      start_UE = 1;
+      break;
+
+    case DEACTIVATE_MESSAGE:
+      start_UE = 0;
+      break;
+
+    case MESSAGE_TEST:
+      LOG_I(EMU, "Received %s\n", ITTI_MSG_NAME(message_p));
+      break;
+
+    default:
+      LOG_E(EMU, "Received unexpected message %s\n", ITTI_MSG_NAME(message_p));
+      break;
+    }
+
+    result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p);
+    AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
+  } while(!oai_exit);
+
+  return NULL;
+}
+#endif
+
+void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]);
+void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) {
+
+  int CC_id;
+  printf("Panos: set_default_frame_parms1 %d \n",MAX_NUM_CCs);
+
+  for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
+    frame_parms[CC_id] = (LTE_DL_FRAME_PARMS*) malloc(sizeof(LTE_DL_FRAME_PARMS));
+    /* Set some default values that may be overwritten while reading options */
+    frame_parms[CC_id]->frame_type          = FDD;
+    frame_parms[CC_id]->tdd_config          = 3;
+    frame_parms[CC_id]->tdd_config_S        = 0;
+    frame_parms[CC_id]->N_RB_DL             = 100;
+
+    frame_parms[CC_id]->N_RB_UL             = 100;
+    frame_parms[CC_id]->Ncp                 = NORMAL;
+    frame_parms[CC_id]->Ncp_UL              = NORMAL;
+    frame_parms[CC_id]->Nid_cell            = 0;
+    frame_parms[CC_id]->num_MBSFN_config    = 0;
+    frame_parms[CC_id]->nb_antenna_ports_eNB  = 1;
+    frame_parms[CC_id]->nb_antennas_tx      = 1;
+    frame_parms[CC_id]->nb_antennas_rx      = 1;
+
+    frame_parms[CC_id]->nushift             = 0;
+
+    frame_parms[CC_id]->phich_config_common.phich_resource = oneSixth;
+    frame_parms[CC_id]->phich_config_common.phich_duration = normal;
+    // UL RS Config
+    frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift = 0;//n_DMRS1 set to 0
+    frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled = 0;
+    frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled = 0;
+    frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH = 0;
+
+    frame_parms[CC_id]->prach_config_common.rootSequenceIndex=22;
+    frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig=1;
+    frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_ConfigIndex=0;
+    frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.highSpeedFlag=0;
+    frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_FreqOffset=0;
+
+    downlink_frequency[CC_id][0] = 2680000000; // Use float to avoid issue with frequency over 2^31.
+    downlink_frequency[CC_id][1] = downlink_frequency[CC_id][0];
+    downlink_frequency[CC_id][2] = downlink_frequency[CC_id][0];
+    downlink_frequency[CC_id][3] = downlink_frequency[CC_id][0];
+    //printf("Downlink for CC_id %d frequency set to %u\n", CC_id, downlink_frequency[CC_id][0]);
+
+  }
+
+}
+
+
+static void get_options(void) {
+  int CC_id;
+  int tddflag;
+  char *loopfile=NULL;
+  int dumpframe;
+  uint32_t online_log_messages;
+  uint32_t glog_level, glog_verbosity;
+  uint32_t start_telnetsrv;
+  printf("Panos: get_options 1 \n");
+
+  paramdef_t cmdline_params[] =CMDLINE_PARAMS_DESC ;
+  paramdef_t cmdline_logparams[] =CMDLINE_LOGPARAMS_DESC ;
+
+  config_process_cmdline( cmdline_params,sizeof(cmdline_params)/sizeof(paramdef_t),NULL);
+  printf("get_options 0, UE_flag: %d", UE_flag);
+
+  printf("Panos: get_options 2 \n");
+  if (strlen(in_path) > 0) {
+      opt_type = OPT_PCAP;
+      opt_enabled=1;
+      printf("Enabling OPT for PCAP  with the following file %s \n",in_path);
+  }
+  if (strlen(in_ip) > 0) {
+      opt_enabled=1;
+      opt_type = OPT_WIRESHARK;
+      printf("Enabling OPT for wireshark for local interface");
+  }
+  printf("Panos: get_options 3 \n");
+  config_process_cmdline( cmdline_logparams,sizeof(cmdline_logparams)/sizeof(paramdef_t),NULL);
+  if(config_isparamset(cmdline_logparams,CMDLINE_ONLINELOG_IDX)) {
+      set_glog_onlinelog(online_log_messages);
+  }
+  if(config_isparamset(cmdline_logparams,CMDLINE_GLOGLEVEL_IDX)) {
+      set_glog(glog_level, -1);
+  }
+  if(config_isparamset(cmdline_logparams,CMDLINE_GLOGVERBO_IDX)) {
+      set_glog(-1, glog_verbosity);
+  }
+  if (start_telnetsrv) {
+     load_module_shlib("telnetsrv",NULL,0);
+  }
+
+  printf("Panos: get_options 4 \n");
+  if (UE_flag > 0) {
+	  // set default parameters
+	  set_default_frame_parms(frame_parms);
+     paramdef_t cmdline_uemodeparams[] =CMDLINE_UEMODEPARAMS_DESC;
+     paramdef_t cmdline_ueparams[] =CMDLINE_UEPARAMS_DESC;
+     printf("Panos: get_options 5 \n");
+
+
+     config_process_cmdline( cmdline_uemodeparams,sizeof(cmdline_uemodeparams)/sizeof(paramdef_t),NULL);
+     config_process_cmdline( cmdline_ueparams,sizeof(cmdline_ueparams)/sizeof(paramdef_t),NULL);
+     printf("Panos: get_options 6 \n");
+      if (loopfile != NULL) {
+  	  printf("Input file for hardware emulation: %s",loopfile);
+  	  mode=loop_through_memory;
+  	  input_fd = fopen(loopfile,"r");
+  	  AssertFatal(input_fd != NULL,"Please provide a valid input file\n");
+      }
+      printf("Panos: get_options 7 \n");
+      if ( (cmdline_uemodeparams[CMDLINE_CALIBUERX_IDX].paramflags &  PARAMFLAG_PARAMSET) != 0) mode = rx_calib_ue;
+      printf("Panos: get_options 8 \n");
+      if ( (cmdline_uemodeparams[CMDLINE_CALIBUERXMED_IDX].paramflags &  PARAMFLAG_PARAMSET) != 0) mode = rx_calib_ue_med;
+      printf("Panos: get_options 9 \n");
+      if ( (cmdline_uemodeparams[CMDLINE_CALIBUERXBYP_IDX].paramflags &  PARAMFLAG_PARAMSET) != 0) mode = rx_calib_ue_byp;
+      printf("Panos: get_options 10 \n");
+      if ( cmdline_uemodeparams[CMDLINE_DEBUGUEPRACH_IDX].uptr != NULL) {
+    	  if ( *(cmdline_uemodeparams[CMDLINE_DEBUGUEPRACH_IDX].uptr) > 0) mode = debug_prach;
+    	  if ( *(cmdline_uemodeparams[CMDLINE_NOL2CONNECT_IDX].uptr) > 0)  mode = no_L2_connect;
+    	  if ( *(cmdline_uemodeparams[CMDLINE_CALIBPRACHTX_IDX].uptr) > 0) mode = calib_prach_tx;
+      }
+      printf("Panos: get_options 11 \n");
+      if (dumpframe  > 0)  mode = rx_dump_frame;
+      if ( downlink_frequency[0][0] > 0) {
+    	  printf("Panos: get_options 8 \n");
+    	  for (CC_id=1; CC_id<MAX_NUM_CCs; CC_id++) {
+  	    downlink_frequency[CC_id][1] = downlink_frequency[0][0];
+  	    downlink_frequency[CC_id][2] = downlink_frequency[0][0];
+  	    downlink_frequency[CC_id][3] = downlink_frequency[0][0];
+  	    printf("Downlink for CC_id %d frequency set to %u\n", CC_id, downlink_frequency[CC_id][0]);
+  	  }
+      UE_scan=0;
+      }
+      printf("Panos: get_options 15 \n");
+
+      if (tddflag > 0) {
+         for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++)
+	     frame_parms[CC_id]->frame_type = TDD;
+      }
+      printf("Panos: get_options 16 \n");
+
+      if (frame_parms != NULL){
+    	  printf("Panos: get_options 17 \n");
+      if (frame_parms[0]->N_RB_DL !=0) {
+    	  printf("Panos: get_options 17 \n");
+  	  if ( frame_parms[0]->N_RB_DL < 6 ) {
+  	     frame_parms[0]->N_RB_DL = 6;
+  	     printf ( "%i: Invalid number of ressource blocks, adjusted to 6\n",frame_parms[0]->N_RB_DL);
+  	  }
+  	  if ( frame_parms[0]->N_RB_DL > 100 ) {
+  	     frame_parms[0]->N_RB_DL = 100;
+  	     printf ( "%i: Invalid number of ressource blocks, adjusted to 100\n",frame_parms[0]->N_RB_DL);
+  	  }
+  	  if ( frame_parms[0]->N_RB_DL > 50 && frame_parms[0]->N_RB_DL < 100 ) {
+  	     frame_parms[0]->N_RB_DL = 50;
+  	     printf ( "%i: Invalid number of ressource blocks, adjusted to 50\n",frame_parms[0]->N_RB_DL);
+  	  }
+  	  if ( frame_parms[0]->N_RB_DL > 25 && frame_parms[0]->N_RB_DL < 50 ) {
+  	     frame_parms[0]->N_RB_DL = 25;
+  	     printf ( "%i: Invalid number of ressource blocks, adjusted to 25\n",frame_parms[0]->N_RB_DL);
+  	  }
+  	  UE_scan = 0;
+  	  frame_parms[0]->N_RB_UL=frame_parms[0]->N_RB_DL;
+  	  for (CC_id=1; CC_id<MAX_NUM_CCs; CC_id++) {
+  	      frame_parms[CC_id]->N_RB_DL=frame_parms[0]->N_RB_DL;
+  	      frame_parms[CC_id]->N_RB_UL=frame_parms[0]->N_RB_UL;
+  	  }
+      }
+      }
+      printf("Panos: get_options 17 \n");
+
+      for (CC_id=1;CC_id<MAX_NUM_CCs;CC_id++) {
+  	    tx_max_power[CC_id]=tx_max_power[0];
+	    rx_gain[0][CC_id] = rx_gain[0][0];
+	    tx_gain[0][CC_id] = tx_gain[0][0];
+      }
+      printf("Panos: get_options 6 \n");
+  } /* UE_flag > 0 */
+#if T_TRACER
+  paramdef_t cmdline_ttraceparams[] =CMDLINE_TTRACEPARAMS_DESC ;
+  config_process_cmdline( cmdline_ttraceparams,sizeof(cmdline_ttraceparams)/sizeof(paramdef_t),NULL);
+#endif
+
+  if ( !(CONFIG_ISFLAGSET(CONFIG_ABORT)) ) {
+    if (UE_flag == 0) {
+      memset((void*)&RC,0,sizeof(RC));
+      /* Read RC configuration file */
+      RCConfig();
+      NB_eNB_INST = RC.nb_inst;
+      NB_RU	  = RC.nb_RU;
+      printf("Configuration: nb_rrc_inst %d, nb_L1_inst %d, nb_ru %d\n",NB_eNB_INST,RC.nb_L1_inst,NB_RU);
+    }
+  } else if (UE_flag == 1 && (CONFIG_GETCONFFILE != NULL)) {
+    // Here the configuration file is the XER encoded UE capabilities
+    // Read it in and store in asn1c data structures
+    strcpy(uecap_xer,CONFIG_GETCONFFILE);
+    uecap_xer_in=1;
+    printf("Panos: get_options 7 \n");
+  } /* UE with config file  */
+}
+
+
+#if T_TRACER
+int T_nowait = 0;     /* by default we wait for the tracer */
+int T_port = 2021;    /* default port to listen to to wait for the tracer */
+int T_dont_fork = 0;  /* default is to fork, see 'T_init' to understand */
+#endif
+
+
+
+void init_openair0(void);
+
+void init_openair0() {
+
+  int card;
+  int i;
+
+  for (card=0; card<MAX_CARDS; card++) {
+
+    openair0_cfg[card].mmapped_dma=mmapped_dma;
+    openair0_cfg[card].configFilename = NULL;
+
+    if(frame_parms[0]->N_RB_DL == 100) {
+      if (frame_parms[0]->threequarter_fs) {
+	openair0_cfg[card].sample_rate=23.04e6;
+	openair0_cfg[card].samples_per_frame = 230400;
+	openair0_cfg[card].tx_bw = 10e6;
+	openair0_cfg[card].rx_bw = 10e6;
+      } else {
+	openair0_cfg[card].sample_rate=30.72e6;
+	openair0_cfg[card].samples_per_frame = 307200;
+	openair0_cfg[card].tx_bw = 10e6;
+	openair0_cfg[card].rx_bw = 10e6;
+      }
+    } else if(frame_parms[0]->N_RB_DL == 50) {
+      openair0_cfg[card].sample_rate=15.36e6;
+      openair0_cfg[card].samples_per_frame = 153600;
+      openair0_cfg[card].tx_bw = 5e6;
+      openair0_cfg[card].rx_bw = 5e6;
+    } else if (frame_parms[0]->N_RB_DL == 25) {
+      openair0_cfg[card].sample_rate=7.68e6;
+      openair0_cfg[card].samples_per_frame = 76800;
+      openair0_cfg[card].tx_bw = 2.5e6;
+      openair0_cfg[card].rx_bw = 2.5e6;
+    } else if (frame_parms[0]->N_RB_DL == 6) {
+      openair0_cfg[card].sample_rate=1.92e6;
+      openair0_cfg[card].samples_per_frame = 19200;
+      openair0_cfg[card].tx_bw = 1.5e6;
+      openair0_cfg[card].rx_bw = 1.5e6;
+    }
+
+
+
+
+    if (frame_parms[0]->frame_type==TDD)
+      openair0_cfg[card].duplex_mode = duplex_mode_TDD;
+    else //FDD
+      openair0_cfg[card].duplex_mode = duplex_mode_FDD;
+
+    printf("HW: Configuring card %d, nb_antennas_tx/rx %d/%d\n",card,
+	   ((UE_flag==0) ? RC.eNB[0][0]->frame_parms.nb_antennas_tx : PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_tx),
+	   ((UE_flag==0) ? RC.eNB[0][0]->frame_parms.nb_antennas_rx : PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_rx));
+    openair0_cfg[card].Mod_id = 0;
+
+    openair0_cfg[card].num_rb_dl=frame_parms[0]->N_RB_DL;
+
+    openair0_cfg[card].clock_source = clock_source;
+
+
+    openair0_cfg[card].tx_num_channels=min(2,((UE_flag==0) ? RC.eNB[0][0]->frame_parms.nb_antennas_tx : PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_tx));
+    openair0_cfg[card].rx_num_channels=min(2,((UE_flag==0) ? RC.eNB[0][0]->frame_parms.nb_antennas_rx : PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_rx));
+
+    for (i=0; i<4; i++) {
+
+      if (i<openair0_cfg[card].tx_num_channels)
+	openair0_cfg[card].tx_freq[i] = (UE_flag==0) ? downlink_frequency[0][i] : downlink_frequency[0][i]+uplink_frequency_offset[0][i];
+      else
+	openair0_cfg[card].tx_freq[i]=0.0;
+
+      if (i<openair0_cfg[card].rx_num_channels)
+	openair0_cfg[card].rx_freq[i] = (UE_flag==0) ? downlink_frequency[0][i] + uplink_frequency_offset[0][i] : downlink_frequency[0][i];
+      else
+	openair0_cfg[card].rx_freq[i]=0.0;
+
+      openair0_cfg[card].autocal[i] = 1;
+      openair0_cfg[card].tx_gain[i] = tx_gain[0][i];
+      if (UE_flag == 0) {
+	openair0_cfg[card].rx_gain[i] = RC.eNB[0][0]->rx_total_gain_dB;
+      }
+      else {
+	openair0_cfg[card].rx_gain[i] = PHY_vars_UE_g[0][0]->rx_total_gain_dB - rx_gain_off;
+      }
+
+      openair0_cfg[card].configFilename = rf_config_file;
+      printf("Card %d, channel %d, Setting tx_gain %f, rx_gain %f, tx_freq %f, rx_freq %f\n",
+	     card,i, openair0_cfg[card].tx_gain[i],
+	     openair0_cfg[card].rx_gain[i],
+	     openair0_cfg[card].tx_freq[i],
+	     openair0_cfg[card].rx_freq[i]);
+    }
+  }
+}
+
+
+void wait_RUs(void) {
+
+  LOG_I(PHY,"Waiting for RUs to be configured ... RC.ru_mask:%02lx\n", RC.ru_mask);
+
+  // wait for all RUs to be configured over fronthaul
+  pthread_mutex_lock(&RC.ru_mutex);
+
+
+
+  while (RC.ru_mask>0) {
+    pthread_cond_wait(&RC.ru_cond,&RC.ru_mutex);
+    printf("RC.ru_mask:%02lx\n", RC.ru_mask);
+  }
+
+  LOG_I(PHY,"RUs configured\n");
+}
+
+void wait_eNBs(void) {
+
+  int i,j;
+  int waiting=1;
+
+
+  while (waiting==1) {
+    printf("Waiting for eNB L1 instances to all get configured ... sleeping 500ms (nb_L1_inst %d)\n",RC.nb_L1_inst);
+    usleep(5000000);
+    waiting=0;
+    for (i=0;i<RC.nb_L1_inst;i++) {
+
+      printf("RC.nb_L1_CC[%d]:%d\n", i, RC.nb_L1_CC[i]);
+
+      for (j=0;j<RC.nb_L1_CC[i];j++) {
+	if (RC.eNB[i][j]->configured==0) {
+	  waiting=1;
+	  break;
+        }
+      }
+    }
+  }
+  printf("eNB L1 are configured\n");
+}
+
+static inline void wait_nfapi_init(char *thread_name) {
+
+  printf( "waiting for NFAPI PNF connection and population of global structure (%s)\n",thread_name);
+  pthread_mutex_lock( &nfapi_sync_mutex );
+
+  while (nfapi_sync_var<0)
+    pthread_cond_wait( &nfapi_sync_cond, &nfapi_sync_mutex );
+
+  pthread_mutex_unlock(&nfapi_sync_mutex);
+
+  printf( "NFAPI: got sync (%s)\n", thread_name);
+}
+
+int main( int argc, char **argv )
+{
+  int i;
+#if defined (XFORMS)
+  void *status;
+#endif
+
+  int CC_id;
+  int ru_id;
+  uint8_t  abstraction_flag=0;
+  uint8_t beta_ACK=0,beta_RI=0,beta_CQI=2;
+
+#if defined (XFORMS)
+  int ret;
+#endif
+
+  start_background_system();
+  if ( load_configmodule(argc,argv) == NULL) {
+    exit_fun("[SOFTMODEM] Error, configuration module init failed\n");
+  }
+
+#ifdef DEBUG_CONSOLE
+  setvbuf(stdout, NULL, _IONBF, 0);
+  setvbuf(stderr, NULL, _IONBF, 0);
+#endif
+
+  PHY_VARS_UE *UE[MAX_NUM_CCs];
+
+  mode = normal_txrx;
+
+  //Panos: RF-sepcific part should get dropped (next 3 lines)?
+  //memset(&openair0_cfg[0],0,sizeof(openair0_config_t)*MAX_CARDS);
+
+  //memset(tx_max_power,0,sizeof(int)*MAX_NUM_CCs);
+
+  //set_latency_target();
+
+  // set default parameters
+  //if (UE_flag == 1) set_default_frame_parms(frame_parms);
+
+  logInit();
+
+  printf("Reading in command-line options\n");
+
+  get_options ();
+  if (CONFIG_ISFLAGSET(CONFIG_ABORT)) {
+      fprintf(stderr,"Getting configuration failed\n");
+      exit(-1);
+  }
+
+
+#if T_TRACER
+  T_init(T_port, 1-T_nowait, T_dont_fork);
+#endif
+
+
+
+  //randominit (0);
+  set_taus_seed (0);
+
+  if (UE_flag==1) {
+    printf("configuring for UE\n");
+
+    set_comp_log(HW,      LOG_DEBUG,  LOG_HIGH, 1);
+    set_comp_log(PHY,     LOG_DEBUG,   LOG_HIGH, 1);
+    set_comp_log(MAC,     LOG_INFO,   LOG_HIGH, 1);
+    set_comp_log(RLC,     LOG_INFO,   LOG_HIGH | FLAG_THREAD, 1);
+    set_comp_log(PDCP,    LOG_INFO,   LOG_HIGH, 1);
+    set_comp_log(OTG,     LOG_INFO,   LOG_HIGH, 1);
+    set_comp_log(RRC,     LOG_INFO,   LOG_HIGH, 1);
+#if defined(ENABLE_ITTI)
+    set_comp_log(EMU,     LOG_INFO,   LOG_MED, 1);
+# if defined(ENABLE_USE_MME)
+    set_comp_log(NAS,     LOG_INFO,   LOG_HIGH, 1);
+# endif
+#endif
+
+  } else {
+    printf("configuring for RAU/RRU\n");
+
+  }
+
+  if (ouput_vcd) {
+    if (UE_flag==1)
+      VCD_SIGNAL_DUMPER_INIT("/tmp/openair_dump_UE.vcd");
+    else
+      VCD_SIGNAL_DUMPER_INIT("/tmp/openair_dump_eNB.vcd");
+  }
+
+  // Panos: Not required for phy_stub_UE mode
+  /*if (opp_enabled ==1) {
+    reset_opp_meas();
+  }
+  cpuf=get_cpu_freq_GHz();*/
+
+#if defined(ENABLE_ITTI)
+
+  if (UE_flag == 1) {
+    log_set_instance_type (LOG_INSTANCE_UE);
+  } else {
+    log_set_instance_type (LOG_INSTANCE_ENB);
+  }
+
+  printf("ITTI init\n");
+  itti_init(TASK_MAX, THREAD_MAX, MESSAGES_ID_MAX, tasks_info, messages_info, messages_definition_xml, itti_dump_file);
+
+  // initialize mscgen log after ITTI
+  MSC_INIT(MSC_E_UTRAN, THREAD_MAX+TASK_MAX);
+#endif
+
+  if (opt_type != OPT_NONE) {
+    radio_type_t radio_type;
+
+    if (frame_parms[0]->frame_type == FDD)
+      radio_type = RADIO_TYPE_FDD;
+    else
+      radio_type = RADIO_TYPE_TDD;
+
+    if (init_opt(in_path, in_ip, NULL, radio_type) == -1)
+      LOG_E(OPT,"failed to run OPT \n");
+  }
+
+#ifdef PDCP_USE_NETLINK
+  printf("PDCP netlink\n");
+  netlink_init();
+#if defined(PDCP_USE_NETLINK_QUEUES)
+  pdcp_netlink_init();
+#endif
+#endif
+
+#if !defined(ENABLE_ITTI)
+  // to make a graceful exit when ctrl-c is pressed
+  signal(SIGSEGV, signal_handler);
+  signal(SIGINT, signal_handler);
+#endif
+
+
+  check_clock();
+
+#ifndef PACKAGE_VERSION
+#  define PACKAGE_VERSION "UNKNOWN-EXPERIMENTAL"
+#endif
+
+  LOG_I(HW, "Version: %s\n", PACKAGE_VERSION);
+
+  // init the parameters
+  // Panos: Probably don't need next lines for the stub.
+
+  /*for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
+
+    if (UE_flag==1) {
+      frame_parms[CC_id]->nb_antennas_tx     = nb_antenna_tx;
+      frame_parms[CC_id]->nb_antennas_rx     = nb_antenna_rx;
+      frame_parms[CC_id]->nb_antenna_ports_eNB = 1; //initial value overwritten by initial sync later
+    }
+  }*/
+
+
+
+  printf("Before CC \n");
+
+  for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
+
+
+    if (UE_flag==1) {
+      NB_UE_INST=1;
+      NB_INST=1;
+      PHY_vars_UE_g = malloc(sizeof(PHY_VARS_UE**));
+      PHY_vars_UE_g[0] = malloc(sizeof(PHY_VARS_UE*)*MAX_NUM_CCs);
+
+
+
+      PHY_vars_UE_g[0][CC_id] = init_ue_vars(frame_parms[CC_id], 0,abstraction_flag);
+      UE[CC_id] = PHY_vars_UE_g[0][CC_id];
+      printf("PHY_vars_UE_g[0][%d] = %p\n",CC_id,UE[CC_id]);
+
+      if (phy_test==1)
+	UE[CC_id]->mac_enabled = 0;
+      else
+	UE[CC_id]->mac_enabled = 1;
+
+      /*if (UE[CC_id]->mac_enabled == 0) {  //set default UL parameters for testing mode
+	for (i=0; i<NUMBER_OF_CONNECTED_eNB_MAX; i++) {
+	  UE[CC_id]->pusch_config_dedicated[i].betaOffset_ACK_Index = beta_ACK;
+	  UE[CC_id]->pusch_config_dedicated[i].betaOffset_RI_Index  = beta_RI;
+	  UE[CC_id]->pusch_config_dedicated[i].betaOffset_CQI_Index = beta_CQI;
+
+	  UE[CC_id]->scheduling_request_config[i].sr_PUCCH_ResourceIndex = 0;
+	  UE[CC_id]->scheduling_request_config[i].sr_ConfigIndex = 7+(0%3);
+	  UE[CC_id]->scheduling_request_config[i].dsr_TransMax = sr_n4;
+	}
+      }
+
+      UE[CC_id]->UE_scan = UE_scan;
+      UE[CC_id]->UE_scan_carrier = UE_scan_carrier;
+      UE[CC_id]->mode    = mode;
+      printf("UE[%d]->mode = %d\n",CC_id,mode);
+
+      if (UE[CC_id]->mac_enabled == 1) {
+	UE[CC_id]->pdcch_vars[0][0]->crnti = 0x1234;
+	UE[CC_id]->pdcch_vars[1][0]->crnti = 0x1234;
+      }else {
+	UE[CC_id]->pdcch_vars[0][0]->crnti = 0x1235;
+	UE[CC_id]->pdcch_vars[1][0]->crnti = 0x1235;
+      }
+      UE[CC_id]->rx_total_gain_dB =  (int)rx_gain[CC_id][0] + rx_gain_off;
+      UE[CC_id]->tx_power_max_dBm = tx_max_power[CC_id];
+
+      if (frame_parms[CC_id]->frame_type==FDD) {
+	UE[CC_id]->N_TA_offset = 0;
+      }
+      else {
+	if (frame_parms[CC_id]->N_RB_DL == 100)
+	  UE[CC_id]->N_TA_offset = 624;
+	else if (frame_parms[CC_id]->N_RB_DL == 50)
+	  UE[CC_id]->N_TA_offset = 624/2;
+	else if (frame_parms[CC_id]->N_RB_DL == 25)
+	  UE[CC_id]->N_TA_offset = 624/4;
+      }*/
+
+    }
+  }
+
+  // Panos: Probably don't need these lines for phy_stub
+  /*printf("Runtime table\n");
+  fill_modeled_runtime_table(runtime_phy_rx,runtime_phy_tx);
+  cpuf=get_cpu_freq_GHz();*/
+
+
+
+#ifndef DEADLINE_SCHEDULER
+
+  printf("NO deadline scheduler\n");
+  /* Currently we set affinity for UHD to CPU 0 for eNB/UE and only if number of CPUS >2 */
+
+  cpu_set_t cpuset;
+  int s;
+  char cpu_affinity[1024];
+  CPU_ZERO(&cpuset);
+#ifdef CPU_AFFINITY
+  if (get_nprocs() > 2) {
+    CPU_SET(0, &cpuset);
+    s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
+    if (s != 0) {
+      perror( "pthread_setaffinity_np");
+      exit_fun("Error setting processor affinity");
+    }
+    LOG_I(HW, "Setting the affinity of main function to CPU 0, for device library to use CPU 0 only!\n");
+  }
+#endif
+
+  /* Check the actual affinity mask assigned to the thread */
+  s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
+  if (s != 0) {
+    perror( "pthread_getaffinity_np");
+    exit_fun("Error getting processor affinity ");
+  }
+  memset(cpu_affinity, 0 , sizeof(cpu_affinity));
+  for (int j = 0; j < CPU_SETSIZE; j++) {
+    if (CPU_ISSET(j, &cpuset)) {
+      char temp[1024];
+      sprintf(temp, " CPU_%d ", j);
+      strcat(cpu_affinity, temp);
+    }
+  }
+  LOG_I(HW, "CPU Affinity of main() function is... %s\n", cpu_affinity);
+#endif
+
+
+
+
+#if defined(ENABLE_ITTI)
+
+  printf("ITTI enabled\n");
+
+  printf("UE_flag:%d\n", UE_flag);
+  printf("RC.nb_inst:%d\n", RC.nb_inst);
+  /*if ((UE_flag == 1)||
+      (RC.nb_inst > 0))  {*/
+
+  if (UE_flag == 1) {
+    // don't create if node doesn't connect to RRC/S1/GTP
+    if (create_tasks(UE_flag ? 0 : 1, UE_flag ? 1 : 0) < 0) {
+      printf("cannot create ITTI tasks\n");
+      exit(-1); // need a softer mode
+    }
+    UE_config_stub_pnf();
+    printf("ITTI tasks created\n");
+  }
+  else {
+    printf("No ITTI, Initializing L1\n");
+    RCconfig_L1();
+  }
+#endif
+
+  /*if (phy_test==0) {
+    if (UE_flag==1) {
+      printf("Filling UE band info\n");
+      fill_ue_band_info();
+      dl_phy_sync_success (0, 0, 0, 1);
+    }
+  }*/
+
+  mlockall(MCL_CURRENT | MCL_FUTURE);
+
+  // Panos: Why we have these initializations twice if in nfapi_mode?
+  pthread_cond_init(&sync_cond,NULL);
+  pthread_mutex_init(&sync_mutex, NULL);
+
+#ifdef XFORMS
+  int UE_id;
+
+  printf("XFORMS\n");
+
+  if (do_forms==1) {
+    fl_initialize (&argc, argv, NULL, 0, 0);
+
+    if (UE_flag==0) {
+      form_stats_l2 = create_form_stats_form();
+      fl_show_form (form_stats_l2->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "l2 stats");
+      form_stats = create_form_stats_form();
+      fl_show_form (form_stats->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "stats");
+
+      for(UE_id=0; UE_id<scope_enb_num_ue; UE_id++) {
+	for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
+	  form_enb[CC_id][UE_id] = create_lte_phy_scope_enb();
+	  sprintf (title, "LTE UL SCOPE eNB for CC_id %d, UE %d",CC_id,UE_id);
+	  fl_show_form (form_enb[CC_id][UE_id]->lte_phy_scope_enb, FL_PLACE_HOTSPOT, FL_FULLBORDER, title);
+
+	  if (otg_enabled) {
+	    fl_set_button(form_enb[CC_id][UE_id]->button_0,1);
+	    fl_set_object_label(form_enb[CC_id][UE_id]->button_0,"DL Traffic ON");
+	  } else {
+	    fl_set_button(form_enb[CC_id][UE_id]->button_0,0);
+	    fl_set_object_label(form_enb[CC_id][UE_id]->button_0,"DL Traffic OFF");
+	  }
+	} // CC_id
+      } // UE_id
+    } else {
+      form_stats = create_form_stats_form();
+      fl_show_form (form_stats->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "stats");
+      UE_id = 0;
+      form_ue[UE_id] = create_lte_phy_scope_ue();
+      sprintf (title, "LTE DL SCOPE UE");
+      fl_show_form (form_ue[UE_id]->lte_phy_scope_ue, FL_PLACE_HOTSPOT, FL_FULLBORDER, title);
+
+      /*
+	if (openair_daq_vars.use_ia_receiver) {
+	fl_set_button(form_ue[UE_id]->button_0,1);
+	fl_set_object_label(form_ue[UE_id]->button_0, "IA Receiver ON");
+	} else {
+	fl_set_button(form_ue[UE_id]->button_0,0);
+	fl_set_object_label(form_ue[UE_id]->button_0, "IA Receiver OFF");
+	}*/
+      fl_set_button(form_ue[UE_id]->button_0,0);
+      fl_set_object_label(form_ue[UE_id]->button_0, "IA Receiver OFF");
+    }
+
+    ret = pthread_create(&forms_thread, NULL, scope_thread, NULL);
+
+    if (ret == 0)
+      pthread_setname_np( forms_thread, "xforms" );
+
+    printf("Scope thread created, ret=%d\n",ret);
+  }
+
+#endif
+
+  rt_sleep_ns(10*100000000ULL);
+
+  if (nfapi_mode)
+  {
+    printf("NFAPI*** - mutex and cond created - will block shortly for completion of PNF connection\n");
+    pthread_cond_init(&sync_cond,NULL);
+    pthread_mutex_init(&sync_mutex, NULL);
+  }
+
+  const char *nfapi_mode_str = "<UNKNOWN>";
+
+  switch(nfapi_mode)
+  {
+    case 0:
+      nfapi_mode_str = "MONOLITHIC";
+      break;
+    case 1:
+      nfapi_mode_str = "PNF";
+      break;
+    case 2:
+      nfapi_mode_str = "VNF";
+      break;
+    case 3:
+      nfapi_mode_str = "UE_STUB_PNF";
+      break;
+    default:
+      nfapi_mode_str = "<UNKNOWN NFAPI MODE>";
+      break;
+  }
+  printf("NFAPI MODE:%s\n", nfapi_mode_str);
+
+  // Panos: We should never enter here since we are always going to run with nfapi_mode=3
+  if (nfapi_mode==2) // VNF
+    wait_nfapi_init("main?");
+
+  printf("START MAIN THREADS\n");
+
+  // start the main threads
+  if (UE_flag == 1) {
+    int eMBMS_active = 0;
+    // Panos: Call init_UE_stub instead of init_UE as we are always on nfapi_mode=3
+    //phy_stub_ticking = (SF_ticking*)malloc(sizeof(SF_ticking));
+    init_timer_thread();
+    init_UE_stub(1,eMBMS_active,uecap_xer_in);
+    //init_UE(1,eMBMS_active,uecap_xer_in);
+    number_of_cards = 1;
+    if (nfapi_mode==3) // UE-STUB-PNF
+    	{
+    	wait_nfapi_init("main?");
+    	}
+
+    /*for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
+      PHY_vars_UE_g[0][CC_id]->rf_map.card=0;
+      PHY_vars_UE_g[0][CC_id]->rf_map.chain=CC_id+chain_offset;
+    }*/
+  }
+  // Panos: We should never enter this else case for nfapi_mode=3.
+  /*else {
+    number_of_cards = 1;
+    printf("RC.nb_L1_inst:%d\n", RC.nb_L1_inst);
+    if (RC.nb_L1_inst > 0) {
+      printf("Initializing eNB threads single_thread_flag:%d wait_for_sync:%d\n", single_thread_flag,wait_for_sync);
+      init_eNB(single_thread_flag,wait_for_sync);
+      //      for (inst=0;inst<RC.nb_L1_inst;inst++)
+      //	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);
+    if (RC.nb_RU >0) {
+      printf("Initializing RU threads\n");
+      init_RU(rf_config_file);
+      for (ru_id=0;ru_id<RC.nb_RU;ru_id++) {
+	RC.ru[ru_id]->rf_map.card=0;
+	RC.ru[ru_id]->rf_map.chain=CC_id+chain_offset;
+      }
+    }
+
+    config_sync_var=0;
+
+    if (nfapi_mode==1) // PNF
+    {
+      wait_nfapi_init("main?");
+    }
+
+    printf("wait RUs\n");
+    wait_RUs();
+    printf("ALL RUs READY!\n");
+    printf("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)
+    printf("ALL RUs ready - init eNBs\n");
+
+    if (nfapi_mode != 1 && nfapi_mode != 2)
+    {
+      printf("Not NFAPI mode - call init_eNB_afterRU()\n");
+      init_eNB_afterRU();
+    }
+    else
+    {
+      printf("NFAPI mode - DO NOT call init_eNB_afterRU()\n");
+    }
+
+    printf("ALL RUs ready - ALL eNBs ready\n");
+  }*/
+  if (phy_test==0) {
+      if (UE_flag==1) {
+        printf("Filling UE band info\n");
+        fill_ue_band_info();
+        dl_phy_sync_success (0, 0, 0, 1);
+      }
+    }
+
+
+  // connect the TX/RX buffers
+  if (UE_flag==1) {
+
+    for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
+
+
+#ifdef OAI_USRP
+      UE[CC_id]->hw_timing_advance = timing_advance;
+#else
+      UE[CC_id]->hw_timing_advance = 160;
+#endif
+    }
+    // Panos: No need to call setup_ue_buffers() for nfapi_mode=3
+    /*if (setup_ue_buffers(UE,&openair0_cfg[0])!=0) {
+      printf("Error setting up eNB buffer\n");
+      exit(-1);
+    }*/
+
+
+    // Panos: Similar for nfapi_mode=3
+    /*if (input_fd) {
+      printf("Reading in from file to antenna buffer %d\n",0);
+      if (fread(UE[0]->common_vars.rxdata[0],
+		sizeof(int32_t),
+		frame_parms[0]->samples_per_tti*10,
+		input_fd) != frame_parms[0]->samples_per_tti*10)
+	printf("error reading from file\n");
+    }*/
+    //p_exmimo_config->framing.tdd_config = TXRXSWITCH_TESTRX;
+  } else {
+
+    printf("eNB mode\n");
+
+  }
+
+  printf("Sending sync to all threads\n");
+
+  pthread_mutex_lock(&sync_mutex);
+  sync_var=0;
+  pthread_cond_broadcast(&sync_cond);
+  pthread_mutex_unlock(&sync_mutex);
+  printf("About to call end_configmodule() from %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__);
+  end_configmodule();
+  printf("Called end_configmodule() from %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__);
+
+  // wait for end of program
+  printf("TYPE <CTRL-C> TO TERMINATE\n");
+  //getchar();
+
+#if defined(ENABLE_ITTI)
+  printf("Entering ITTI signals handler\n");
+  itti_wait_tasks_end();
+  printf("Returned from ITTI signal handler\n");
+  oai_exit=1;
+  printf("oai_exit=%d\n",oai_exit);
+#else
+
+  while (oai_exit==0)
+    rt_sleep_ns(100000000ULL);
+  printf("Terminating application - oai_exit=%d\n",oai_exit);
+
+#endif
+
+  // stop threads
+#ifdef XFORMS
+  printf("waiting for XFORMS thread\n");
+
+  if (do_forms==1) {
+    pthread_join(forms_thread,&status);
+    fl_hide_form(form_stats->stats_form);
+    fl_free_form(form_stats->stats_form);
+
+    if (UE_flag==1) {
+      fl_hide_form(form_ue[0]->lte_phy_scope_ue);
+      fl_free_form(form_ue[0]->lte_phy_scope_ue);
+    } else {
+      fl_hide_form(form_stats_l2->stats_form);
+      fl_free_form(form_stats_l2->stats_form);
+
+      for(UE_id=0; UE_id<scope_enb_num_ue; UE_id++) {
+	for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
+	  fl_hide_form(form_enb[CC_id][UE_id]->lte_phy_scope_enb);
+	  fl_free_form(form_enb[CC_id][UE_id]->lte_phy_scope_enb);
+	}
+      }
+    }
+  }
+
+#endif
+
+  printf("stopping MODEM threads\n");
+
+  // cleanup
+  if (UE_flag == 1) {
+  } /*else {
+    stop_eNB(1);
+  }*/
+
+
+  pthread_cond_destroy(&sync_cond);
+  pthread_mutex_destroy(&sync_mutex);
+
+  pthread_cond_destroy(&nfapi_sync_cond);
+  pthread_mutex_destroy(&nfapi_sync_mutex);
+
+
+  // Panos: No RF in phy_stub mode: Exclude the following lines
+  // *** Handle per CC_id openair0
+  /*if (UE_flag==1) {
+    if (PHY_vars_UE_g[0][0]->rfdevice.trx_end_func)
+      PHY_vars_UE_g[0][0]->rfdevice.trx_end_func(&PHY_vars_UE_g[0][0]->rfdevice);
+  }
+  else {
+    for(ru_id=0; ru_id<NB_RU; ru_id++) {
+      if (RC.ru[ru_id]->rfdevice.trx_end_func)
+	RC.ru[ru_id]->rfdevice.trx_end_func(&RC.ru[ru_id]->rfdevice);
+      if (RC.ru[ru_id]->ifdevice.trx_end_func)
+	RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice);
+
+    }
+  }*/
+  if (ouput_vcd)
+    VCD_SIGNAL_DUMPER_CLOSE();
+
+  if (opt_enabled == 1)
+    terminate_opt();
+
+  logClean();
+
+  return 0;
+}
diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c
index 0dec98e137a..86cac797d06 100644
--- a/targets/RT/USER/lte-softmodem.c
+++ b/targets/RT/USER/lte-softmodem.c
@@ -118,6 +118,8 @@ int nfapi_sync_var=-1; //!< protected by mutex \ref nfapi_sync_mutex
 
 uint8_t nfapi_mode = 0;
 
+uint16_t sf_ahead=4;
+
 pthread_cond_t sync_cond;
 pthread_mutex_t sync_mutex;
 int sync_var=-1; //!< protected by mutex \ref sync_mutex.
@@ -937,7 +939,6 @@ int main( int argc, char **argv )
 
   // set default parameters
   if (UE_flag == 1) set_default_frame_parms(frame_parms);
-
   logInit();
 
   printf("Reading in command-line options\n");
diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c
index e97ed62d512..84f2452d425 100644
--- a/targets/RT/USER/lte-ue.c
+++ b/targets/RT/USER/lte-ue.c
@@ -76,6 +76,7 @@ void init_UE_threads(int);
 void init_UE_threads_stub(int);
 void *UE_thread(void *arg);
 void init_UE(int nb_inst,int,int);
+void init_UE_stub(int nb_inst,int,int);
 extern void oai_subframe_ind(uint16_t sfn, uint16_t sf);
 //extern int tx_req_UE_MAC1();
 
@@ -1408,17 +1409,18 @@ int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, openair0_config_t *openair0_cfg)
     return 0;
 }
 
+
 // Panos: This timer thread is used only in the phy_sub mode as an independent timer
 // which will be ticking and provide the SFN/SF values that will be used from the UE threads
 // playing the role of nfapi-pnf.
 static void* timer_thread( void* param ) {
 	timer_subframe =9;
 	timer_frame    =1023;
-	phy_stub_ticking = (SF_ticking*)malloc(sizeof(SF_ticking));
+	//phy_stub_ticking = (SF_ticking*)malloc(sizeof(SF_ticking));
 	phy_stub_ticking->ticking_var = -1;
 	wait_sync("timer_thread");
-    pthread_mutex_init(&phy_stub_ticking->mutex_ticking,NULL);
-    pthread_cond_init(&phy_stub_ticking->cond_ticking,NULL);
+    //pthread_mutex_init(&phy_stub_ticking->mutex_ticking,NULL);
+    //pthread_cond_init(&phy_stub_ticking->cond_ticking,NULL);
 
 	while (!oai_exit) {
 	    usleep(1000);
@@ -1454,6 +1456,14 @@ static void* timer_thread( void* param ) {
 
 }
 
+int init_timer_thread(void) {
+	phy_stub_ticking = (SF_ticking*)malloc(sizeof(SF_ticking));
+	pthread_mutex_init(&phy_stub_ticking->mutex_ticking,NULL);
+	pthread_cond_init(&phy_stub_ticking->cond_ticking,NULL);
+	pthread_create(phy_stub_ticking->pthread_timer, NULL, &timer_thread, NULL);
+	return 0;
+}
+
 
 
 
-- 
GitLab