From 3cced60a00e598b24088213ca6348880e39dbd51 Mon Sep 17 00:00:00 2001
From: matzakos <panagiotis.matzakos@eurecom.fr>
Date: Thu, 23 Nov 2017 17:10:48 +0100
Subject: [PATCH] Connected new callback functions at nfapi_pnf for phy_stub
 mode + Intorducing new functions initializing UE variables and threads
 specific to phy_stub mode, instead of extending the existing ones + Direct
 connection of the timer_thread with UE_phy_stub_thread_rxn_txnp4.

---
 nfapi/nfapi_pnf.c                    |  17 +-
 openair2/LAYER2/MAC/ue_procedures.c  |  10 +
 openair2/PHY_INTERFACE/phy_stub_UE.c |  20 +-
 openair2/PHY_INTERFACE/phy_stub_UE.h |   8 +-
 targets/RT/USER/lte-ue.c             | 438 ++++++++++++++++++++-------
 5 files changed, 370 insertions(+), 123 deletions(-)

diff --git a/nfapi/nfapi_pnf.c b/nfapi/nfapi_pnf.c
index e1a62b0c07f..9ba66684a4a 100644
--- a/nfapi/nfapi_pnf.c
+++ b/nfapi/nfapi_pnf.c
@@ -9,6 +9,7 @@
 #include "nfapi.h"
 #include "nfapi_pnf.h"
 #include "common/ran_context.h"
+#include "openair2/PHY_INTERFACE/phy_stub_UE.h"
 //#include "openair1/PHY/vars.h"
 extern RAN_CONTEXT_t RC;
 
@@ -1338,10 +1339,18 @@ int start_request(nfapi_pnf_config_t* config, nfapi_pnf_phy_config_t* phy, nfapi
       p7_config->timing_info_mode_aperiodic = 1;
     }
 
-    p7_config->dl_config_req = &pnf_phy_dl_config_req;
-    p7_config->ul_config_req = &pnf_phy_ul_config_req;
-    p7_config->hi_dci0_req = &pnf_phy_hi_dci0_req;
-    p7_config->tx_req = &pnf_phy_tx_req;
+    if (nfapi_mode==3) {
+    	p7_config->dl_config_req = &memcpy_dl_config_req;
+    	p7_config->ul_config_req = &memcpy_ul_config_req;
+    	p7_config->hi_dci0_req = &memcpy_hi_dci0_req;
+    	p7_config->tx_req = &memcpy_tx_req;
+    }
+    else {
+    	p7_config->dl_config_req = &pnf_phy_dl_config_req;
+    	p7_config->ul_config_req = &pnf_phy_ul_config_req;
+    	p7_config->hi_dci0_req = &pnf_phy_hi_dci0_req;
+    	p7_config->tx_req = &pnf_phy_tx_req;
+    }
     p7_config->lbt_dl_config_req = &pnf_phy_lbt_dl_config_req;
 
     memset(&dummy_dl_config_req, 0, sizeof(dummy_dl_config_req));
diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c
index 1d219825c25..db7304c70a9 100644
--- a/openair2/LAYER2/MAC/ue_procedures.c
+++ b/openair2/LAYER2/MAC/ue_procedures.c
@@ -137,6 +137,16 @@ void ue_init_mac(module_id_t module_idP)
     UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[i] = 0;
   }
 
