From d8c35774aa0666742ea089eb6a68c78ea7f46036 Mon Sep 17 00:00:00 2001
From: Raymond Knoppp <raymond.knopp@eurecom.fr>
Date: Tue, 27 Nov 2018 12:30:10 +0100
Subject: [PATCH] modifications at slave RRU

---
 openair1/PHY/INIT/lte_init_ru.c               |  43 +-
 .../PHY/LTE_ESTIMATION/lte_adjust_sync_eNB.c  |  14 +-
 openair1/PHY/LTE_ESTIMATION/lte_estimation.h  |  13 +
 openair1/PHY/LTE_ESTIMATION/lte_sync_time.c   |  18 +-
 .../lte_ul_channel_estimation.c               | 374 +++++++++++++++++-
 openair1/PHY/MODULATION/ul_7_5_kHz.c          |  13 +-
 openair1/PHY/defs_eNB.h                       |   9 +-
 openair1/PHY/impl_defs_lte.h                  |  17 +-
 openair1/SCHED/ru_procedures.c                |  85 +++-
 targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c |   2 +-
 targets/RT/USER/lte-ru.c                      |  53 ++-
 11 files changed, 601 insertions(+), 40 deletions(-)

diff --git a/openair1/PHY/INIT/lte_init_ru.c b/openair1/PHY/INIT/lte_init_ru.c
index 17435c1af2..b1c57e052f 100644
--- a/openair1/PHY/INIT/lte_init_ru.c
+++ b/openair1/PHY/INIT/lte_init_ru.c
@@ -36,26 +36,38 @@ void init_7_5KHz(void);
 int phy_init_RU(RU_t *ru) {
 
   LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
+  RU_CALIBRATION *calibration = &ru->calibration;
   int i,j;
   int p;
   int re;
 
   LOG_I(PHY,"Initializing RU signal buffers (if_south %s) nb_tx %d\n",ru_if_types[ru->if_south],ru->nb_tx);
 
+  if (ru->is_slave == 1) {
+ 	 generate_ul_ref_sigs_rx();
+       	 init_dfts();
+  }
+
   if (ru->if_south <= REMOTE_IF5) { // this means REMOTE_IF5 or LOCAL_RF, so allocate memory for time-domain signals 
     // Time-domain signals
     ru->common.txdata        = (int32_t**)malloc16(ru->nb_tx*sizeof(int32_t*));
     ru->common.rxdata        = (int32_t**)malloc16(ru->nb_rx*sizeof(int32_t*) );
 
-
     for (i=0; i<ru->nb_tx; i++) {
       // Allocate 10 subframes of I/Q TX signal data (time) if not
       ru->common.txdata[i]  = (int32_t*)malloc16_clear( fp->samples_per_tti*10*sizeof(int32_t) );
-
       LOG_I(PHY,"[INIT] common.txdata[%d] = %p (%lu bytes)\n",i,ru->common.txdata[i],
 	     fp->samples_per_tti*10*sizeof(int32_t));
+    }
 
+    if (ru->is_slave == 1) {
+        calibration->drs_ch_estimates_time = (int32_t**)malloc16_clear(ru->nb_rx*sizeof(int32_t*));
+        for (i=0; i<ru->nb_rx; i++) {    
+        	calibration->drs_ch_estimates_time[i] = (int32_t*)malloc16_clear(2*sizeof(int32_t)*fp->ofdm_symbol_size);
+        }
     }
+
+
     for (i=0;i<ru->nb_rx;i++) {
       ru->common.rxdata[i] = (int32_t*)malloc16_clear( fp->samples_per_tti*10*sizeof(int32_t) );
     }
@@ -91,6 +103,18 @@ int phy_init_RU(RU_t *ru) {
       ru->common.rxdataF[i] = (int32_t*)malloc16_clear(sizeof(int32_t)*(2*fp->ofdm_symbol_size*fp->symbols_per_tti) ); 
       LOG_I(PHY,"rxdataF[%d] %p for RU %d\n",i,ru->common.rxdataF[i],ru->idx);
     }
+    
+     if (ru->is_slave == 1) {
+     	// allocate FFT output buffers after extraction (RX)
+    	calibration->rxdataF_ext = (int32_t**)malloc16(2*sizeof(int32_t*));
+	calibration->drs_ch_estimates = (int32_t**)malloc16(2*sizeof(int32_t*));
+    	for (i=0; i<ru->nb_rx; i++) {    
+      		// allocate 2 subframes of I/Q signal data (frequency)
+      		calibration->rxdataF_ext[i] = (int32_t*)malloc16_clear(sizeof(int32_t)*fp->N_RB_UL*12*fp->symbols_per_tti ); 
+      		LOG_I(PHY,"rxdataF_ext[%d] %p for RU %d\n",i,calibration->rxdataF_ext[i],ru->idx);
+                calibration->drs_ch_estimates[i] = (int32_t*)malloc16_clear(sizeof(int32_t)*fp->N_RB_UL*12*fp->symbols_per_tti);
+    	}
+     }
 
     /* number of elements of an array X is computed as sizeof(X) / sizeof(X[0]) */
     //AssertFatal(ru->nb_rx <= sizeof(ru->prach_rxsigF) / sizeof(ru->prach_rxsigF[0]),
@@ -162,12 +186,19 @@ void phy_free_RU(RU_t *ru)
 {
   int i,j;
   int p;
+  RU_CALIBRATION *calibration = &ru->calibration;
 
   LOG_I(PHY, "Feeing RU signal buffers (if_south %s) nb_tx %d\n", ru_if_types[ru->if_south], ru->nb_tx);
 
   if (ru->if_south <= REMOTE_IF5) { // this means REMOTE_IF5 or LOCAL_RF, so free memory for time-domain signals
     for (i = 0; i < ru->nb_tx; i++) free_and_zero(ru->common.txdata[i]);
     for (i = 0; i < ru->nb_rx; i++) free_and_zero(ru->common.rxdata[i]);
+    if (ru->is_slave == 1) {  
+    	for (i = 0; i < ru->nb_rx; i++) {
+       		free_and_zero(calibration->drs_ch_estimates_time[i]);
+        }
+        free_and_zero(calibration->drs_ch_estimates_time);
+    }
     free_and_zero(ru->common.txdata);
     free_and_zero(ru->common.rxdata);
   } // else: IF5 or local RF -> nothing to free()
@@ -183,6 +214,14 @@ void phy_free_RU(RU_t *ru)
     // free FFT output buffers (RX)
     for (i = 0; i < ru->nb_rx; i++) free_and_zero(ru->common.rxdataF[i]);
     free_and_zero(ru->common.rxdataF);
+    if (ru->is_slave == 1) {
+    	for (i = 0; i < ru->nb_rx; i++) {
+        	free_and_zero(calibration->rxdataF_ext[i]);
+  		free_and_zero(calibration->drs_ch_estimates[i]);
+        }
+        free_and_zero(calibration->rxdataF_ext);
+        free_and_zero(calibration->drs_ch_estimates);
+    }
 
     for (i = 0; i < ru->nb_rx; i++) {
       free_and_zero(ru->prach_rxsigF[i]);
diff --git a/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync_eNB.c b/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync_eNB.c
index 61ce019577..07f417ad98 100644
--- a/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync_eNB.c
+++ b/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync_eNB.c
@@ -112,17 +112,23 @@ int lte_est_timing_advance(LTE_DL_FRAME_PARMS *frame_parms,
 }
 
 
-int lte_est_timing_advance_pusch(PHY_VARS_eNB* eNB,module_id_t UE_id)
+int lte_est_timing_advance_pusch(PHY_VARS_eNB *eNB,module_id_t UE_id)
 {
   int temp, i, aa, max_pos=0, max_val=0;
   short Re,Im;
 
-  LTE_DL_FRAME_PARMS *frame_parms = &eNB->frame_parms;
+  RU_t *ru;
+  ru = RC.ru[UE_id];
+  //LTE_DL_FRAME_PARMS *frame_parms = &eNB->frame_parms;
+  LTE_DL_FRAME_PARMS *frame_parms = (eNB==NULL) ? &ru->frame_parms : &eNB->frame_parms;
   LTE_eNB_PUSCH *eNB_pusch_vars = eNB->pusch_vars[UE_id];
-  int32_t **ul_ch_estimates_time=  eNB_pusch_vars->drs_ch_estimates_time;
+  RU_CALIBRATION *calibration = &ru->calibration;
+  //int32_t **ul_ch_estimates_time=  eNB_pusch_vars->drs_ch_estimates_time;
+  int32_t **ul_ch_estimates_time = calibration->drs_ch_estimates_time;
+  //int32_t **ul_ch_estimates_time = (eNB==NULL) ? calibration->drs_ch_estimates_time : eNB_pusch_vars->drs_ch_estimates_time;
   uint8_t cyclic_shift = 0;
   int sync_pos = (frame_parms->ofdm_symbol_size-cyclic_shift*frame_parms->ofdm_symbol_size/12)%(frame_parms->ofdm_symbol_size);
-
+  
   AssertFatal(frame_parms->ofdm_symbol_size > 127,"frame_parms->ofdm_symbol_size %d<128\n",frame_parms->ofdm_symbol_size);
   AssertFatal(frame_parms->nb_antennas_rx >0 && frame_parms->nb_antennas_rx<3,"frame_parms->nb_antennas_rx %d not in [0,1]\n",
 	      frame_parms->nb_antennas_rx);
diff --git a/openair1/PHY/LTE_ESTIMATION/lte_estimation.h b/openair1/PHY/LTE_ESTIMATION/lte_estimation.h
index 013b718e04..53d874a8fc 100644
--- a/openair1/PHY/LTE_ESTIMATION/lte_estimation.h
+++ b/openair1/PHY/LTE_ESTIMATION/lte_estimation.h
@@ -217,6 +217,19 @@ int lte_ul_channel_estimation(PHY_VARS_eNB *phy_vars_eNB,
                               uint8_t l,
                               uint8_t Ns);
 
+int32_t lte_ul_channel_estimation_RRU(LTE_DL_FRAME_PARMS *frame_parms,
+				  int32_t **ul_ch_estimates,
+				  int32_t **ul_ch_estimates_time,
+				  int32_t **rxdataF_ext,
+				  int N_rb_alloc,
+				  int frame_rx,
+				  int subframe_rx,
+				  uint32_t u,
+				  uint32_t v,
+				  uint32_t cyclic_shift,
+                                  unsigned char l,
+				  int interpolate,
+				  uint16_t rnti);
 
 int16_t lte_ul_freq_offset_estimation(LTE_DL_FRAME_PARMS *frame_parms,
                                       int32_t *ul_ch_estimates,
diff --git a/openair1/PHY/LTE_ESTIMATION/lte_sync_time.c b/openair1/PHY/LTE_ESTIMATION/lte_sync_time.c
index 1a0e8bdebe..d796cd7ebb 100644
--- a/openair1/PHY/LTE_ESTIMATION/lte_sync_time.c
+++ b/openair1/PHY/LTE_ESTIMATION/lte_sync_time.c
@@ -648,6 +648,7 @@ int ru_sync_time(RU_t *ru,
 
 
   LTE_DL_FRAME_PARMS *frame_parms = &ru->frame_parms;
+  RU_CALIBRATION *calibration = &ru->calibration;
 		      
   // perform a time domain correlation using the oversampled sync sequence
 
@@ -671,6 +672,14 @@ int ru_sync_time(RU_t *ru,
     maxval = max(maxval,ru->dmrssync[i]);
     maxval = max(maxval,-ru->dmrssync[i]);
   }
+
+  if (ru->state == RU_CHECK_SYNC) {
+  	for (int i=0;i<2*(frame_parms->ofdm_symbol_size);i++) {
+    		maxval = max(maxval,calibration->drs_ch_estimates_time[0][i]);
+	        maxval = max(maxval,-calibration->drs_ch_estimates_time[0][i]);
+        }
+  }
+
   int shift = log2_approx(maxval);
 
   for (int n=0; n<length; n+=4) {
@@ -684,6 +693,13 @@ int ru_sync_time(RU_t *ru,
 			      (int16_t*) &ru->common.rxdata[ar][n],
 			      frame_parms->ofdm_symbol_size,
 			      shift);     
+
+      if (ru->state == RU_CHECK_SYNC) {
+      	result  = dot_product64((int16_t*) &calibration->drs_ch_estimates_time[ar],
+                              (int16_t*) &ru->common.rxdata[ar][n],
+                              frame_parms->ofdm_symbol_size,
+                              shift);
+      }
       dmrs_corr += abs64(result);
     }
     if (ru->dmrs_corr != NULL) ru->dmrs_corr[n] = dmrs_corr;
@@ -696,7 +712,7 @@ int ru_sync_time(RU_t *ru,
   }
   avg0/=(length/4);
 
-  int dmrsoffset = frame_parms->samples_per_tti + (3*frame_parms->ofdm_symbol_size)+(2*frame_parms->nb_prefix_samples) + frame_parms->nb_prefix_samples0;
+  int dmrsoffset = frame_parms->samples_per_tti + (3*frame_parms->ofdm_symbol_size)+(3*frame_parms->nb_prefix_samples) + frame_parms->nb_prefix_samples0;
   
   if ((int64_t)maxlev0 > (10*avg0)) {*lev = maxlev0; *avg=avg0; return((length+maxpos0-dmrsoffset)%length);}
 
diff --git a/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c
index 206ba8b15f..44d8832e7a 100644
--- a/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c
+++ b/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c
@@ -39,14 +39,26 @@ int32_t lte_ul_channel_estimation(PHY_VARS_eNB *eNB,
                                   module_id_t UE_id,
                                   unsigned char l,
                                   unsigned char Ns) {
-
-  LTE_DL_FRAME_PARMS *frame_parms = &eNB->frame_parms;
+  RU_t *ru;
+  ru = RC.ru[UE_id];
+  LTE_DL_FRAME_PARMS *frame_parms = (eNB==NULL) ? &eNB->frame_parms : &ru->frame_parms;
+  //LTE_DL_FRAME_PARMS *frame_parms = &eNB->frame_parms;
   LTE_eNB_PUSCH *pusch_vars = eNB->pusch_vars[UE_id];
-  int32_t **ul_ch_estimates=pusch_vars->drs_ch_estimates;
-  int32_t **ul_ch_estimates_time=  pusch_vars->drs_ch_estimates_time;
-  int32_t **rxdataF_ext=  pusch_vars->rxdataF_ext;
-  int subframe = proc->subframe_rx;
+  RU_CALIBRATION *calibration = &ru->calibration;
+  //int32_t **ul_ch_estimates=pusch_vars->drs_ch_estimates;
+  int32_t **ul_ch_estimates = (eNB==NULL) ? pusch_vars->drs_ch_estimates : calibration->drs_ch_estimates;
+
+  //int32_t **ul_ch_estimates_time=  pusch_vars->drs_ch_estimates_time;
+  int32_t **ul_ch_estimates_time = (eNB==NULL) ? pusch_vars->drs_ch_estimates_time : calibration->drs_ch_estimates_time;
+  
+  //int32_t **rxdataF_ext=  pusch_vars->rxdataF_ext;
+  int32_t **rxdataF_ext = (eNB==NULL) ? pusch_vars->rxdataF_ext : calibration->rxdataF_ext;
+
+  int subframe = (eNB==NULL) ? proc->subframe_rx : ru->proc.subframe_rx;
+  //int subframe = proc->subframe_rx;
+
   uint8_t harq_pid = subframe2harq_pid(frame_parms,proc->frame_rx,subframe);
+
   int16_t delta_phase = 0;
   int16_t *ru1 = ru_90;
   int16_t *ru2 = ru_90;
@@ -413,6 +425,356 @@ int32_t temp_in_ifft_0[2048*2] __attribute__((aligned(32)));
   return(0);
 }
 
+int32_t lte_ul_channel_estimation_RRU(LTE_DL_FRAME_PARMS *frame_parms,
+				  int32_t **ul_ch_estimates,
+				  int32_t **ul_ch_estimates_time,
+				  int32_t **rxdataF_ext,
+				  int N_rb_alloc,
+				  int frame_rx,
+				  int subframe_rx,
+				  uint32_t u,
+				  uint32_t v,
+				  uint32_t cyclic_shift,
+                                  unsigned char l,
+				  int interpolate,
+				  uint16_t rnti) {
+
+  int16_t delta_phase = 0;
+  int16_t *ru1 = ru_90;
+  int16_t *ru2 = ru_90;
+  int16_t current_phase1,current_phase2;
+  uint16_t aa,Msc_RS,Msc_RS_idx;
+  uint16_t * Msc_idx_ptr;
+  int k,pilot_pos1 = 3 - frame_parms->Ncp, pilot_pos2 = 10 - 2*frame_parms->Ncp;
+  int32_t *ul_ch1=NULL, *ul_ch2=NULL;
+  int16_t ul_ch_estimates_re,ul_ch_estimates_im;
+  uint8_t nb_antennas_rx = frame_parms->nb_antennas_rx;
+  uint32_t alpha_ind;
+  int32_t tmp_estimates[N_rb_alloc*12] __attribute__((aligned(16)));
+
+  int symbol_offset,i;
+
+  //debug_msg("lte_ul_channel_estimation_RRU: cyclic shift %d\n",cyclicShift);
+
+  int16_t alpha_re[12] = {32767, 28377, 16383,     0,-16384,  -28378,-32768,-28378,-16384,    -1, 16383, 28377};
+  int16_t alpha_im[12] = {0,     16383, 28377, 32767, 28377,   16383,     0,-16384,-28378,-32768,-28378,-16384};
+
+#if defined(__x86_64__) || defined(__i386__)
+  __m128i *rxdataF128,*ul_ref128,*ul_ch128;
+  __m128i mmtmpU0,mmtmpU1,mmtmpU2,mmtmpU3;
+#elif defined(__arm__)
+  int16x8_t *rxdataF128,*ul_ref128,*ul_ch128;
+  int32x4_t mmtmp0,mmtmp1,mmtmp_re,mmtmp_im;
+#endif
+
+  int32_t temp_in_ifft_0[2048*2] __attribute__((aligned(32)));
+
+  AssertFatal(l==pilot_pos1 || l==pilot_pos2,"%d is not a valid symbol for DMRS, should be %d or %d\n",
+	      l,pilot_pos1,pilot_pos2);
+
+  Msc_RS = N_rb_alloc*12;
+  /*
+
+  */
+
+  Msc_idx_ptr = (uint16_t*) bsearch(&Msc_RS, dftsizes, 33, sizeof(uint16_t), compareints);
+
+  if (Msc_idx_ptr)
+    Msc_RS_idx = Msc_idx_ptr - dftsizes;
+  else {
+    LOG_E(PHY,"lte_ul_channel_estimation_RRU: index for Msc_RS=%d not found\n",Msc_RS);
+    return(-1);
+  }
+  LOG_D(PHY,"subframe %d, l %d, Msc_RS = %d, Msc_RS_idx = %d, u %d, v %d, cyclic_shift %d\n",subframe_rx,l,Msc_RS, Msc_RS_idx,u,v,cyclic_shift);
+#ifdef DEBUG_CH
+  if (l==pilot_pos1)
+    write_output("drs_seq0.m","drsseq0",ul_ref_sigs_rx[u][v][Msc_RS_idx],Msc_RS,1,1);
+  else
+    write_output("drs_seq1.m","drsseq1",ul_ref_sigs_rx[u][v][Msc_RS_idx],Msc_RS,1,1);
+
+#endif
+
+  symbol_offset = frame_parms->N_RB_UL*12*l;
+  
+  for (aa=0; aa<nb_antennas_rx; aa++) {
+    
+#if defined(__x86_64__) || defined(__i386__)
+    rxdataF128 = (__m128i *)&rxdataF_ext[aa][symbol_offset];
+    ul_ch128   = (__m128i *)&ul_ch_estimates[aa][symbol_offset];
+    ul_ref128  = (__m128i *)ul_ref_sigs_rx[u][v][Msc_RS_idx];
+#elif defined(__arm__)
+    rxdataF128 = (int16x8_t *)&rxdataF_ext[aa][symbol_offset];
+    ul_ch128   = (int16x8_t *)&ul_ch_estimates[aa][symbol_offset];
+    ul_ref128  = (int16x8_t *)ul_ref_sigs_rx[u][v][Msc_RS_idx];
+#endif
+    
+    for (i=0; i<Msc_RS/12; i++) {
+#if defined(__x86_64__) || defined(__i386__)
+      // multiply by conjugated channel
+      mmtmpU0 = _mm_madd_epi16(ul_ref128[0],rxdataF128[0]);
+      // mmtmpU0 contains real part of 4 consecutive outputs (32-bit)
+      mmtmpU1 = _mm_shufflelo_epi16(ul_ref128[0],_MM_SHUFFLE(2,3,0,1));
+      mmtmpU1 = _mm_shufflehi_epi16(mmtmpU1,_MM_SHUFFLE(2,3,0,1));
+      mmtmpU1 = _mm_sign_epi16(mmtmpU1,*(__m128i*)&conjugate[0]);
+      mmtmpU1 = _mm_madd_epi16(mmtmpU1,rxdataF128[0]);
+      // mmtmpU1 contains imag part of 4 consecutive outputs (32-bit)
+      mmtmpU0 = _mm_srai_epi32(mmtmpU0,15);
+      mmtmpU1 = _mm_srai_epi32(mmtmpU1,15);
+      mmtmpU2 = _mm_unpacklo_epi32(mmtmpU0,mmtmpU1);
+      mmtmpU3 = _mm_unpackhi_epi32(mmtmpU0,mmtmpU1);
+      
+      ul_ch128[0] = _mm_packs_epi32(mmtmpU2,mmtmpU3);
+      //      printf("rb %d ch: %d %d\n",i,((int16_t*)ul_ch128)[0],((int16_t*)ul_ch128)[1]);
+      // multiply by conjugated channel
+      mmtmpU0 = _mm_madd_epi16(ul_ref128[1],rxdataF128[1]);
+      // mmtmpU0 contains real part of 4 consecutive outputs (32-bit)
+      mmtmpU1 = _mm_shufflelo_epi16(ul_ref128[1],_MM_SHUFFLE(2,3,0,1));
+      mmtmpU1 = _mm_shufflehi_epi16(mmtmpU1,_MM_SHUFFLE(2,3,0,1));
+      mmtmpU1 = _mm_sign_epi16(mmtmpU1,*(__m128i*)conjugate);
+      mmtmpU1 = _mm_madd_epi16(mmtmpU1,rxdataF128[1]);
+      // mmtmpU1 contains imag part of 4 consecutive outputs (32-bit)
+      mmtmpU0 = _mm_srai_epi32(mmtmpU0,15);
+      mmtmpU1 = _mm_srai_epi32(mmtmpU1,15);
+      mmtmpU2 = _mm_unpacklo_epi32(mmtmpU0,mmtmpU1);
+      mmtmpU3 = _mm_unpackhi_epi32(mmtmpU0,mmtmpU1);
+      
+      ul_ch128[1] = _mm_packs_epi32(mmtmpU2,mmtmpU3);
+      
+      mmtmpU0 = _mm_madd_epi16(ul_ref128[2],rxdataF128[2]);
+      // mmtmpU0 contains real part of 4 consecutive outputs (32-bit)
+      mmtmpU1 = _mm_shufflelo_epi16(ul_ref128[2],_MM_SHUFFLE(2,3,0,1));
+      mmtmpU1 = _mm_shufflehi_epi16(mmtmpU1,_MM_SHUFFLE(2,3,0,1));
+      mmtmpU1 = _mm_sign_epi16(mmtmpU1,*(__m128i*)conjugate);
+      mmtmpU1 = _mm_madd_epi16(mmtmpU1,rxdataF128[2]);
+      // mmtmpU1 contains imag part of 4 consecutive outputs (32-bit)
+      mmtmpU0 = _mm_srai_epi32(mmtmpU0,15);
+      mmtmpU1 = _mm_srai_epi32(mmtmpU1,15);
+      mmtmpU2 = _mm_unpacklo_epi32(mmtmpU0,mmtmpU1);
+      mmtmpU3 = _mm_unpackhi_epi32(mmtmpU0,mmtmpU1);
+      
+      ul_ch128[2] = _mm_packs_epi32(mmtmpU2,mmtmpU3);
+#elif defined(__arm__)
+      mmtmp0 = vmull_s16(((int16x4_t*)ul_ref128)[0],((int16x4_t*)rxdataF128)[0]);
+      mmtmp1 = vmull_s16(((int16x4_t*)ul_ref128)[1],((int16x4_t*)rxdataF128)[1]);
+      mmtmp_re = vcombine_s32(vpadd_s32(vget_low_s32(mmtmp0),vget_high_s32(mmtmp0)),
+                              vpadd_s32(vget_low_s32(mmtmp1),vget_high_s32(mmtmp1)));
+      mmtmp0 = vmull_s16(vrev32_s16(vmul_s16(((int16x4_t*)ul_ref128)[0],*(int16x4_t*)conjugate)), ((int16x4_t*)rxdataF128)[0]);
+      mmtmp1 = vmull_s16(vrev32_s16(vmul_s16(((int16x4_t*)ul_ref128)[1],*(int16x4_t*)conjugate)), ((int16x4_t*)rxdataF128)[1]);
+      mmtmp_im = vcombine_s32(vpadd_s32(vget_low_s32(mmtmp0),vget_high_s32(mmtmp0)),
+                              vpadd_s32(vget_low_s32(mmtmp1),vget_high_s32(mmtmp1)));
+      
+      ul_ch128[0] = vcombine_s16(vmovn_s32(mmtmp_re),vmovn_s32(mmtmp_im));
+      ul_ch128++;
+      ul_ref128++;
+      rxdataF128++;
+      mmtmp0 = vmull_s16(((int16x4_t*)ul_ref128)[0],((int16x4_t*)rxdataF128)[0]);
+      mmtmp1 = vmull_s16(((int16x4_t*)ul_ref128)[1],((int16x4_t*)rxdataF128)[1]);
+      mmtmp_re = vcombine_s32(vpadd_s32(vget_low_s32(mmtmp0),vget_high_s32(mmtmp0)),
+                              vpadd_s32(vget_low_s32(mmtmp1),vget_high_s32(mmtmp1)));
+      mmtmp0 = vmull_s16(vrev32_s16(vmul_s16(((int16x4_t*)ul_ref128)[0],*(int16x4_t*)conjugate)), ((int16x4_t*)rxdataF128)[0]);
+      mmtmp1 = vmull_s16(vrev32_s16(vmul_s16(((int16x4_t*)ul_ref128)[1],*(int16x4_t*)conjugate)), ((int16x4_t*)rxdataF128)[1]);
+      mmtmp_im = vcombine_s32(vpadd_s32(vget_low_s32(mmtmp0),vget_high_s32(mmtmp0)),
+                              vpadd_s32(vget_low_s32(mmtmp1),vget_high_s32(mmtmp1)));
+      
+      ul_ch128[0] = vcombine_s16(vmovn_s32(mmtmp_re),vmovn_s32(mmtmp_im));
+      ul_ch128++;
+      ul_ref128++;
+      rxdataF128++;
+      
+      mmtmp0 = vmull_s16(((int16x4_t*)ul_ref128)[0],((int16x4_t*)rxdataF128)[0]);
+      mmtmp1 = vmull_s16(((int16x4_t*)ul_ref128)[1],((int16x4_t*)rxdataF128)[1]);
+      mmtmp_re = vcombine_s32(vpadd_s32(vget_low_s32(mmtmp0),vget_high_s32(mmtmp0)),
+                              vpadd_s32(vget_low_s32(mmtmp1),vget_high_s32(mmtmp1)));
+      mmtmp0 = vmull_s16(vrev32_s16(vmul_s16(((int16x4_t*)ul_ref128)[0],*(int16x4_t*)conjugate)), ((int16x4_t*)rxdataF128)[0]);
+      mmtmp1 = vmull_s16(vrev32_s16(vmul_s16(((int16x4_t*)ul_ref128)[1],*(int16x4_t*)conjugate)), ((int16x4_t*)rxdataF128)[1]);
+      mmtmp_im = vcombine_s32(vpadd_s32(vget_low_s32(mmtmp0),vget_high_s32(mmtmp0)),
+                              vpadd_s32(vget_low_s32(mmtmp1),vget_high_s32(mmtmp1)));
+      
+      ul_ch128[0] = vcombine_s16(vmovn_s32(mmtmp_re),vmovn_s32(mmtmp_im));
+      ul_ch128++;
+      ul_ref128++;
+      rxdataF128++;
+      
+      
+#endif
+      ul_ch128+=3;
+      ul_ref128+=3;
+      rxdataF128+=3;
+    }
+    
+    alpha_ind = 0;
+    
+    if((cyclic_shift != 0)) {
+      // Compensating for the phase shift introduced at the transmitte
+#ifdef DEBUG_CH
+      write_output("drs_est_pre.m","drsest_pre",ul_ch_estimates[0],300*12,1,1);
+#endif
+      
+      for(i=symbol_offset; i<symbol_offset+Msc_RS; i++) {
+	ul_ch_estimates_re = ((int16_t*) ul_ch_estimates[aa])[i<<1];
+	ul_ch_estimates_im = ((int16_t*) ul_ch_estimates[aa])[(i<<1)+1];
+	//    ((int16_t*) ul_ch_estimates[aa])[i<<1] =  (i%2 == 1? 1:-1) * ul_ch_estimates_re;
+	((int16_t*) ul_ch_estimates[aa])[i<<1] =
+	  (int16_t) (((int32_t) (alpha_re[alpha_ind]) * (int32_t) (ul_ch_estimates_re) +
+		      (int32_t) (alpha_im[alpha_ind]) * (int32_t) (ul_ch_estimates_im))>>15);
+	
+	//((int16_t*) ul_ch_estimates[aa])[(i<<1)+1] =  (i%2 == 1? 1:-1) * ul_ch_estimates_im;
+	((int16_t*) ul_ch_estimates[aa])[(i<<1)+1] =
+	  (int16_t) (((int32_t) (alpha_re[alpha_ind]) * (int32_t) (ul_ch_estimates_im) -
+		      (int32_t) (alpha_im[alpha_ind]) * (int32_t) (ul_ch_estimates_re))>>15);
+	
+	alpha_ind+=cyclic_shift;
+	
+	if (alpha_ind>11)
+	  alpha_ind-=12;
+      }
+      
+#ifdef DEBUG_CH
+      write_output("drs_est_post.m","drsest_post",ul_ch_estimates[0],300*12,1,1);
+#endif
+    }
+    
+    if (ul_ch_estimates_time && ul_ch_estimates_time[aa]) {
+      // Convert to time domain for visualization
+      memset(temp_in_ifft_0,0,frame_parms->ofdm_symbol_size*sizeof(int32_t));
+      for(i=0; i<Msc_RS; i++)
+	((int32_t*)temp_in_ifft_0)[i] = ul_ch_estimates[aa][symbol_offset+i];
+      
+      switch(frame_parms->N_RB_DL) {
+      case 6:
+	idft128((int16_t*) temp_in_ifft_0,
+		(int16_t*) ul_ch_estimates_time[aa],
+		1);
+	break;
+      case 25:
+	idft512((int16_t*) temp_in_ifft_0,
+		(int16_t*) ul_ch_estimates_time[aa],
+		1);
+	break;
+      case 50:
+	idft1024((int16_t*) temp_in_ifft_0,
+		 (int16_t*) ul_ch_estimates_time[aa],
+		 1);
+	break;
+      case 100:
+	idft2048((int16_t*) temp_in_ifft_0,
+		 (int16_t*) ul_ch_estimates_time[aa],
+		 1);
+	break;
+      }
+      
+#if T_TRACER
+      if (aa == 0)
+	T(T_ENB_PHY_UL_CHANNEL_ESTIMATE, T_INT(0), T_INT(rnti),
+	  T_INT(frame_rx), T_INT(subframe_rx),
+	  T_INT(0), T_BUFFER(ul_ch_estimates_time[0], 512  * 4));
+#endif
+    }
+#ifdef DEBUG_CH
+    
+    if (aa==1) {
+      if (l == pilot_pos1) {
+	write_output("rxdataF_ext.m","rxF_ext",&rxdataF_ext[aa][symbol_offset],512*2,2,1);
+	write_output("tmpin_ifft.m","drs_in",temp_in_ifft_0,512,1,1);
+	if (ul_ch_estimates_time[aa]) write_output("drs_est0.m","drs0",ul_ch_estimates_time[aa],512,1,1);
+      } else
+	if (ul_ch_estimates_time[aa]) write_output("drs_est1.m","drs1",ul_ch_estimates_time[aa],512,1,1);
+    }
+    
+#endif
+    
+    
+    
+    
+    if (l==pilot_pos2 && interpolate==1) {//we are in the second slot of the sub-frame, so do the interpolation
+      
+      ul_ch1 = &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*pilot_pos1];
+      ul_ch2 = &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*pilot_pos2];
+      
+      
+      // Estimation of phase difference between the 2 channel estimates
+      delta_phase = lte_ul_freq_offset_estimation(frame_parms,
+						  ul_ch_estimates[aa],
+						  N_rb_alloc);
+      // negative phase index indicates negative Im of ru
+      //    msg("delta_phase: %d\n",delta_phase);
+      
+#ifdef DEBUG_CH
+      LOG_D(PHY,"lte_ul_channel_estimation_RRU: ul_ch1 = %p, ul_ch2 = %p, pilot_pos1=%d, pilot_pos2=%d\n",ul_ch1, ul_ch2, pilot_pos1,pilot_pos2);
+#endif
+      
+      for (k=0; k<frame_parms->symbols_per_tti; k++) {
+	
+#ifdef DEBUG_CH
+	//	LOG_D(PHY,"lte_ul_channel_estimation: k=%d, alpha = %d, beta = %d\n",k,alpha,beta);
+#endif
+	//symbol_offset_subframe = frame_parms->N_RB_UL*12*k;
+	
+	// interpolate between estimates
+	if ((k != pilot_pos1) && (k != pilot_pos2))  {
+	  
+	  // the phase is linearly interpolated
+	  current_phase1 = (delta_phase/7)*(k-pilot_pos1);
+	  current_phase2 = (delta_phase/7)*(k-pilot_pos2);
+	  //          msg("sym: %d, current_phase1: %d, current_phase2: %d\n",k,current_phase1,current_phase2);
+	  // set the right quadrant
+	  (current_phase1 > 0) ? (ru1 = ru_90) : (ru1 = ru_90c);
+	  (current_phase2 > 0) ? (ru2 = ru_90) : (ru2 = ru_90c);
+	  // take absolute value and clip
+	  current_phase1 = cmin(abs(current_phase1),127);
+	  current_phase2 = cmin(abs(current_phase2),127);
+	  
+	  //          msg("sym: %d, current_phase1: %d, ru: %d + j%d, current_phase2: %d, ru: %d + j%d\n",k,current_phase1,ru1[2*current_phase1],ru1[2*current_phase1+1],current_phase2,ru2[2*current_phase2],ru2[2*current_phase2+1]);
+	  
+	  // rotate channel estimates by estimated phase
+	  rotate_cpx_vector((int16_t*) ul_ch1,
+			    &ru1[2*current_phase1],
+			    (int16_t*) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k],
+			    Msc_RS,
+			    15);
+	  
+	  rotate_cpx_vector((int16_t*) ul_ch2,
+			    &ru2[2*current_phase2],
+			    (int16_t*) &tmp_estimates[0],
+			    Msc_RS,
+			    15);
+	  
+	  // Combine the two rotated estimates
+	  multadd_complex_vector_real_scalar((int16_t*) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k],SCALE,(int16_t*) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k],1,Msc_RS);
+	  multadd_complex_vector_real_scalar((int16_t*) &tmp_estimates[0],SCALE,(int16_t*) &ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k],0,Msc_RS);
+	  
+	}
+      } //for(k=...
+      
+      // because of the scaling of alpha and beta we also need to scale the final channel estimate at the pilot positions
+      
+      //    multadd_complex_vector_real_scalar((int16_t*) ul_ch1,SCALE,(int16_t*) ul_ch1,1,Msc_RS);
+      //    multadd_complex_vector_real_scalar((int16_t*) ul_ch2,SCALE,(int16_t*) ul_ch2,1,Msc_RS);
+      
+    } //if (Ns&1 && interpolate==1)
+    else if (interpolate == 0 && l == pilot_pos1)
+      for (k=0;k<frame_parms->symbols_per_tti>>1;k++) { 
+        if (k==pilot_pos1) k++;
+	memcpy((void*)&ul_ch_estimates[aa][frame_parms->N_RB_UL*12*k],
+	       (void*)&ul_ch_estimates[aa][frame_parms->N_RB_UL*12*pilot_pos1],
+	       frame_parms->N_RB_UL*12*sizeof(int));
+      }
+    else if (interpolate == 0 && l == pilot_pos2) {
+      for (k=0;k<frame_parms->symbols_per_tti>>1;k++) {
+	if (k==pilot_pos2) k++;
+	memcpy((void*)&ul_ch_estimates[aa][frame_parms->N_RB_UL*12*(k+(frame_parms->symbols_per_tti>>1))],
+	       (void*)&ul_ch_estimates[aa][frame_parms->N_RB_UL*12*pilot_pos2],
+	       frame_parms->N_RB_UL*12*sizeof(int));
+      }	
+      delta_phase = lte_ul_freq_offset_estimation(frame_parms,
+                                                  ul_ch_estimates[aa],
+                                                  N_rb_alloc);
+      LOG_D(PHY,"delta_phase = %d\n",delta_phase);
+    }
+  } //for(aa=...
+  return(0);
+}
+
 extern uint16_t transmission_offset_tdd[16];
 //#define DEBUG_SRS
 
diff --git a/openair1/PHY/MODULATION/ul_7_5_kHz.c b/openair1/PHY/MODULATION/ul_7_5_kHz.c
index d27a305a5d..c3f13578bb 100644
--- a/openair1/PHY/MODULATION/ul_7_5_kHz.c
+++ b/openair1/PHY/MODULATION/ul_7_5_kHz.c
@@ -147,6 +147,17 @@ void remove_7_5_kHz(RU_t *ru,uint8_t slot)
 
 #endif
     }
