From 570ac353f1205bb2baf84430227ddebfb653ea27 Mon Sep 17 00:00:00 2001
From: Raymond Knopp <raymond.knopp@eurecom.fr>
Date: Sun, 4 Mar 2018 18:38:43 +0100
Subject: [PATCH] frame resynchronization in RAU and RRU

---
 openair1/PHY/defs.h       |  14 +++-
 targets/RT/USER/lte-enb.c |  17 ++--
 targets/RT/USER/lte-ru.c  | 167 ++++++++++++++++++++++----------------
 3 files changed, 117 insertions(+), 81 deletions(-)

diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h
index 8b868222895..8e89433b70c 100644
--- a/openair1/PHY/defs.h
+++ b/openair1/PHY/defs.h
@@ -559,7 +559,9 @@ typedef struct eNB_proc_t_s {
   /// mutex for RU access to eNB processing (PRACH BR)
   pthread_mutex_t mutex_RU_PRACH_br;
   /// mask for RUs serving eNB (PDSCH/PUSCH)
-  int RU_mask;
+  int RU_mask[10];
+  /// time measurements for RU arrivals
+  struct timespec t[10];
   /// mask for RUs serving eNB (PRACH)
   int RU_mask_prach;
 #ifdef Rel14
@@ -687,7 +689,8 @@ typedef enum {
 /// Some commamds to RRU. Not sure we should do it like this !
 typedef enum {
   EMPTY     = 0,
-  STOP_RU   = 1
+  STOP_RU   = 1,
+  RU_FRAME_RESYNCH = 2
 } rru_cmd_t;
 
 typedef struct RU_t_s{
@@ -709,6 +712,8 @@ typedef struct RU_t_s{
   int rx_offset;        
   /// flag to indicate the RU is a slave to another source
   int is_slave;
+  /// counter to delay start of processing of RU until HW settles
+  int wait_cnt;
   /// Total gain of receive chain
   uint32_t             rx_total_gain_dB;
   /// number of bands that this device can support
@@ -812,6 +817,8 @@ typedef struct RU_t_s{
   rru_state_t state;
   /// Command to do
   rru_cmd_t cmd;
+  /// value to be passed using command
+  uint16_t cmdval;
   /// process scheduling variables
   RU_proc_t            proc;
   /// stats thread pthread descriptor
@@ -1501,7 +1508,8 @@ typedef enum {
   RRU_config_ok=4,
   RRU_start=5,
   RRU_stop=6,
-  RRU_sync_ok=7
+  RRU_sync_ok=7,
+  RRU_frame_resynch=8
 } rru_config_msg_type_t;
 
 
diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c
index b300aac83eb..e36bde783c0 100644
--- a/targets/RT/USER/lte-enb.c
+++ b/targets/RT/USER/lte-enb.c
@@ -225,6 +225,7 @@ static inline int rxtx(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, char *thread_nam
 
   // UE-specific RX processing for subframe n
   if (nfapi_mode == 0 || nfapi_mode == 1) {
+    LOG_I(PHY,"Calling RX procedures for SFNSF %d.%d\n",proc->frame_rx,proc->subframe_rx);
     phy_procedures_eNB_uespec_RX(eNB, proc, no_relay );
   }
 
@@ -250,7 +251,7 @@ static inline int rxtx(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, char *thread_nam
   
   if (oai_exit) return(-1);
 
-  LOG_D(PHY,"Calling eNB_procedures_TX for SFN.SF %d.%d\n",proc->frame_tx,proc->subframe_tx);  
+  LOG_I(PHY,"Calling eNB_procedures_TX for SFN.SF %d.%d\n",proc->frame_tx,proc->subframe_tx);  
   phy_procedures_eNB_TX(eNB, proc, no_relay, NULL, 1);
 
   stop_meas( &softmodem_stats_rxtx_sf );
@@ -416,21 +417,21 @@ int wakeup_rxtx(PHY_VARS_eNB *eNB,RU_t *ru) {
   pthread_mutex_lock(&proc->mutex_RU);
   for (i=0;i<eNB->num_RU;i++) {
     if (ru == eNB->RU_list[i]) {
-      if ((proc->RU_mask&(1<<i)) > 0)
+      if ((proc->RU_mask[ru->proc.subframe_rx]&(1<<i)) > 0)
 	LOG_E(PHY,"eNB %d frame %d, subframe %d : previous information from RU %d (num_RU %d,mask %x) has not been served yet!\n",
-	      eNB->Mod_id,proc->frame_rx,proc->subframe_rx,ru->idx,eNB->num_RU,proc->RU_mask);
-      proc->RU_mask |= (1<<i);
+	      eNB->Mod_id,proc->frame_rx,proc->subframe_rx,ru->idx,eNB->num_RU,proc->RU_mask[ru->proc.subframe_rx]);
+      proc->RU_mask[ru->proc.subframe_rx] |= (1<<i);
     }else if (eNB->RU_list[i]->state == RU_SYNC){
-        proc->RU_mask |= (1<<i);
+        proc->RU_mask[ru->proc.subframe_rx] |= (1<<i);
      }
   }
-  if (proc->RU_mask != (1<<eNB->num_RU)-1) {  // not all RUs have provided their information so return
+  if (proc->RU_mask[ru->proc.subframe_rx] != (1<<eNB->num_RU)-1) {  // not all RUs have provided their information so return
     LOG_E(PHY,"Not all RUs have provided their info\n");
     pthread_mutex_unlock(&proc->mutex_RU);
     return(0);
   }
   else { // all RUs have provided their information so continue on and wakeup eNB processing
-    proc->RU_mask = 0;
+    proc->RU_mask[ru->proc.subframe_rx] = 0;
     pthread_mutex_unlock(&proc->mutex_RU);
   }
 
@@ -724,7 +725,7 @@ void init_eNB_proc(int inst) {
 
     proc->first_rx=1;
     proc->first_tx=1;
-    proc->RU_mask=0;
+    for (i=0;i<10;i++) proc->RU_mask[i]=0;
     proc->RU_mask_prach=0;
 
     pthread_mutex_init( &eNB->UL_INFO_mutex, NULL);
diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c
index 38ede8340da..ea89667c85a 100644
--- a/targets/RT/USER/lte-ru.c
+++ b/targets/RT/USER/lte-ru.c
@@ -584,6 +584,7 @@ void fh_if4p5_south_asynch_in(RU_t *ru,int *frame,int *subframe) {
 
   do {   // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!!
     recv_IF4p5(ru, &proc->frame_rx, &proc->subframe_rx, &packet_type, &symbol_number);
+    if (ru->cmd == STOP_RU) break;
     // grab first prach information for this new subframe
     if (got_prach_info==0) {
       prach_rx       = is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx);
@@ -793,6 +794,12 @@ void rx_rf(RU_t *ru,int *frame,int *subframe) {
 				   ru->nb_rx);
   
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );
+
+  if (ru->cmd==RU_FRAME_RESYNCH) {
+    ru->ts_offset += (proc->frame_rx - ru->cmdval)*fp->samples_per_tti*10;
+    *frame = ru->cmdval;
+    ru->cmd=EMPTY;
+  }
  
   proc->timestamp_rx = ts-ru->ts_offset;
 
@@ -1240,6 +1247,7 @@ void wakeup_eNBs(RU_t *ru) {
   PHY_VARS_eNB **eNB_list = ru->eNB_list;
   PHY_VARS_eNB *eNB=eNB_list[0];
   eNB_proc_t *proc = &eNB->proc;
+  struct timespec t;
 
   LOG_D(PHY,"wakeup_eNBs (num %d) for RU %d (state %s)ru->eNB_top:%p\n",ru->num_eNB,ru->idx, ru_states[ru->state],ru->eNB_top);
 
@@ -1248,32 +1256,36 @@ void wakeup_eNBs(RU_t *ru) {
 
     char string[20];
     sprintf(string,"Incoming RU %d",ru->idx);
-    LOG_D(PHY,"Frame %d, Subframe %d: RU %d Waking up eNB,RU_mask %x\n",ru->proc.frame_rx,ru->proc.subframe_rx,ru->idx,proc->RU_mask);
     
     pthread_mutex_lock(&proc->mutex_RU);
+    LOG_D(PHY,"Frame %d, Subframe %d: RU %d done,RU_mask[%d] %x\n",ru->proc.frame_rx,ru->proc.subframe_rx,ru->idx,ru->proc.subframe_rx,proc->RU_mask[ru->proc.subframe_rx]);
+
+    if (proc->RU_mask[ru->proc.subframe_rx] == 0)
+      clock_gettime(CLOCK_MONOTONIC,&proc->t[ru->proc.subframe_rx]);
     for (i=0;i<eNB->num_RU;i++) {
       LOG_D(PHY,"RU %d state %s\n",eNB->RU_list[i]->idx,ru_states[eNB->RU_list[i]->state]);
       if (ru == eNB->RU_list[i]) {
 //	AssertFatal((proc->RU_mask&(1<<i)) == 0, "eNB %d frame %d, subframe %d : previous information from RU %d (num_RU %d,mask %x) has not been served yet!\n",eNB->Mod_id,ru->proc.frame_rx,ru->proc.subframe_rx,ru->idx,eNB->num_RU,proc->RU_mask);
-        proc->RU_mask |= (1<<i);
-      }else if (eNB->RU_list[i]->state == RU_SYNC){
-      	proc->RU_mask |= (1<<i);
+        proc->RU_mask[ru->proc.subframe_rx] |= (1<<i);
+      }else if (eNB->RU_list[i]->state == RU_SYNC || eNB->RU_list[i]->wait_cnt > 0){
+      	proc->RU_mask[ru->proc.subframe_rx] |= (1<<i);
       }
     }
-    LOG_D(PHY,"RU mask is now %x\n",proc->RU_mask);
-    if (proc->RU_mask != (1<<eNB->num_RU)-1) {  // not all RUs have provided their information so return
-      pthread_mutex_unlock(&proc->mutex_RU);
-      return(0);
+    LOG_D(PHY,"RU mask is now %x\n",proc->RU_mask[ru->proc.subframe_rx]);
+
+    if (proc->RU_mask[ru->proc.subframe_rx] == (1<<eNB->num_RU)-1) {
+      proc->RU_mask[ru->proc.subframe_rx] = 0;
+      clock_gettime(CLOCK_MONOTONIC,&t);
+      AssertFatal(t.tv_nsec > proc->t[ru->proc.subframe_rx].tv_nsec+500000,
+                  "Time difference for subframe %d => %d > 5ms\n",
+                  ru->proc.subframe_rx,t.tv_nsec - proc->t[ru->proc.subframe_rx].tv_nsec);
     }
-    else { // all RUs have provided their information so continue on and wakeup eNB processing
-      proc->RU_mask = 0;
-      pthread_mutex_unlock(&proc->mutex_RU);
-    }
-
+    
+    pthread_mutex_unlock(&proc->mutex_RU);
     LOG_D(PHY,"wakeup eNB top for for subframe %d\n", ru->proc.subframe_rx);
     ru->eNB_top(eNB_list[0],ru->proc.frame_rx,ru->proc.subframe_rx,string);
   }
-  else {
+  else { // multiple eNB case for later
 
     LOG_D(PHY,"ru->num_eNB:%d\n", ru->num_eNB);
 
@@ -1564,9 +1576,8 @@ static void* ru_thread_control( void* param ) {
 	      break;
 
 	    case RRU_capabilities: // RAU
-	      if (ru->if_south == LOCAL_RF){
-		LOG_I(PHY,"Received RRU_capab msg...Ignoring\n");
-	      }
+	      if (ru->if_south == LOCAL_RF) LOG_E(PHY,"Received RRU_capab msg...Ignoring\n");
+	      
 	      else{
 		msg_len  = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t);
 
@@ -1629,15 +1640,13 @@ static void* ru_thread_control( void* param ) {
 			    "RU %d failed send CONFIG_OK to RAU\n",ru->idx);
                 reset_proc(ru);
 		ru->state = RU_READY;
-	      }else{
-		LOG_I(PHY,"Received RRU_config msg...Ignoring\n");
-	      }	
+	      } else LOG_E(PHY,"Received RRU_config msg...Ignoring\n");
+	      	
 	      break;	
 
 	    case RRU_config_ok: // RAU
-	      if (ru->if_south == LOCAL_RF){
-		LOG_I(PHY,"Received RRU_config_ok msg...Ignoring\n");
-	      }else{
+	      if (ru->if_south == LOCAL_RF) LOG_E(PHY,"Received RRU_config_ok msg...Ignoring\n");
+	      else{
 
 		if (setup_RU_buffers(ru)!=0) {
 		  printf("Exiting, cannot initialize RU Buffers\n");
@@ -1701,27 +1710,30 @@ static void* ru_thread_control( void* param ) {
 		    break;
 		  }
 		}
-		else{
-		  LOG_I(PHY,"RRU not ready, cannot start\n"); 
-		}
-	      }else{
-		LOG_I(PHY,"Received RRU_start msg...Ignoring\n");
-	      }
+		else LOG_E(PHY,"RRU not ready, cannot start\n"); 
+		
+	      } else LOG_E(PHY,"Received RRU_start msg...Ignoring\n");
+	      
 
 	      break;
 
 	    case RRU_sync_ok: //RAU
-	      if (ru->if_south == LOCAL_RF){
-		LOG_I(PHY,"Received RRU_config_ok msg...Ignoring\n");
-	      }else{
+	      if (ru->if_south == LOCAL_RF) LOG_E(PHY,"Received RRU_config_ok msg...Ignoring\n");
+	      else{
 		if (ru->is_slave == 1){
+                  LOG_I(PHY,"Received RRU_sync_ok from RRU %d\n",ru->idx);
 		  // Just change the state of the RRU to unblock ru_thread()
 		  ru->state = RU_RUN;		
-		}else{
-		  LOG_I(PHY,"Received RRU_sync_ok from a master RRU...Ignoring\n");
-		}	
+		}else LOG_E(PHY,"Received RRU_sync_ok from a master RRU...Ignoring\n"); 	
 	      }
 	      break;
+            case RRU_frame_resynch: //RRU
+              if (ru->if_south != LOCAL_RF) LOG_E(PHY,"Received RRU frame resynch message, should not happen in RAU\n");
+              else {
+                 ru->cmd = RU_FRAME_RESYNCH;
+                 ru->cmdval = ((uint16_t*)&rru_config_msg.msg[0])[0];
+              }
+              break;
 
 	    case RRU_stop: // RRU
 	      if (ru->if_south == LOCAL_RF){
@@ -1735,9 +1747,8 @@ static void* ru_thread_control( void* param ) {
 		}else{
 		  LOG_I(PHY,"RRU not running, can't stop\n"); 
 		}
-	      }else{
-		LOG_I(PHY,"Received RRU_stop msg...Ignoring\n");
-	      }
+	      }else LOG_E(PHY,"Received RRU_stop msg...Ignoring\n");
+	      
 	      break;
 
 	    default:
@@ -1778,16 +1789,17 @@ static void* ru_thread( void* param ) {
 
   LOG_I(PHY,"Starting RU %d (%s,%s),\n",ru->idx,eNB_functions[ru->function],eNB_timing[ru->if_timing]);
 
-  
 	
   while (!oai_exit) {
   
+    if (ru->if_south != LOCAL_RF) ru->wait_cnt = 100;
+    else                          ru->wait_cnt = 0;
 
     // wait to be woken up
     if (wait_on_condition(&ru->proc.mutex_ru,&ru->proc.cond_ru_thread,&ru->proc.instance_cnt_ru,"ru_thread")<0) break;
 	  
-    if (ru->is_slave == 0) AssertFatal(ru->state == RU_RUN,"ru->state = %d != RU_RUN\n",ru->state);
-    else if (ru->is_slave == 1) AssertFatal(ru->state == RU_SYNC,"ru->state = %d != RU_SYNC\n",ru->state);  
+    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]);  
     // Start RF device if any
     if (ru->start_rf) {
       if (ru->start_rf(ru) != 0)
@@ -1826,10 +1838,6 @@ static void* ru_thread( void* param ) {
 	subframe++;
       }      
 
-      LOG_D(PHY,"RU thread %d, frame %d (%p), subframe %d (%p)\n",
-	    ru->idx, frame,&frame,subframe,&subframe);
-
-    
 
       // synchronization on input FH interface, acquire signals/data and block
       if (ru->stop_rf && ru->cmd == STOP_RU) {
@@ -1848,43 +1856,62 @@ static void* ru_thread( void* param ) {
             
       if (ru->fh_south_in && ru->state == RU_RUN ) ru->fh_south_in(ru,&frame,&subframe);
       else AssertFatal(1==0, "No fronthaul interface at south port");
-
-      if ((ru->do_prach>0) && (is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx)==1)) {
-	wakeup_prach_ru(ru);
+      if (ru->wait_cnt > 0) {
+         ru->wait_cnt--;
+
+         if (ru->if_south!=LOCAL_RF && ru->wait_cnt <=20 && subframe == 5 && frame != RC.ru[0]->proc.frame_rx) {
+           // Send RRU_frame adjust
+           RRU_CONFIG_msg_t rru_config_msg;
+           rru_config_msg.type = RRU_frame_resynch;
+           rru_config_msg.len  = sizeof(RRU_CONFIG_msg_t); // TODO: set to correct msg len
+           ((uint16_t*)&rru_config_msg.msg[0])[0] = RC.ru[0]->proc.frame_rx;
+           LOG_I(PHY,"Sending Frame Resynch %d to RRU\n", ru->idx,RC.ru[0]->proc.frame_rx);
+           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 {
+
+        LOG_D(PHY,"RU thread %d, frame %d, subframe %d \n",
+              ru->idx,frame,subframe);
+
+
+        if ((ru->do_prach>0) && (is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx)==1)) {
+  	  wakeup_prach_ru(ru);
+        }
 #ifdef Rel14
-      else if ((ru->do_prach>0) && (is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx)>1)) {
-	wakeup_prach_ru_br(ru);
-      }
+        else if ((ru->do_prach>0) && (is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx)>1)) {
+	  wakeup_prach_ru_br(ru);
+        }
 #endif
 
-      // adjust for timing offset between RU
-      if (ru->idx!=0) proc->frame_tx = (proc->frame_tx+proc->frame_offset)&1023;
+        // adjust for timing offset between RU
+        if (ru->idx!=0) proc->frame_tx = (proc->frame_tx+proc->frame_offset)&1023;
 
-      // At this point, all information for subframe has been received on FH interface
-      // If this proc is to provide synchronization, do so
-      wakeup_slaves(proc);
+        // At this point, all information for subframe has been received on FH interface
+        // If this proc is to provide synchronization, do so
+        wakeup_slaves(proc);
 
-      // do RX front-end processing (frequency-shift, dft) if needed
-      if (ru->feprx) ru->feprx(ru);
+        // do RX front-end processing (frequency-shift, dft) if needed
+        if (ru->feprx) ru->feprx(ru);
 
-      // wakeup all eNB processes waiting for this RU
-      if (ru->num_eNB>0) wakeup_eNBs(ru);
+        // wakeup all eNB processes waiting for this RU
+        if (ru->num_eNB>0) wakeup_eNBs(ru);
 
-      // wait until eNBs are finished subframe RX n and TX n+4
-      wait_on_condition(&proc->mutex_eNBs,&proc->cond_eNBs,&proc->instance_cnt_eNBs,"ru_thread");
+        // wait until eNBs are finished subframe RX n and TX n+4
+        wait_on_condition(&proc->mutex_eNBs,&proc->cond_eNBs,&proc->instance_cnt_eNBs,"ru_thread");
 
 
-      // do TX front-end processing if needed (precoding and/or IDFTs)
-      if (ru->feptx_prec) ru->feptx_prec(ru);
+        // do TX front-end processing if needed (precoding and/or IDFTs)
+        if (ru->feptx_prec) ru->feptx_prec(ru);
 	   
-      // do OFDM if needed
-      if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru);
-      // do outgoing fronthaul (south) if needed
-      if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru);
+        // do OFDM if needed
+        if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru);
+        // do outgoing fronthaul (south) if needed
+        if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru);
 	 
-      if (ru->fh_north_out) ru->fh_north_out(ru);
-
+        if (ru->fh_north_out) ru->fh_north_out(ru);
+      }
     }
 
   } // while !oai_exit
-- 
GitLab