+  if(nfapi_mode == 3) {
+	  pthread_mutex_init(&UE_mac_inst[module_idP].UL_INFO_mutex,NULL);
+	  UE_mac_inst[module_idP].UE_mode[0] = PRACH;
+	  UE_mac_inst[module_idP].first_ULSCH_Tx =0;
+	  UE_mac_inst[module_idP].dl_config_req = NULL;
+	  UE_mac_inst[module_idP].ul_config_req = NULL;
+	  UE_mac_inst[module_idP].hi_dci0_req = NULL;
+	  UE_mac_inst[module_idP].tx_req = NULL;
+  }
+
 #ifdef CBA
 
   for (i=0; i <NUM_MAX_CBA_GROUP; i++) {
diff --git a/openair2/PHY_INTERFACE/phy_stub_UE.c b/openair2/PHY_INTERFACE/phy_stub_UE.c
index 799ad1a06ab..837fd2976a4 100644
--- a/openair2/PHY_INTERFACE/phy_stub_UE.c
+++ b/openair2/PHY_INTERFACE/phy_stub_UE.c
@@ -489,7 +489,7 @@ void handle_nfapi_ul_pdu_UE_MAC(module_id_t Mod_id,
     uint16_t rnti = ul_config_pdu->ulsch_pdu.ulsch_pdu_rel8.rnti;
     uint8_t access_mode=SCHEDULED_ACCESS;
     if(buflen>0){
-    	if(UE_mac_inst[Mod_id].first_ULSCH_Tx){ // Msg3 case
+    	if(UE_mac_inst[Mod_id].first_ULSCH_Tx == 1){ // Msg3 case
     		fill_crc_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, 0);
     		fill_rx_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, UE_mac_inst[Mod_id].RA_prach_resources.Msg3,buflen, rnti);
     		Msg3_transmitted(Mod_id, 0, frame, 0);
@@ -514,7 +514,7 @@ void handle_nfapi_ul_pdu_UE_MAC(module_id_t Mod_id,
 	  uint16_t rnti = ul_config_pdu->ulsch_harq_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti;
 	  uint8_t access_mode=SCHEDULED_ACCESS;
 	  if(buflen>0){
-		  if(UE_mac_inst[Mod_id].first_ULSCH_Tx){ // Msg3 case
+		  if(UE_mac_inst[Mod_id].first_ULSCH_Tx == 1){ // Msg3 case
 			  fill_crc_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, 0);
 			  fill_rx_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, UE_mac_inst[Mod_id].RA_prach_resources.Msg3,buflen, rnti);
 			  Msg3_transmitted(Mod_id, 0, frame, 0);
@@ -542,7 +542,7 @@ void handle_nfapi_ul_pdu_UE_MAC(module_id_t Mod_id,
 	  uint16_t rnti = ul_config_pdu->ulsch_cqi_ri_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti;
 	  uint8_t access_mode=SCHEDULED_ACCESS;
 	  if(buflen>0){
-		  if(UE_mac_inst[Mod_id].first_ULSCH_Tx){ // Msg3 case
+		  if(UE_mac_inst[Mod_id].first_ULSCH_Tx == 1){ // Msg3 case
 			  fill_crc_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, 0);
 			  fill_rx_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, UE_mac_inst[Mod_id].RA_prach_resources.Msg3,buflen, rnti);
 			  Msg3_transmitted(Mod_id, 0, frame, 0);
@@ -569,7 +569,7 @@ void handle_nfapi_ul_pdu_UE_MAC(module_id_t Mod_id,
 	  uint16_t rnti = ul_config_pdu->ulsch_cqi_harq_ri_pdu.ulsch_pdu.ulsch_pdu_rel8.rnti;
 	  uint8_t access_mode=SCHEDULED_ACCESS;
 	  if(buflen>0){
-		  if(UE_mac_inst[Mod_id].first_ULSCH_Tx){ // Msg3 case
+		  if(UE_mac_inst[Mod_id].first_ULSCH_Tx == 1){ // Msg3 case
 			  fill_crc_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, 0);
 			  fill_rx_indication_UE_MAC(Mod_id, frame, subframe, UL_INFO, UE_mac_inst[Mod_id].RA_prach_resources.Msg3,buflen, rnti);
 			  Msg3_transmitted(Mod_id, 0, frame, 0);
@@ -921,28 +921,32 @@ int hi_dci0_req_UE_MAC(nfapi_hi_dci0_request_t* req)
 
 // The following set of memcpy functions should be getting called as callback functions from
 // pnf_p7_subframe_ind.
-void memcpy_dl_config_req (nfapi_pnf_p7_config_t* pnf_p7, nfapi_dl_config_request_t* req)
+int memcpy_dl_config_req (nfapi_pnf_p7_config_t* pnf_p7, nfapi_dl_config_request_t* req)
 {
 	module_id_t Mod_id = 0; //Panos: Currently static (only for one UE) but this should change.
 	UE_mac_inst[Mod_id].dl_config_req = req;
+	return 0;
 }
 
-void memcpy_ul_config_req (nfapi_pnf_p7_config_t* pnf_p7, nfapi_ul_config_request_t* req)
+int memcpy_ul_config_req (nfapi_pnf_p7_config_t* pnf_p7, nfapi_ul_config_request_t* req)
 {
 	module_id_t Mod_id = 0; //Panos: Currently static (only for one UE) but this should change.
 	UE_mac_inst[Mod_id].ul_config_req = req;
+	return 0;
 }
 
-void memcpy_tx_req (nfapi_pnf_p7_config_t* pnf_p7, nfapi_tx_request_t* req)
+int memcpy_tx_req (nfapi_pnf_p7_config_t* pnf_p7, nfapi_tx_request_t* req)
 {
 	module_id_t Mod_id = 0; //Panos: Currently static (only for one UE) but this should change.
 	UE_mac_inst[Mod_id].tx_req = req;
+	return 0;
 }
 
-void memcpy_hi_dci0_req (nfapi_pnf_p7_config_t* pnf_p7, nfapi_hi_dci0_request_t* req)
+int memcpy_hi_dci0_req (nfapi_pnf_p7_config_t* pnf_p7, nfapi_hi_dci0_request_t* req)
 {
 	module_id_t Mod_id = 0; //Panos: Currently static (only for one UE) but this should change.
 	UE_mac_inst[Mod_id].hi_dci0_req = req;
+	return 0;
 }
 
 
diff --git a/openair2/PHY_INTERFACE/phy_stub_UE.h b/openair2/PHY_INTERFACE/phy_stub_UE.h
index 69d3e2b9823..4cb56d02237 100644
--- a/openair2/PHY_INTERFACE/phy_stub_UE.h
+++ b/openair2/PHY_INTERFACE/phy_stub_UE.h
@@ -87,16 +87,16 @@ int hi_dci0_req_UE_MAC(nfapi_hi_dci0_request_t* req);
 // The following set of memcpy functions should be getting called as callback functions from
 // pnf_p7_subframe_ind.
 
-void memcpy_dl_config_req (nfapi_pnf_p7_config_t* pnf_p7, nfapi_dl_config_request_t* req);
+int memcpy_dl_config_req (nfapi_pnf_p7_config_t* pnf_p7, nfapi_dl_config_request_t* req);
 
 
-void memcpy_ul_config_req (nfapi_pnf_p7_config_t* pnf_p7, nfapi_ul_config_request_t* req);
+int memcpy_ul_config_req (nfapi_pnf_p7_config_t* pnf_p7, nfapi_ul_config_request_t* req);
 
 
-void memcpy_tx_req (nfapi_pnf_p7_config_t* pnf_p7, nfapi_tx_request_t* req);
+int memcpy_tx_req (nfapi_pnf_p7_config_t* pnf_p7, nfapi_tx_request_t* req);
 
 
-void memcpy_hi_dci0_req (nfapi_pnf_p7_config_t* pnf_p7, nfapi_hi_dci0_request_t* req);
+int memcpy_hi_dci0_req (nfapi_pnf_p7_config_t* pnf_p7, nfapi_hi_dci0_request_t* req);
 
 
 
diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c
index 09e59b4d3ee..e97ed62d512 100644
--- a/targets/RT/USER/lte-ue.c
+++ b/targets/RT/USER/lte-ue.c
@@ -73,8 +73,10 @@ typedef enum {
 } sync_mode_t;
 
 void init_UE_threads(int);
+void init_UE_threads_stub(int);
 void *UE_thread(void *arg);
 void init_UE(int nb_inst,int,int);
+extern void oai_subframe_ind(uint16_t sfn, uint16_t sf);
 //extern int tx_req_UE_MAC1();
 
 int32_t **rxdata;
@@ -162,10 +164,15 @@ PHY_VARS_UE* init_ue_vars(LTE_DL_FRAME_PARMS *frame_parms,
 
   ue->Mod_id      = UE_id;
   ue->mac_enabled = 1;
+
+  // Panos: In phy_stub_UE (MAC-to-MAC) mode these init functions don't need to get called. Is this correct?
+  if (nfapi_mode!=3)
+  {
   // initialize all signal buffers
   init_lte_ue_signal(ue,1,abstraction_flag);
   // intialize transport
   init_lte_ue_transport(ue,abstraction_flag);
+  }
 
   return(ue);
 }
@@ -258,6 +265,58 @@ void init_UE(int nb_inst,int eMBMS_active, int uecap_xer_in) {
 #endif
 }
 
+
+void init_UE_stub(int nb_inst,int eMBMS_active, int uecap_xer_in) {
+
+  PHY_VARS_UE *UE;
+  int         inst;
+  //int         ret;
+
+  LOG_I(PHY,"UE : Calling Layer 2 for initialization\n");
+
+  l2_init_ue(eMBMS_active,(uecap_xer_in==1)?uecap_xer:NULL,
+	     0,// cba_group_active
+	     0); // HO flag
+
+  for (inst=0;inst<nb_inst;inst++) {
+
+    LOG_I(PHY,"Initializing memory for UE instance %d (%p)\n",inst,PHY_vars_UE_g[inst]);
+    PHY_vars_UE_g[inst][0] = init_ue_vars(NULL,inst,0);
+
+    LOG_I(PHY,"Intializing UE Threads for instance %d (%p,%p)...\n",inst,PHY_vars_UE_g[inst],PHY_vars_UE_g[inst][0]);
+    init_UE_threads_stub(inst);
+    UE = PHY_vars_UE_g[inst][0];
+
+    /*if (oaisim_flag == 0) {
+      ret = openair0_device_load(&(UE->rfdevice), &openair0_cfg[0]);
+      if (ret !=0){
+	exit_fun("Error loading device library");
+      }
+    }*/
+    //UE->rfdevice.host_type = RAU_HOST;
+    //    UE->rfdevice.type      = NONE_DEV;
+
+    /*PHY_VARS_UE *UE = PHY_vars_UE_g[inst][0];
+    AssertFatal(0 == pthread_create(&UE->proc.pthread_ue,
+                                    &UE->proc.attr_ue,
+                                    UE_thread,
+                                    (void*)UE), "");*/
+  }
+
+  printf("UE threads created \n");
+#if 0
+#if defined(ENABLE_USE_MME)
+  extern volatile int start_UE;
+  while (start_UE == 0) {
+    sleep(1);
+  }
+#endif
+#endif
+}
+
+
+
+
 /*!
  * \brief This is the UE synchronize thread.
  * It performs band scanning and synchonization.
@@ -569,17 +628,12 @@ static void *UE_thread_synch(void *arg)
  */
 
 static void *UE_thread_rxn_txnp4(void *arg) {
-	module_id_t Mod_id = 0;
     static __thread int UE_thread_rxtx_retval;
     struct rx_tx_thread_data *rtd = arg;
     UE_rxtx_proc_t *proc = rtd->proc;
     PHY_VARS_UE    *UE   = rtd->UE;
     int ret;
 
-    // Panos: Call (Sched_Rsp_t) get_nfapi_sched_response(UE->Mod_ID) to get all
-    //sched_response config messages which concern the specific UE. Inside this
-    //function we should somehow make the translation of rnti to Mod_ID.
-
     proc->instance_cnt_rxtx=-1;
     proc->subframe_rx=proc->sub_frame_start;
 
@@ -617,6 +671,175 @@ static void *UE_thread_rxn_txnp4(void *arg) {
         pickTime(current);
         updateTimes(proc->gotIQs, &t2, 10000, "Delay to wake up UE_Thread_Rx (case 2)");
 
+        // Process Rx data for one sub-frame
+        lte_subframe_t sf_type = subframe_select( &UE->frame_parms, proc->subframe_rx);
+        if ((sf_type == SF_DL) ||
+                (UE->frame_parms.frame_type == FDD) ||
+                (sf_type == SF_S)) {
+
+            if (UE->frame_parms.frame_type == TDD) {
+                LOG_D(PHY, "%s,TDD%d,%s: calling UE_RX\n",
+                      threadname,
+                      UE->frame_parms.tdd_config,
+                      (sf_type==SF_DL? "SF_DL" :
+                       (sf_type==SF_UL? "SF_UL" :
+                        (sf_type==SF_S ? "SF_S"  : "UNKNOWN_SF_TYPE"))));
+            } else {
+                LOG_D(PHY, "%s,%s,%s: calling UE_RX\n",
+                      threadname,
+                      (UE->frame_parms.frame_type==FDD? "FDD":
+                       (UE->frame_parms.frame_type==TDD? "TDD":"UNKNOWN_DUPLEX_MODE")),
+                      (sf_type==SF_DL? "SF_DL" :
+                       (sf_type==SF_UL? "SF_UL" :
+                        (sf_type==SF_S ? "SF_S"  : "UNKNOWN_SF_TYPE"))));
+            }
+#ifdef UE_SLOT_PARALLELISATION
+            phy_procedures_slot_parallelization_UE_RX( UE, proc, 0, 0, 1, UE->mode, no_relay, NULL );
+#else
+            phy_procedures_UE_RX( UE, proc, 0, 0, 1, UE->mode, no_relay, NULL );
+#endif
+        }
+
+#if UE_TIMING_TRACE
+        start_meas(&UE->generic_stat);
+#endif
+        if (UE->mac_enabled==1) {
+
+            ret = ue_scheduler(UE->Mod_id,
+			       proc->frame_rx,
+			       proc->subframe_rx,
+			       proc->frame_tx,
+			       proc->subframe_tx,
+			       subframe_select(&UE->frame_parms,proc->subframe_tx),
+			       0,
+			       0/*FIXME CC_id*/);
+            if ( ret != CONNECTION_OK) {
+                char *txt;
+                switch (ret) {
+                case CONNECTION_LOST:
+                    txt="RRC Connection lost, returning to PRACH";
+                    break;
+                case PHY_RESYNCH:
+                    txt="RRC Connection lost, trying to resynch";
+                    break;
+                case RESYNCH:
+                    txt="return to PRACH and perform a contention-free access";
+                    break;
+                default:
+                    txt="UNKNOWN RETURN CODE";
+                };
+                LOG_E( PHY, "[UE %"PRIu8"] Frame %"PRIu32", subframe %u %s\n",
+                       UE->Mod_id, proc->frame_rx, proc->subframe_tx,txt );
+            }
+        }
+#if UE_TIMING_TRACE
+        stop_meas(&UE->generic_stat);
+#endif
+
+
+        // Prepare the future Tx data
+
+        if ((subframe_select( &UE->frame_parms, proc->subframe_tx) == SF_UL) ||
+	    (UE->frame_parms.frame_type == FDD) )
+            if (UE->mode != loop_through_memory)
+                phy_procedures_UE_TX(UE,proc,0,0,UE->mode,no_relay);
+
+
+
+        if ((subframe_select( &UE->frame_parms, proc->subframe_tx) == SF_S) &&
+                (UE->frame_parms.frame_type == TDD))
+            if (UE->mode != loop_through_memory)
+                phy_procedures_UE_S_TX(UE,0,0,no_relay);
+        updateTimes(current, &t3, 10000, "Delay to process sub-frame (case 3)");
+
+        if (pthread_mutex_lock(&proc->mutex_rxtx) != 0) {
+          LOG_E( PHY, "[SCHED][UE] error locking mutex for UE RXTX\n" );
+          exit_fun("noting to add");
+        }
+        proc->instance_cnt_rxtx--;
+        if (pthread_mutex_unlock(&proc->mutex_rxtx) != 0) {
+          LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE RXTX\n" );
+          exit_fun("noting to add");
+        }
+    }
+
+// thread finished
+    free(arg);
+    return &UE_thread_rxtx_retval;
+}
+
+
+
+
+
+/*!
+ * \brief This is the UE thread for RX subframe n and TX subframe n+4.
+ * This thread performs the phy_procedures_UE_RX() on every received slot.
+ * then, if TX is enabled it performs TX for n+4.
+ * \param arg is a pointer to a \ref PHY_VARS_UE structure.
+ * \returns a pointer to an int. The storage is not on the heap and must not be freed.
+ */
+
+static void *UE_phy_stub_thread_rxn_txnp4(void *arg) {
+	module_id_t Mod_id = 0;
+    static __thread int UE_thread_rxtx_retval;
+    struct rx_tx_thread_data *rtd = arg;
+    UE_rxtx_proc_t *proc = rtd->proc;
+    PHY_VARS_UE    *UE   = rtd->UE;
+    int ret;
+
+    // Panos: Call (Sched_Rsp_t) get_nfapi_sched_response(UE->Mod_ID) to get all
+    //sched_response config messages which concern the specific UE. Inside this
+    //function we should somehow make the translation of rnti to Mod_ID.
+
+    //proc->instance_cnt_rxtx=-1;
+
+    phy_stub_ticking->ticking_var = -1;
+    proc->subframe_rx=proc->sub_frame_start;
+
+    char threadname[256];
+    sprintf(threadname,"UE_%d_proc_%d", UE->Mod_id, proc->sub_frame_start);
+    cpu_set_t cpuset;
+    CPU_ZERO(&cpuset);
+
+    if ( (proc->sub_frame_start+1)%RX_NB_TH == 0 && threads.one != -1 )
+        CPU_SET(threads.one, &cpuset);
+    if ( (proc->sub_frame_start+1)%RX_NB_TH == 1 && threads.two != -1 )
+        CPU_SET(threads.two, &cpuset);
+    if ( (proc->sub_frame_start+1)%RX_NB_TH == 2 && threads.three != -1 )
+        CPU_SET(threads.three, &cpuset);
+            //CPU_SET(threads.three, &cpuset);
+    init_thread(900000,1000000 , FIFO_PRIORITY-1, &cpuset,
+                threadname);
+
+    while (!oai_exit) {
+        if (pthread_mutex_lock(&phy_stub_ticking->mutex_ticking) != 0) {
+          LOG_E( PHY, "[SCHED][UE] error locking mutex for UE RXTX\n" );
+          exit_fun("nothing to add");
+        }
+        while (phy_stub_ticking->ticking_var < 0) {
+          // most of the time, the thread is waiting here
+          //pthread_cond_wait( &proc->cond_rxtx, &proc->mutex_rxtx );
+          pthread_cond_wait( &phy_stub_ticking->cond_ticking, &phy_stub_ticking->mutex_ticking);
+        }
+        if (pthread_mutex_unlock(&phy_stub_ticking->mutex_ticking) != 0) {
+          LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE RXn_TXnp4\n" );
+          exit_fun("nothing to add");
+        }
+
+        proc->subframe_rx=timer_subframe;
+        proc->frame_rx = timer_frame;
+        proc->subframe_tx=(timer_subframe+4)%10;
+        proc->frame_tx = proc->frame_rx + (proc->subframe_rx>5?1:0);
+
+
+        // Panos: Guessing that the next 4 lines are not needed for the phy_stub mode.
+        /*initRefTimes(t2);
+        initRefTimes(t3);
+        pickTime(current);
+        updateTimes(proc->gotIQs, &t2, 10000, "Delay to wake up UE_Thread_Rx (case 2)");*/
+
+
         // Process Rx data for one sub-frame
         lte_subframe_t sf_type = subframe_select( &UE->frame_parms, proc->subframe_rx);
         if ((sf_type == SF_DL) ||
@@ -640,27 +863,25 @@ static void *UE_thread_rxn_txnp4(void *arg) {
                         (sf_type==SF_S ? "SF_S"  : "UNKNOWN_SF_TYPE"))));
             }
 
+/*
 #ifdef UE_SLOT_PARALLELISATION
             phy_procedures_slot_parallelization_UE_RX( UE, proc, 0, 0, 1, UE->mode, no_relay, NULL );
 #else
+*/
 			// Panos: Substitute call to phy_procedures Rx with call to phy_stub functions in order to trigger
             // UE Rx procedures directly at the MAC layer, based on the received nfapi requests from the vnf (eNB).
             // Hardcode Mod_id for now. Will be changed later.
 
-            if(nfapi_mode == 3){
-            	// Panos: is this the right place to call oai_subframe_indication to invoke p7 nfapi callbacks here?
-            	//oai_subframe_insdication()
-            	if(UE_mac_inst[Mod_id].tx_req)
-            		tx_req_UE_MAC(UE_mac_inst[Mod_id].tx_req);
-            	if(UE_mac_inst[Mod_id].dl_config_req)
-            		dl_config_req_UE_MAC(UE_mac_inst[Mod_id].dl_config_req);
-            	if(UE_mac_inst[Mod_id].hi_dci0_req)
-            		hi_dci0_req_UE_MAC(UE_mac_inst[Mod_id].hi_dci0_req);
-            }
-            else{
-            phy_procedures_UE_RX( UE, proc, 0, 0, 1, UE->mode, no_relay, NULL );
-            }
-#endif
+            // Panos: is this the right place to call oai_subframe_indication to invoke p7 nfapi callbacks here?
+            oai_subframe_ind(proc->frame_rx, proc->subframe_rx);
+            if(UE_mac_inst[Mod_id].tx_req!= NULL)
+            	tx_req_UE_MAC(UE_mac_inst[Mod_id].tx_req);
+            if(UE_mac_inst[Mod_id].dl_config_req!= NULL)
+            	dl_config_req_UE_MAC(UE_mac_inst[Mod_id].dl_config_req);
+            if(UE_mac_inst[Mod_id].hi_dci0_req!= NULL)
+            	hi_dci0_req_UE_MAC(UE_mac_inst[Mod_id].hi_dci0_req);
+
+//#endif
         }
 
 #if UE_TIMING_TRACE
@@ -708,30 +929,31 @@ static void *UE_thread_rxn_txnp4(void *arg) {
             	// Panos: Substitute call to phy_procedures Tx with call to phy_stub functions in order to trigger
                 // UE Tx procedures directly at the MAC layer, based on the received ul_config requests from the vnf (eNB).
             	// Generate UL_indications which corresponf to UL traffic.
-            	if(nfapi_mode == 3 && UE_mac_inst[Mod_id].ul_config_req){
+            	if(UE_mac_inst[Mod_id].ul_config_req!= NULL){
             		ul_config_req_UE_MAC(UE_mac_inst[Mod_id].ul_config_req);
             		UL_indication(UL_INFO);
             	}
-            	else{
-            	phy_procedures_UE_TX(UE,proc,0,0,UE->mode,no_relay);
-            	}
             }
 
 
 
 
-        if ((subframe_select( &UE->frame_parms, proc->subframe_tx) == SF_S) &&
+        /*if ((subframe_select( &UE->frame_parms, proc->subframe_tx) == SF_S) &&
                 (UE->frame_parms.frame_type == TDD))
             if (UE->mode != loop_through_memory)
                 phy_procedures_UE_S_TX(UE,0,0,no_relay);
-        updateTimes(current, &t3, 10000, "Delay to process sub-frame (case 3)");
+        updateTimes(current, &t3, 10000, "Delay to process sub-frame (case 3)");*/
 
-        if (pthread_mutex_lock(&proc->mutex_rxtx) != 0) {
+        //if (pthread_mutex_lock(&proc->mutex_rxtx) != 0) {
+        if (pthread_mutex_lock(&phy_stub_ticking->mutex_ticking) != 0) {
           LOG_E( PHY, "[SCHED][UE] error locking mutex for UE RXTX\n" );
           exit_fun("noting to add");
         }
-        proc->instance_cnt_rxtx--;
-        if (pthread_mutex_unlock(&proc->mutex_rxtx) != 0) {
+
+        //proc->instance_cnt_rxtx--;
+        phy_stub_ticking->ticking_var--;
+        //if (pthread_mutex_unlock(&proc->mutex_rxtx) != 0) {
+        if (pthread_mutex_unlock(&phy_stub_ticking->mutex_ticking) != 0) {
           LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE RXTX\n" );
           exit_fun("noting to add");
         }
@@ -742,6 +964,8 @@ static void *UE_thread_rxn_txnp4(void *arg) {
     return &UE_thread_rxtx_retval;
 }
 
+
+
 /*!
  * \brief This is the main UE thread.
  * This thread controls the other three UE threads:
@@ -751,7 +975,7 @@ static void *UE_thread_rxn_txnp4(void *arg) {
  * \param arg unused
  * \returns a pointer to an int. The storage is not on the heap and must not be freed.
  */
-// Panos: Modified function to support nfapi_mode=3 (phy_stub mode).
+
 void *UE_thread(void *arg) {
 
 
@@ -780,16 +1004,11 @@ void *UE_thread(void *arg) {
 #endif
 
     int sub_frame=-1;
-    if(nfapi_mode==3) {
-    	phy_stub_ticking->ticking_var = -1;
-    }
-
     //int cumulated_shift=0;
 
 
     while (!oai_exit) {
-    	if(nfapi_mode!=3) {
-    	AssertFatal ( 0== pthread_mutex_lock(&UE->proc.mutex_synch), "");
+        AssertFatal ( 0== pthread_mutex_lock(&UE->proc.mutex_synch), "");
         int instance_cnt_synch = UE->proc.instance_cnt_synch;
         int is_synchronized    = UE->is_synchronized;
         AssertFatal ( 0== pthread_mutex_unlock(&UE->proc.mutex_synch), "");
@@ -948,7 +1167,6 @@ void *UE_thread(void *arg) {
                     pickTime(gotIQs);
                     // operate on thread sf mod 2
                     AssertFatal(pthread_mutex_lock(&proc->mutex_rxtx) ==0,"");
-
                     if(sub_frame == 0) {
                         //UE->proc.proc_rxtx[0].frame_rx++;
                         //UE->proc.proc_rxtx[1].frame_rx++;
@@ -995,72 +1213,6 @@ void *UE_thread(void *arg) {
             } // start_rx_stream==1
         } // UE->is_synchronized==1
 
-    } // nfapi_mode!=3
-    	else { // nfapi_mode==3
-
-    		//AssertFatal ( 0== pthread_mutex_lock(&UE->proc.mutex_ticking), "");
-    		AssertFatal ( 0== pthread_mutex_lock(&phy_stub_ticking->mutex_ticking), "");
-    		while (phy_stub_ticking->ticking_var<0)
-    			pthread_cond_wait( &phy_stub_ticking->cond_ticking, &phy_stub_ticking->mutex_ticking);
-    		AssertFatal ( 0== pthread_mutex_unlock(&phy_stub_ticking->mutex_ticking), "");
-
-    		UE_rxtx_proc_t *proc = &UE->proc.proc_rxtx[thread_idx];
-    		// update thread index for received subframe
-    		UE->current_thread_id[sub_frame] = thread_idx;
-    		LOG_D(PHY,"Process Subframe %d thread Idx %d \n", sub_frame, UE->current_thread_id[sub_frame]);
-    		thread_idx++;
-    		if(thread_idx>=RX_NB_TH)
-    			thread_idx = 0;
-
-    		// Panos: timer_subframe/timer_frame (phy_stub mode SFN/SF counter) acquired from thread_timer.
-    		if(timer_subframe == 0) {
-    			//UE->proc.proc_rxtx[0].frame_rx++;
-    			//UE->proc.proc_rxtx[1].frame_rx++;
-    			for (th_id=0; th_id < RX_NB_TH; th_id++) {
-    				//UE->proc.proc_rxtx[th_id].frame_rx++;
-    				UE->proc.proc_rxtx[th_id].frame_rx = timer_frame;
-    			}
-    		}
-    		//UE->proc.proc_rxtx[0].gotIQs=readTime(gotIQs);
-    		//UE->proc.proc_rxtx[1].gotIQs=readTime(gotIQs);
-
-    		// Panos: Remove for phy_stub
-    		/*for (th_id=0; th_id < RX_NB_TH; th_id++) {
-    			UE->proc.proc_rxtx[th_id].gotIQs=readTime(gotIQs);
-    		}*/
-
-    		proc->subframe_rx=timer_subframe;
-    		proc->subframe_tx=(sub_frame+4)%10;
-    		proc->frame_tx = proc->frame_rx + (proc->subframe_rx>5?1:0);
-
-    		// Panos: Do we need the timestamp_tx indication for phy_stub mode?
-    		proc->timestamp_tx = timestamp+
-    				(4*UE->frame_parms.samples_per_tti)-
-    				UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0;
-    		proc->instance_cnt_rxtx++;
-
-    		LOG_D( PHY, "[SCHED][UE %d] UE RX instance_cnt_rxtx %d subframe %d !!\n", UE->Mod_id, proc->instance_cnt_rxtx,proc->subframe_rx);
-    		if (proc->instance_cnt_rxtx == 0) {
-    			if (pthread_cond_signal(&proc->cond_rxtx) != 0) {
-    				LOG_E( PHY, "[SCHED][UE %d] ERROR pthread_cond_signal for UE RX thread\n", UE->Mod_id);
-    				exit_fun("nothing to add");
-    			}
-    		} else {
-    			LOG_E( PHY, "[SCHED][UE %d] UE RX thread busy (IC %d)!!\n", UE->Mod_id, proc->instance_cnt_rxtx);
-    			if (proc->instance_cnt_rxtx > 2)
-    				exit_fun("instance_cnt_rxtx > 2");
-    		}
-    		AssertFatal (pthread_cond_signal(&proc->cond_rxtx) ==0 ,"");
-    		AssertFatal(pthread_mutex_unlock(&proc->mutex_rxtx) ==0,"");
-
-    		// Panos: Do we need these function calls for the phy_stub?
-    		/*initRefTimes(t1);
-    		initStaticTime(lastTime);
-    		updateTimes(lastTime, &t1, 20000, "Delay between two IQ acquisitions (case 1)");
-    		pickStaticTime(lastTime);*/
-    		phy_stub_ticking->ticking_var--;
-    		}
-
     } // while !oai_exit
     return NULL;
 }
@@ -1123,6 +1275,69 @@ void init_UE_threads(int inst) {
 }
 
 
+
+/*!
+ * \brief Initialize the UE theads.
+ * Creates the UE threads:
+ * - UE_thread_rxtx0
+ * - UE_thread_synch
+ * - UE_thread_fep_slot0
+ * - UE_thread_fep_slot1
+ * - UE_thread_dlsch_proc_slot0
+ * - UE_thread_dlsch_proc_slot1
+ * and the locking between them.
+ */
+void init_UE_threads_stub(int inst) {
+    struct rx_tx_thread_data *rtd;
+    PHY_VARS_UE *UE;
+
+    AssertFatal(PHY_vars_UE_g!=NULL,"PHY_vars_UE_g is NULL\n");
+    AssertFatal(PHY_vars_UE_g[inst]!=NULL,"PHY_vars_UE_g[inst] is NULL\n");
+    AssertFatal(PHY_vars_UE_g[inst][0]!=NULL,"PHY_vars_UE_g[inst][0] is NULL\n");
+    UE = PHY_vars_UE_g[inst][0];
+
+    pthread_attr_init (&UE->proc.attr_ue);
+    pthread_attr_setstacksize(&UE->proc.attr_ue,8192);//5*PTHREAD_STACK_MIN);
+
+    // Panos: Don't need synch for phy_stub mode
+    //pthread_mutex_init(&UE->proc.mutex_synch,NULL);
+    //pthread_cond_init(&UE->proc.cond_synch,NULL);
+
+    // the threads are not yet active, therefore access is allowed without locking
+    // Panos: In phy_stub_UE mode due to less heavy processing operations we don't need two threads
+    //int nb_threads=RX_NB_TH;
+    int nb_threads=1;
+    for (int i=0; i<nb_threads; i++) {
+        rtd = calloc(1, sizeof(struct rx_tx_thread_data));
+        if (rtd == NULL) abort();
+        rtd->UE = UE;
+        rtd->proc = &UE->proc.proc_rxtx[i];
+
+        pthread_mutex_init(&UE->proc.proc_rxtx[i].mutex_rxtx,NULL);
+        pthread_cond_init(&UE->proc.proc_rxtx[i].cond_rxtx,NULL);
+        UE->proc.proc_rxtx[i].sub_frame_start=i;
+        UE->proc.proc_rxtx[i].sub_frame_step=nb_threads;
+        printf("Init_UE_threads rtd %d proc %d nb_threads %d i %d\n",rtd->proc->sub_frame_start, UE->proc.proc_rxtx[i].sub_frame_start,nb_threads, i);
+        pthread_create(&UE->proc.proc_rxtx[i].pthread_rxtx, NULL, UE_phy_stub_thread_rxn_txnp4, rtd);
+/*
+#ifdef UE_SLOT_PARALLELISATION
+        //pthread_mutex_init(&UE->proc.proc_rxtx[i].mutex_slot0_dl_processing,NULL);
+        //pthread_cond_init(&UE->proc.proc_rxtx[i].cond_slot0_dl_processing,NULL);
+        //pthread_create(&UE->proc.proc_rxtx[i].pthread_slot0_dl_processing,NULL,UE_thread_slot0_dl_processing, rtd);
+
+        pthread_mutex_init(&UE->proc.proc_rxtx[i].mutex_slot1_dl_processing,NULL);
+        pthread_cond_init(&UE->proc.proc_rxtx[i].cond_slot1_dl_processing,NULL);
+        pthread_create(&UE->proc.proc_rxtx[i].pthread_slot1_dl_processing,NULL,UE_thread_slot1_dl_processing, rtd);
+#endif*/
+
+    }
+    // Panos: Remove thread for UE_sync in phy_stub_UE mode.
+    //pthread_create(&UE->proc.pthread_synch,NULL,UE_thread_synch,(void*)UE);
+}
+
+
+
+
 #ifdef OPENAIR2
 void fill_ue_band_info(void) {
 
@@ -1202,6 +1417,8 @@ static void* timer_thread( void* param ) {
 	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);
 
 	while (!oai_exit) {
 	    usleep(1000);
@@ -1214,18 +1431,25 @@ static void* timer_thread( void* param ) {
 	    } else {
 	    	timer_subframe++;
 	    }
-	    phy_stub_ticking->ticking_var++;
 	    //AssertFatal( 0 == pthread_cond_signal(&phy_stub_ticking->cond_ticking), "");
-	    if (pthread_cond_signal(&phy_stub_ticking->cond_ticking) != 0) {
-	    	//LOG_E( PHY, "[SCHED][UE %d] ERROR pthread_cond_signal for UE RX thread\n", UE->Mod_id);
-	    	LOG_E( PHY, "timer_thread ERROR pthread_cond_signal for UE_thread\n");
-	    	exit_fun("nothing to add");
+	    AssertFatal(pthread_mutex_lock(&phy_stub_ticking->mutex_ticking) ==0,"");
+	    phy_stub_ticking->ticking_var++;
+	    // This should probably be a call to pthread_cond_broadcast when we introduce support for multiple UEs (threads)
+	    if(phy_stub_ticking->ticking_var == 0) {
+	    	if (pthread_cond_signal(&phy_stub_ticking->cond_ticking) != 0) {
+	    		//LOG_E( PHY, "[SCHED][UE %d] ERROR pthread_cond_signal for UE RX thread\n", UE->Mod_id);
+	    		LOG_E( PHY, "timer_thread ERROR pthread_cond_signal for UE_thread\n");
+	    		exit_fun("nothing to add");
+	    	}
 	    }
+	    AssertFatal(pthread_mutex_unlock(&phy_stub_ticking->mutex_ticking) ==0,"");
 	    //UE->proc.ticking_var++;
 	    // pthread_cond_signal() //Send signal to ue_thread()?
 	    // We also need to somehow pass the information of SFN/SF
 	  }
 	free(phy_stub_ticking);
+	pthread_cond_destroy(&phy_stub_ticking->cond_ticking);
+	pthread_mutex_destroy(&phy_stub_ticking->mutex_ticking);
 	return 0;
 
 }
-- 
GitLab