-  }
+    // undo 7.5 kHz offset for symbol 3 in case RU is slave (for OTA synchronization)
+    if (ru->is_slave == 1 && slot == 2){
+      memcpy((void*)&rxdata_7_5kHz[aa][(3*frame_parms->ofdm_symbol_size)+
+                                (2*frame_parms->nb_prefix_samples)+
+                                frame_parms->nb_prefix_samples0],
+             (void*)&rxdata[aa][slot_offset+ru->N_TA_offset+
+                           (3*frame_parms->ofdm_symbol_size)+
+                           (2*frame_parms->nb_prefix_samples)+
+                           frame_parms->nb_prefix_samples0],
+             (frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples)*sizeof(int32_t));
+}  
+}
 }
 
diff --git a/openair1/PHY/defs_eNB.h b/openair1/PHY/defs_eNB.h
index 5e239123fb..15845add91 100644
--- a/openair1/PHY/defs_eNB.h
+++ b/openair1/PHY/defs_eNB.h
@@ -301,7 +301,8 @@ typedef enum {
   RU_READY  = 2,
   RU_RUN    = 3,
   RU_ERROR  = 4,
-  RU_SYNC   = 5
+  RU_SYNC   = 5,
+  RU_CHECK_SYNC = 6
 } rru_state_t;
 
 /// Some commamds to RRU. Not sure we should do it like this !
