From 20b0aae98ba0aaedfd035a287437b2079765b8c5 Mon Sep 17 00:00:00 2001 From: Raymond Knopp <raymond.knopp@eurecom.fr> Date: Mon, 21 Nov 2016 18:00:36 +0800 Subject: [PATCH] integration of over-the-air synchronization mechanism for distributed RRU --- openair1/PHY/LTE_ESTIMATION/lte_sync_time.c | 21 +-- openair1/PHY/defs.h | 16 ++ targets/RT/USER/lte-enb.c | 193 +++++++++++++++++++- targets/RT/USER/lte-softmodem.c | 12 +- 4 files changed, 225 insertions(+), 17 deletions(-) diff --git a/openair1/PHY/LTE_ESTIMATION/lte_sync_time.c b/openair1/PHY/LTE_ESTIMATION/lte_sync_time.c index dfb39a510f0..5f0ba9b2d2e 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_sync_time.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_sync_time.c @@ -517,14 +517,15 @@ int lte_sync_time_eNB(int32_t **rxdata, ///rx data in time domain // perform a time domain correlation using the oversampled sync sequence - unsigned int n, ar, peak_val, peak_pos, mean_val; + unsigned int n, ar, peak_val, peak_pos; + uint64_t mean_val; int result; short *primary_synch_time; int eNB_id = frame_parms->Nid_cell%3; // msg("[SYNC TIME] Calling sync_time_eNB(%p,%p,%d,%d)\n",rxdata,frame_parms,eNB_id,length); if (sync_corr_eNB == NULL) { - msg("[SYNC TIME] sync_corr_eNB not yet allocated! Exiting.\n"); + LOG_E(PHY,"[SYNC TIME] sync_corr_eNB not yet allocated! Exiting.\n"); return(-1); } @@ -542,7 +543,7 @@ int lte_sync_time_eNB(int32_t **rxdata, ///rx data in time domain break; default: - msg("[SYNC TIME] Illegal eNB_id!\n"); + LOG_E(PHY,"[SYNC TIME] Illegal eNB_id!\n"); return (-1); } @@ -574,7 +575,7 @@ int lte_sync_time_eNB(int32_t **rxdata, ///rx data in time domain peak_val); } */ - mean_val += (sync_corr_eNB[n]>>10); + mean_val += sync_corr_eNB[n]; if (sync_corr_eNB[n]>peak_val) { peak_val = sync_corr_eNB[n]; @@ -582,17 +583,15 @@ int lte_sync_time_eNB(int32_t **rxdata, ///rx data in time domain } } + mean_val/=length; + *peak_val_out = peak_val; - if (peak_val <= (40*mean_val)) { -#ifdef DEBUG_PHY - msg("[SYNC TIME] No peak found (%u,%u,%u,%u)\n",peak_pos,peak_val,mean_val,40*mean_val); -#endif + if (peak_val <= (40*(uint32_t)mean_val)) { + LOG_D(PHY,"[SYNC TIME] No peak found (%u,%u,%u,%u)\n",peak_pos,peak_val,mean_val,40*mean_val); return(-1); } else { -#ifdef DEBUG_PHY - msg("[SYNC TIME] Peak found at pos %u, val = %u, mean_val = %u\n",peak_pos,peak_val,mean_val); -#endif + LOG_D(PHY,"[SYNC TIME] Peak found at pos %u, val = %u, mean_val = %u\n",peak_pos,peak_val,mean_val); return(peak_pos); } diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h index 703bdd2d6fd..e42157769db 100755 --- a/openair1/PHY/defs.h +++ b/openair1/PHY/defs.h @@ -256,6 +256,8 @@ typedef struct eNB_proc_t_s { /// \brief Instance count for rx processing thread. /// \internal This variable is protected by \ref mutex_prach. int instance_cnt_prach; + // instance count for over-the-air eNB synchronization + int instance_cnt_synch; /// \internal This variable is protected by \ref mutex_asynch_rxtx. int instance_cnt_asynch_rxtx; /// pthread structure for FH processing thread @@ -280,6 +282,8 @@ typedef struct eNB_proc_t_s { pthread_attr_t attr_single; /// pthread attributes for prach processing thread pthread_attr_t attr_prach; + /// pthread attributes for over-the-air synch thread + pthread_attr_t attr_synch; /// pthread attributes for asynchronous RX thread pthread_attr_t attr_asynch_rxtx; /// scheduling parameters for parallel fep thread @@ -294,6 +298,8 @@ typedef struct eNB_proc_t_s { struct sched_param sched_param_single; /// scheduling parameters for prach thread struct sched_param sched_param_prach; + /// scheduling parameters for over-the-air synchronization thread + struct sched_param sched_param_synch; /// scheduling parameters for asynch_rxtx thread struct sched_param sched_param_asynch_rxtx; /// pthread structure for parallel fep thread @@ -304,6 +310,8 @@ typedef struct eNB_proc_t_s { pthread_t pthread_te; /// pthread structure for PRACH thread pthread_t pthread_prach; + /// pthread structure for eNB synch thread + pthread_t pthread_synch; /// condition variable for parallel fep thread pthread_cond_t cond_fep; /// condition variable for parallel turbo-decoder thread @@ -314,6 +322,8 @@ typedef struct eNB_proc_t_s { pthread_cond_t cond_FH; /// condition variable for PRACH processing thread; pthread_cond_t cond_prach; + // condition variable for over-the-air eNB synchronization + pthread_cond_t cond_synch; /// condition variable for asynch RX/TX thread pthread_cond_t cond_asynch_rxtx; /// mutex for parallel fep thread @@ -326,6 +336,8 @@ typedef struct eNB_proc_t_s { pthread_mutex_t mutex_FH; /// mutex for PRACH thread pthread_mutex_t mutex_prach; + // mutex for over-the-air eNB synchronization + pthread_mutex_t mutex_synch; /// mutex for asynch RX/TX thread pthread_mutex_t mutex_asynch_rxtx; /// parameters for turbo-decoding worker thread @@ -411,6 +423,10 @@ typedef struct PHY_VARS_eNB_s { openair0_rf_map rf_map; int abstraction_flag; openair0_timestamp ts_offset; + // indicator for synchronization state of eNB + int in_synch; + // indicator for master/slave (RRU) + int is_slave; void (*do_prach)(struct PHY_VARS_eNB_s *eNB); void (*fep)(struct PHY_VARS_eNB_s *eNB); int (*td)(struct PHY_VARS_eNB_s *eNB,int UE_id,int harq_pid,int llr8_flag); diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index 58494caed4d..66d60bf2ccc 100644 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -161,7 +161,7 @@ static struct { void exit_fun(const char* s); -void init_eNB(eNB_func_t node_function[], eNB_timing_t node_timing[],int nb_inst,eth_params_t *,int); +void init_eNB(eNB_func_t node_function[], eNB_timing_t node_timing[],int nb_inst,eth_params_t *,int,int); void stop_eNB(int nb_inst); @@ -1122,6 +1122,114 @@ void wakeup_slaves(eNB_proc_t *proc) { } } +uint32_t sync_corr[307200] __attribute__((aligned(32))); + +// This thread run the initial synchronization like a UE +void *eNB_thread_synch(void *arg) { + + PHY_VARS_eNB *eNB = (PHY_VARS_eNB*)arg; + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + int32_t sync_pos,sync_pos2; + uint32_t peak_val; + + thread_top_init("eNB_thread_synch",0,5000000,10000000,10000000); + + wait_sync("eNB_thread_synch"); + + // initialize variables for PSS detection + lte_sync_time_init(&eNB->frame_parms); + + while (!oai_exit) { + + // wait to be woken up + pthread_mutex_lock(&eNB->proc.mutex_synch); + while (eNB->proc.instance_cnt_synch < 0) + pthread_cond_wait(&eNB->proc.cond_synch,&eNB->proc.mutex_synch); + pthread_mutex_unlock(&eNB->proc.mutex_synch); + + // if we're not in synch, then run initial synch + if (eNB->in_synch == 0) { + // run intial synch like UE + LOG_I(PHY,"Running initial synchronization\n"); + + sync_pos = lte_sync_time_eNB(eNB->common_vars.rxdata[0], + fp, + fp->samples_per_tti*5, + &peak_val, + sync_corr); + LOG_I(PHY,"eNB synch: %d, val %d\n",sync_pos,peak_val); + + if (sync_pos >= 0) { + if (sync_pos >= fp->nb_prefix_samples) + sync_pos2 = sync_pos - fp->nb_prefix_samples; + else + sync_pos2 = sync_pos + (fp->samples_per_tti*10) - fp->nb_prefix_samples; + + if (fp->frame_type == FDD) { + + // PSS is hypothesized in last symbol of first slot in Frame + int sync_pos_slot = (fp->samples_per_tti>>1) - fp->ofdm_symbol_size - fp->nb_prefix_samples; + + if (sync_pos2 >= sync_pos_slot) + eNB->rx_offset = sync_pos2 - sync_pos_slot; + else + eNB->rx_offset = (fp->samples_per_tti*10) + sync_pos2 - sync_pos_slot; + } + else { + + } + + LOG_I(PHY,"Estimated sync_pos %d, peak_val %d => timing offset %d\n",sync_pos,peak_val,eNB->rx_offset); + + + /* if ((peak_val > 10000) && (sync_pos == -1)) { + // if (sync_pos++ > 3) { + write_output("eNB_sync.m","sync",(void*)&sync_corr[0],fp->samples_per_tti*5,1,2); + write_output("eNB_rx.m","rxs",(void*)eNB->common_vars.rxdata[0][0],fp->samples_per_tti*10,1,1); + exit(-1); + }*/ + } + } + + // release thread + pthread_mutex_lock(&eNB->proc.mutex_synch); + eNB->proc.instance_cnt_synch--; + pthread_mutex_unlock(&eNB->proc.mutex_synch); + } // oai_exit + + lte_sync_time_free(); + +} + +int wakeup_synch(PHY_VARS_eNB *eNB){ + + struct timespec wait; + + wait.tv_sec=0; + wait.tv_nsec=5000000L; + + // wake up synch thread + // lock the synch mutex and make sure the thread is ready + if (pthread_mutex_timedlock(&eNB->proc.mutex_synch,&wait) != 0) { + LOG_E( PHY, "[eNB] ERROR pthread_mutex_lock for eNB synch thread (IC %d)\n", eNB->proc.instance_cnt_synch ); + exit_fun( "error locking mutex_synch" ); + return(-1); + } + + ++eNB->proc.instance_cnt_synch; + + // the thread can now be woken up + if (pthread_cond_signal(&eNB->proc.cond_synch) != 0) { + LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB synch thread\n"); + exit_fun( "ERROR pthread_cond_signal" ); + return(-1); + } + + pthread_mutex_unlock( &eNB->proc.mutex_synch ); + + return(0); +} + /*! * \brief The Fronthaul thread of RRU/RAU/RCC/eNB * In the case of RRU/eNB, handles interface with external RF @@ -1242,6 +1350,8 @@ static void* eNB_thread_prach( void* param ) { return &eNB_thread_prach_status; } + + static void* eNB_thread_single( void* param ) { static int eNB_thread_single_status; @@ -1249,9 +1359,24 @@ static void* eNB_thread_single( void* param ) { eNB_proc_t *proc = (eNB_proc_t*)param; eNB_rxtx_proc_t *proc_rxtx = &proc->proc_rxtx[0]; PHY_VARS_eNB *eNB = PHY_vars_eNB_g[0][proc->CC_id]; + LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; + + void *rxp[2],*rxp2[2]; int subframe=0, frame=0; + int32_t dummy_rx[fp->nb_antennas_rx][fp->samples_per_tti] __attribute__((aligned(32))); + + int ic; + + int rxs; + + int i; + + // initialize the synchronization buffer to the common_vars.rxdata + for (int i=0;i<fp->nb_antennas_rx;i++) + rxp[i] = &eNB->common_vars.rxdata[0][i][0]; + // set default return value eNB_thread_single_status = 0; @@ -1280,6 +1405,57 @@ static void* eNB_thread_single( void* param ) { pthread_mutex_unlock(&proc->mutex_asynch_rxtx); pthread_cond_signal(&proc->cond_asynch_rxtx); + + + // if this is a slave eNB, try to synchronize on the DL frequency + if ((eNB->is_slave) && + ((eNB->node_function >= NGFI_RRU_IF5))) { + // if FDD, switch RX on DL frequency + + double temp_freq1 = eNB->rfdevice.openair0_cfg->rx_freq[0]; + double temp_freq2 = eNB->rfdevice.openair0_cfg->tx_freq[0]; + for (i=0;i<4;i++) { + eNB->rfdevice.openair0_cfg->rx_freq[i] = eNB->rfdevice.openair0_cfg->tx_freq[i]; + eNB->rfdevice.openair0_cfg->tx_freq[i] = temp_freq1; + } + eNB->rfdevice.trx_set_freq_func(&eNB->rfdevice,eNB->rfdevice.openair0_cfg,0); + + while ((eNB->in_synch ==0)&&(!oai_exit)) { + // read in frame + rxs = eNB->rfdevice.trx_read_func(&eNB->rfdevice, + &(proc->timestamp_rx), + rxp, + fp->samples_per_tti*10, + fp->nb_antennas_rx); + // wakeup synchronization processing thread + wakeup_synch(eNB); + ic=0; + + while ((ic>=0)&&(!oai_exit)) { + // continuously read in frames, 1ms at a time, + // until we are done with the synchronization procedure + + for (i=0; i<fp->nb_antennas_rx; i++) + rxp2[i] = (void*)&dummy_rx[i][0]; + for (i=0;i<10;i++) + rxs = eNB->rfdevice.trx_read_func(&eNB->rfdevice, + &(proc->timestamp_rx), + rxp2, + fp->samples_per_tti, + fp->nb_antennas_rx); + pthread_mutex_lock(&eNB->proc.mutex_synch); + ic = eNB->proc.instance_cnt_synch; + pthread_mutex_unlock(&eNB->proc.mutex_synch); + } // ic>=0 + } // in_synch==0 + for (i=0;i<4;i++) { + eNB->rfdevice.openair0_cfg->rx_freq[i] = temp_freq1; + eNB->rfdevice.openair0_cfg->rx_freq[i] = temp_freq2; + } + eNB->rfdevice.trx_set_freq_func(&eNB->rfdevice,eNB->rfdevice.openair0_cfg,0); + } // if RRU and slave + + // This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices while (!oai_exit) { @@ -1334,7 +1510,7 @@ void init_eNB_proc(int inst) { PHY_VARS_eNB *eNB; eNB_proc_t *proc; eNB_rxtx_proc_t *proc_rxtx; - pthread_attr_t *attr0=NULL,*attr1=NULL,*attr_FH=NULL,*attr_prach=NULL,*attr_asynch=NULL,*attr_single=NULL,*attr_fep=NULL,*attr_td=NULL,*attr_te; + pthread_attr_t *attr0=NULL,*attr1=NULL,*attr_FH=NULL,*attr_prach=NULL,*attr_asynch=NULL,*attr_single=NULL,*attr_fep=NULL,*attr_td=NULL,*attr_te=NULL,*attr_synch=NULL; for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { eNB = PHY_vars_eNB_g[inst][CC_id]; @@ -1348,7 +1524,8 @@ void init_eNB_proc(int inst) { proc->instance_cnt_FH = -1; proc->instance_cnt_asynch_rxtx = -1; proc->CC_id = CC_id; - + proc->instance_cnt_synch = -1; + proc->first_rx=1; proc->first_tx=1; @@ -1359,13 +1536,16 @@ void init_eNB_proc(int inst) { pthread_mutex_init( &proc->mutex_prach, NULL); pthread_mutex_init( &proc->mutex_asynch_rxtx, NULL); + pthread_mutex_init( &proc->mutex_synch,NULL); pthread_cond_init( &proc->cond_prach, NULL); pthread_cond_init( &proc->cond_FH, NULL); pthread_cond_init( &proc->cond_asynch_rxtx, NULL); + pthread_cond_init( &proc->cond_synch,NULL); pthread_attr_init( &proc->attr_FH); pthread_attr_init( &proc->attr_prach); + pthread_attr_init( &proc->attr_synch); pthread_attr_init( &proc->attr_asynch_rxtx); pthread_attr_init( &proc->attr_single); pthread_attr_init( &proc->attr_fep); @@ -1378,6 +1558,7 @@ void init_eNB_proc(int inst) { attr1 = &proc_rxtx[1].attr_rxtx; attr_FH = &proc->attr_FH; attr_prach = &proc->attr_prach; + attr_synch = &proc->attr_synch; attr_asynch = &proc->attr_asynch_rxtx; attr_single = &proc->attr_single; attr_fep = &proc->attr_fep; @@ -1397,6 +1578,7 @@ void init_eNB_proc(int inst) { init_te_thread(eNB,attr_te); } pthread_create( &proc->pthread_prach, attr_prach, eNB_thread_prach, &eNB->proc ); + pthread_create( &proc->pthread_synch, attr_synch, eNB_thread_synch, eNB); if ((eNB->node_timing == synch_to_other) || (eNB->node_function == NGFI_RRU_IF5) || (eNB->node_function == NGFI_RRU_IF4p5)) @@ -1619,7 +1801,7 @@ extern void eNB_fep_full(PHY_VARS_eNB *eNB); extern void eNB_fep_full_2thread(PHY_VARS_eNB *eNB); extern void do_prach(PHY_VARS_eNB *eNB); -void init_eNB(eNB_func_t node_function[], eNB_timing_t node_timing[],int nb_inst,eth_params_t *eth_params,int single_thread_flag) { +void init_eNB(eNB_func_t node_function[], eNB_timing_t node_timing[],int nb_inst,eth_params_t *eth_params,int single_thread_flag,int wait_for_sync) { int CC_id; int inst; @@ -1634,6 +1816,9 @@ void init_eNB(eNB_func_t node_function[], eNB_timing_t node_timing[],int nb_inst eNB->abstraction_flag = 0; eNB->single_thread_flag = single_thread_flag; eNB->ts_offset = 0; + eNB->in_synch = 0; + eNB->is_slave = (wait_for_sync>0) ? 1 : 0; + LOG_I(PHY,"Initializing eNB %d CC_id %d : (%s,%s)\n",inst,CC_id,eNB_functions[node_function[CC_id]],eNB_timing[node_timing[CC_id]]); switch (node_function[CC_id]) { diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index eeb06753f3a..d2f2f9ccfbb 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -120,7 +120,7 @@ extern int netlink_init(void); // In lte-enb.c extern int setup_eNB_buffers(PHY_VARS_eNB **phy_vars_eNB, openair0_config_t *openair0_cfg); -extern void init_eNB(eNB_func_t *, eNB_timing_t *,int,eth_params_t *,int); +extern void init_eNB(eNB_func_t *, eNB_timing_t *,int,eth_params_t *,int,int); extern void stop_eNB(int); extern void kill_eNB_proc(void); @@ -170,6 +170,8 @@ volatile int oai_exit = 0; static clock_source_t clock_source = internal; +static wait_for_sync = 0; + static char UE_flag=0; unsigned int mmapped_dma=0; int single_thread_flag=0; @@ -696,6 +698,7 @@ static void get_options (int argc, char **argv) LONG_OPTION_MMAPPED_DMA, LONG_OPTION_SINGLE_THREAD, LONG_OPTION_EXTERNAL_CLOCK, + LONG_OPTION_WAIT_FOR_SYNC, #if T_TRACER LONG_OPTION_T_PORT, LONG_OPTION_T_NOWAIT, @@ -722,6 +725,7 @@ static void get_options (int argc, char **argv) {"mmapped-dma", no_argument, NULL, LONG_OPTION_MMAPPED_DMA}, {"single-thread", no_argument, NULL, LONG_OPTION_SINGLE_THREAD}, {"external-clock", no_argument, NULL, LONG_OPTION_EXTERNAL_CLOCK}, + {"wait-for-sync", no_argument, NULL, LONG_OPTION_WAIT_FOR_SYNC}, #if T_TRACER {"T_port", required_argument, 0, LONG_OPTION_T_PORT}, {"T_nowait", no_argument, 0, LONG_OPTION_T_NOWAIT}, @@ -827,6 +831,10 @@ static void get_options (int argc, char **argv) clock_source = external; break; + case LONG_OPTION_WAIT_FOR_SYNC: + wait_for_sync = 1; + break; + #if T_TRACER case LONG_OPTION_T_PORT: { extern int T_port; @@ -1808,7 +1816,7 @@ int main( int argc, char **argv ) // start the main thread if (UE_flag == 1) init_UE(1); else { - init_eNB(node_function,node_timing,1,eth_params,single_thread_flag); + init_eNB(node_function,node_timing,1,eth_params,single_thread_flag,wait_for_sync); // Sleep to allow all threads to setup number_of_cards = 1; -- GitLab