diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h
index 3d55b25a74f5e541f3bf3e46640d90c59a7a00cf..b8bf9524ad3e24a60e3e978572c78450bc21cf28 100644
--- a/openair1/PHY/defs.h
+++ b/openair1/PHY/defs.h
@@ -651,6 +651,20 @@ typedef struct {
   UE_rxtx_proc_t proc_rxtx[RX_NB_TH];
 } UE_proc_t;
 
+
+/// Panos: Structure holding timer_thread related elements (phy_stub_UE mode)
+typedef struct{
+	/// Panos: mutex for waiting SF ticking
+	pthread_mutex_t mutex_ticking;
+	/// Panos: \brief ticking var for ticking thread.
+	/// \internal This variable is protected by \ref mutex_ticking.
+	int ticking_var;
+	/// condition variable for timer_thread;
+	pthread_cond_t cond_ticking;
+}SF_ticking;
+
+
+
 typedef enum {
   LOCAL_RF        =0,
   REMOTE_IF5      =1,
diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c
index 11ce1a281edeb0330ce5e836eece7ec207356276..f3c28546c1ac763dde254afdfc6118c16c43ffdd 100644
--- a/targets/RT/USER/lte-ue.c
+++ b/targets/RT/USER/lte-ue.c
@@ -80,6 +80,10 @@ void init_UE(int nb_inst,int,int);
 int32_t **rxdata;
 int32_t **txdata;
 
+int timer_subframe;
+int timer_frame;
+SF_ticking *phy_stub_ticking;
+
 #define KHz (1000UL)
 #define MHz (1000*KHz)
 
@@ -745,7 +749,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) {
 
 
@@ -776,9 +780,10 @@ void *UE_thread(void *arg) {
     int sub_frame=-1;
     //int cumulated_shift=0;
 
-    
+
     while (!oai_exit) {
-        AssertFatal ( 0== pthread_mutex_lock(&UE->proc.mutex_synch), "");
+    	if(nfapi_mode!=3) {
+    	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), "");
@@ -937,6 +942,7 @@ 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++;
@@ -983,10 +989,77 @@ 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;
 }
 
+
 /*!
  * \brief Initialize the UE theads.
  * Creates the UE threads:
@@ -1114,3 +1187,47 @@ 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->ticking_var = -1;
+	wait_sync("timer_thread");
+
+	while (!oai_exit) {
+	    usleep(1000);
+	    // 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 (timer_subframe==9) {
+	    	timer_subframe=0;
+	    	timer_frame++;
+	    	timer_frame&=1023;
+	    } 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");
+	    }
+	    //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);
+	return 0;
+
+}
+
+
+
+
+
+
+
+