@@ -345,6 +346,8 @@ typedef struct RU_t_s{
   int has_ctrl_prt;
   /// counter to delay start of processing of RU until HW settles
   int wait_cnt;
+  /// counter to delay start of slave RUs until stable synchronization
+  int wait_check;
   /// Total gain of receive chain
   uint32_t             rx_total_gain_dB;
   /// number of bands that this device can support
@@ -441,6 +444,7 @@ typedef struct RU_t_s{
   time_stats_t transport;
   /// RX and TX buffers for precoder output
   RU_COMMON            common;
+  RU_CALIBRATION calibration; 
   /// beamforming weight vectors per eNB
   int32_t **beam_weights[NUMBER_OF_eNB_MAX+1][15];
 
@@ -480,7 +484,8 @@ typedef enum {
   RRU_stop=5,
   RRU_sync_ok=6,
   RRU_frame_resynch=7,
-  RRU_MSG_max_num=8
+  RRU_MSG_max_num=8,
+  RRU_check_sync = 9
 } rru_config_msg_type_t;
 
 typedef struct RRU_CONFIG_msg_s {
diff --git a/openair1/PHY/impl_defs_lte.h b/openair1/PHY/impl_defs_lte.h
index d649dce100..30980d7ceb 100644
--- a/openair1/PHY/impl_defs_lte.h
+++ b/openair1/PHY/impl_defs_lte.h
@@ -58,7 +58,7 @@ typedef struct {
   /// - first index: rx antenna [0..nb_antennas_rx[
   /// - second index: ? [0..2*ofdm_symbol_size*frame_parms->symbols_per_tti[
   int32_t **rxdataF;
-  /// \brief Holds output of the sync correlator.
+   /// \brief Holds output of the sync correlator.
   /// - first index: sample [0..samples_per_tti*10[
   uint32_t *sync_corr;
   /// \brief Holds the tdd reciprocity calibration coefficients 
@@ -68,4 +68,19 @@ typedef struct {
   int32_t **tdd_calib_coeffs;
 } RU_COMMON;
 
+typedef struct {
+  /// \brief Received frequency-domain signal after extraction.
+  /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx
+  /// - second index: ? [0..168*N_RB_DL[
+  int32_t **rxdataF_ext;
+  /// \brief Hold the channel estimates in time domain based on DRS.
+  /// - first index: rx antenna id [0..nb_antennas_rx[
+  /// - second index: ? [0..4*ofdm_symbol_size[
+  int32_t **drs_ch_estimates_time;
+  /// \brief Hold the channel estimates in frequency domain based on DRS.
+  /// - first index: rx antenna id [0..nb_antennas_rx[
+  /// - second index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[
+  int32_t **drs_ch_estimates;
+} RU_CALIBRATION;
+
 #endif
diff --git a/openair1/SCHED/ru_procedures.c b/openair1/SCHED/ru_procedures.c
index dcd238332f..c99cbcdaea 100644
--- a/openair1/SCHED/ru_procedures.c
+++ b/openair1/SCHED/ru_procedures.c
@@ -535,7 +535,6 @@ void fep0(RU_t *ru,int slot) {
   //  printf("fep0: slot %d\n",slot);
 
   //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+slot, 1);
-
   remove_7_5_kHz(ru,(slot&1)+(proc->subframe_rx<<1));
   for (l=0; l<fp->symbols_per_tti/2; l++) {
     slot_fep_ul(ru,
@@ -647,14 +646,20 @@ extern void kill_feptx_thread(RU_t *ru)
 void ru_fep_full_2thread(RU_t *ru) {
 
   RU_proc_t *proc = &ru->proc;
+  //PHY_VARS_eNB *eNB = RC.eNB[0][0];
+  LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
+  RU_CALIBRATION *calibration = &ru->calibration;
+  
+  int cnt;
+  int check_sync_pos;
 
   struct timespec wait;
-
-  LTE_DL_FRAME_PARMS *fp=&ru->frame_parms;
-
-  if ((fp->frame_type == TDD) &&
-     (subframe_select(fp,proc->subframe_rx) != SF_UL)) return;
-
+  if (proc->subframe_rx==1){
+  	//LOG_I(PHY,"subframe type %d, RU %d\n",subframe_select(fp,proc->subframe_rx),ru->idx);
+  }
+  else if ((fp->frame_type == TDD) && (subframe_select(fp,proc->subframe_rx) != SF_UL)) {
+  	return;
+  }
   //if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX, 1 );
 
   wait.tv_sec=0;
@@ -696,9 +701,73 @@ void ru_fep_full_2thread(RU_t *ru) {
   stop_meas(&ru->ofdm_demod_wait_stats);
   if(opp_enabled == 1 && ru->ofdm_demod_wakeup_stats.p_time>30*3000){
     print_meas_now(&ru->ofdm_demod_wakeup_stats,"fep wakeup",stderr);
-    printf("delay in fep wait on codition in frame_rx: %d  subframe_rx: %d \n",proc->frame_rx,proc->subframe_rx);
+    printf("delay in fep wait on condition in frame_rx: %d  subframe_rx: %d \n",proc->frame_rx,proc->subframe_rx);
   }
 
+  if (proc->subframe_rx==1 && ru->is_slave==1/* && ru->state == RU_CHECK_SYNC*/) {
+
+        LOG_I(PHY,"Running check synchronization procedure for frame %d\n", proc->frame_rx);
+  	ulsch_extract_rbs_single(ru->common.rxdataF,
+                                 calibration->rxdataF_ext,
+                                 0,
+                                 fp->N_RB_DL,
+                                 3%(fp->symbols_per_tti/2),// l = symbol within slot
+                                 3/(fp->symbols_per_tti/2),// Ns = slot number 
+                                 fp);
+        
+
+	/*lte_ul_channel_estimation((PHY_VARS_eNB *)NULL,
+				  proc,
+                                  ru->idx,
+                                  3%(fp->symbols_per_tti/2),
+                                  3/(fp->symbols_per_tti/2));
+        */
+	lte_ul_channel_estimation_RRU(fp,
+                                  calibration->drs_ch_estimates,
+                                  calibration->drs_ch_estimates_time,
+                                  calibration->rxdataF_ext,
+                                  fp->N_RB_DL, //N_rb_alloc,
+				  proc->frame_rx,
+				  proc->subframe_rx,
+				  0,//u = 0..29
+				  0,//v = 0,1
+				  /*eNB->ulsch[ru->idx]->cyclicShift,cyclic_shift,0..7*/0,
+				  3,//l,
+ 			          0,//interpolate,
+				  0 /*eNB->ulsch[ru->idx]->rnti rnti or ru->ulsch[eNB_id]->rnti*/);
+ 
+        
+
+        check_sync_pos = lte_est_timing_advance_pusch((PHY_VARS_eNB *)NULL,
+     				     		       ru->idx);
+	//LOG_I(PHY,"Estimated check_sync_pos %d\n",check_sync_pos);
+        if (ru->state == RU_CHECK_SYNC) {
+          if ((check_sync_pos >= 0 && check_sync_pos<8) || (check_sync_pos < 0 && check_sync_pos>-8)) {
+    		  LOG_I(PHY,"check_sync_pos %d, frame %d, cnt %d\n",check_sync_pos,proc->frame_rx,ru->wait_check); 
+                  ru->wait_check++;
+          }
+
+          if (ru->wait_check==10) { 
+	  	ru->state = RU_RUN;
+          	/*LOG_M("dmrs_time.m","dmrstime",calibration->drs_ch_estimates_time[0], (fp->ofdm_symbol_size),1,1);
+		LOG_M("rxdataF_ext.m","rxdataFext",&calibration->rxdataF_ext[0][36*fp->N_RB_DL], 12*(fp->N_RB_DL),1,1);		
+		LOG_M("drs_seq0.m","drsseq0",ul_ref_sigs_rx[0][0][23],600,1,1);
+		LOG_M("rxdata.m","rxdata",&ru->common.rxdata[0][0], fp->samples_per_tti*2,1,1);
+		exit(-1);*/
+	 } 
+       }
+       else if (ru->state == RU_RUN) {
+       	// check for synchronization error
+       	if (check_sync_pos >= 8 || check_sync_pos<=-8) {
+	 	exit(-1);
+	}
+       }
+    
+    else {
+       	 AssertFatal(1==0,"Should not get here\n");
+    }
+ }
+
   stop_meas(&ru->ofdm_demod_stats);
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+ru->idx, 0 );
 }
diff --git a/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c b/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c
index 18e9567402..2336e079eb 100644
--- a/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c
+++ b/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c
@@ -245,7 +245,7 @@ int trx_eth_write_udp_IF4p5(openair0_device *device, openair0_timestamp timestam
   }
    
   eth->tx_nsamps = nblocks;
-  printf("Sending %d bytes to %s:%d\n",packet_size,str,ntohs(eth->local_addrd.sin_port));
+  //printf("Sending %d bytes to %s:%d\n",packet_size,str,ntohs(eth->local_addrd.sin_port));
 
   bytes_sent = sendto(eth->sockfdd,
 		      buff[0], 
diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c
index fafcc21b7b..9e55f4f9f5 100644
--- a/targets/RT/USER/lte-ru.c
+++ b/targets/RT/USER/lte-ru.c
@@ -601,7 +601,7 @@ void rx_rf(RU_t *ru,int *frame,int *subframe) {
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );
 
   ru->south_in_cnt++;
-  LOG_I(PHY,"south_in_cnt %d\n",ru->south_in_cnt);
+  LOG_D(PHY,"south_in_cnt %d\n",ru->south_in_cnt);
 
   if (ru->cmd==RU_FRAME_RESYNCH) {
     LOG_I(PHY,"Applying frame resynch %d => %d\n",*frame,ru->cmdval);
@@ -1118,14 +1118,32 @@ void do_ru_synch(RU_t *ru) {
 
     ru->rfdevice.trx_set_freq_func(&ru->rfdevice,ru->rfdevice.openair0_cfg,0);
   */
-  ru->state    = RU_RUN;
-  // Send RRU_sync_ok
-  rru_config_msg.type = RRU_sync_ok;
+  
+  // Verification of synchronization procedure
+  ru->state = RU_CHECK_SYNC;
+ /* // Send RRU_check_sync
+  rru_config_msg.type = RRU_check_sync;
   rru_config_msg.len  = sizeof(RRU_CONFIG_msg_t); // TODO: set to correct msg len
-
-  LOG_I(PHY,"Sending RRU_sync_ok to RAU\n");
+  LOG_I(PHY,"Sending RRU_check_sync to RAU\n");
   AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1),"Failed to send msg to RAU %d\n",ru->idx);
+  
+  while (check_sync_flag){ // continuously read frames until check synch procedure is over 
+
+  }
 
+
+  //if (synch_peak>...) {
+	ru->state    = RU_RUN;
+  	// Send RRU_sync_ok
+  	rru_config_msg.type = RRU_sync_ok;
+  	rru_config_msg.len  = sizeof(RRU_CONFIG_msg_t); // TODO: set to correct msg len
+  	LOG_I(PHY,"Sending RRU_sync_ok to RAU\n");
+  	AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1),"Failed to send msg to RAU %d\n",ru->idx);
+    //}
+  //else {
+    	//do_ru_synch(ru);
+  //}
+*/
   LOG_I(PHY,"Exiting synch routine\n");
 }
 
@@ -1653,8 +1671,14 @@ static void* ru_thread( void* param ) {
 
   while (!oai_exit) {
 
-    if (ru->if_south != LOCAL_RF && ru->is_slave==1) ru->wait_cnt = 100;
-    else                          ru->wait_cnt = 0;
+    if (ru->if_south != LOCAL_RF && ru->is_slave==1) {
+   	 ru->wait_cnt = 100;
+    }
+    else { 
+         ru->wait_cnt = 0;
+	 ru->wait_check = 0;
+    }
+
 
     // wait to be woken up
     if (ru->function!=eNodeB_3GPP && ru->has_ctrl_prt == 1) {
@@ -1663,7 +1687,7 @@ static void* ru_thread( void* param ) {
     else wait_sync("ru_thread");
 
     if (ru->is_slave == 0) AssertFatal(ru->state == RU_RUN,"ru-%d state = %s != RU_RUN\n",ru->idx,ru_states[ru->state]);
-    else if (ru->is_slave == 1) AssertFatal(ru->state == RU_SYNC || ru->state == RU_RUN,"ru %d state = %s != RU_SYNC or RU_RUN\n",ru->idx,ru_states[ru->state]); 
+    else if (ru->is_slave == 1) AssertFatal(ru->state == RU_SYNC || ru->state == RU_RUN || ru->state == RU_CHECK_SYNC,"ru %d state = %s != RU_SYNC or RU_RUN or RU_CHECK_SYNC\n",ru->idx,ru_states[ru->state]); 
     // Start RF device if any
     if (ru->start_rf) {
       if (ru->start_rf(ru) != 0)
@@ -1691,7 +1715,7 @@ static void* ru_thread( void* param ) {
 
     LOG_D(PHY,"Starting steady-state operation\n");
     // This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices
-    while (ru->state == RU_RUN) {
+    while (ru->state == RU_RUN || ru->state == RU_CHECK_SYNC) {
 
       // 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.
@@ -1841,7 +1865,7 @@ static void* ru_thread( void* param ) {
         // do outgoing fronthaul (south) if needed
         if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru);
         
-        if (ru->fh_north_out) ru->fh_north_out(ru);
+        if ((ru->fh_north_out) && (ru->state!=RU_CHECK_SYNC)) ru->fh_north_out(ru);
       }
       proc->emulate_rf_busy = 0;
     }
@@ -1907,15 +1931,16 @@ void *ru_thread_synch(void *arg) {
 				   &avg);
       LOG_I(PHY,"RU synch cnt %d: %d, val %llu (%d dB,%d dB)\n",cnt,ru->rx_offset,(unsigned long long)peak_val,dB_fixed64(peak_val),dB_fixed64(avg));
       cnt++;
-      if (/*ru->rx_offset >= 0*/dB_fixed64(peak_val)>=85 && cnt>10) {
+      if (/*ru->rx_offset >= 0*/dB_fixed(peak_val)>=85 && cnt>10) {
 
 	LOG_I(PHY,"Estimated peak_val %d dB, avg %d => timing offset %llu\n",dB_fixed(peak_val),dB_fixed(avg),(unsigned long long int)ru->rx_offset);
 	ru->in_synch = 1;
-
+/*
         LOG_M("ru_sync_rx.m","rurx",&ru->common.rxdata[0][0],LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*fp->samples_per_tti,1,1);
         LOG_M("ru_sync_corr.m","sync_corr",ru->dmrs_corr,LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*fp->samples_per_tti,1,6);
         LOG_M("ru_dmrs.m","rudmrs",&ru->dmrssync[0],fp->ofdm_symbol_size,1,1);
-        //exit(-1);
+  */      
+//exit(-1);
       } // sync_pos > 0
       else //AssertFatal(cnt<1000,"Cannot find synch reference\n");
           { 
-- 
2.26.2