eNB_transport_IQ.c 26.8 KB
Newer Older
1
/*! \file eNB_transport_IQ.c
navid's avatar
navid committed
2
 * \brief eNB transport IQ samples 
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 * \author  Katerina Trilyraki, Navid Nikaein, Raymond Knopp
 * \date 2015
 * \version 0.1
 * \company Eurecom
 * \maintainer:  navid.nikaein@eurecom.fr
 * \note
 * \warning very experimental 
 */
#include <unistd.h>
#include <time.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>

#include "common_lib.h"
#include "PHY/defs.h"
#include "rrh_gw.h"
#include "rrh_gw_externs.h"
#include "rt_wrapper.h"

#define PRINTF_PERIOD    3750
#define HEADER_SIZE      ((sizeof(int32_t) + sizeof(openair0_timestamp))>>2)

28
29
pthread_cond_t          sync_eNB_cond[4];
pthread_mutex_t         sync_eNB_mutex[4];
navid's avatar
navid committed
30
31
32
pthread_mutex_t         sync_trx_mutex=PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t          sync_trx_cond=PTHREAD_COND_INITIALIZER;

33
openair0_timestamp 	nrt_eNB_counter[4]= {0,0,0,0};
34
35
36
37
38
39
40
int32_t 	overflow_rx_buffer_eNB[4]= {0,0,0,0};
int32_t 	nsamps_eNB[4]= {0,0,0,0};
int32_t 	eNB_tx_started=0,eNB_rx_started=0;
int32_t 	counter_eNB_rx[4]= {0,0,0,0};
int32_t 	counter_eNB_tx[4]= {0,0,0,0};
uint8_t		RT_flag_eNB,NRT_flag_eNB;
void 		*rrh_eNB_thread_status;
navid's avatar
navid committed
41
42
43
44
45
int 	        sync_eNB_rx[4]= {-1,-1,-1,-1};
unsigned int    sync_trx=0;

int32_t		**tx_buffer_eNB;
int32_t         **rx_buffer_eNB;
46
47
48
void 		**rx_eNB; //was fixed to 2 ant
void 		**tx_eNB; //was fixed to 2 ant

navid's avatar
navid committed
49
50
51
openair0_timestamp	timestamp_eNB_tx[4]= {0,0,0,0};// all antennas must have the same ts
openair0_timestamp      timestamp_eNB_rx[4]= {0,0,0,0};
openair0_timestamp	timestamp_rx=0,timestamp_tx=0;
52

navid's avatar
navid committed
53
54
55
unsigned int   rx_pos=0, next_rx_pos=0;
unsigned int   tx_pos=0, tx_pos_rf=0, prev_tx_pos=0;
unsigned int   rt_period=0;
56

navid's avatar
navid committed
57
58
struct itimerspec       timerspec;
pthread_mutex_t         timer_mutex;
59

navid's avatar
navid committed
60
61
62


/*! \fn void *rrh_eNB_rx_thread(void *arg)
63
64
 * \brief this function
 * \param[in]
navid's avatar
navid committed
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
 * \return none
 * \note
 * @ingroup  _oai
 */
void *rrh_eNB_rx_thread(void *);
/*! \fn void *rrh_eNB_tx_thread(void *arg)
 * \brief this function
 * \param[in]
 * \return none
 * \note
 * @ingroup  _oai
 */
void *rrh_eNB_tx_thread(void *);
/*! \fn void *rrh_eNB_thread(void *arg)
 * \brief this function
 * \param[in]
 * \return none
 * \note
 * @ingroup  _oai
 */
void *rrh_eNB_thread(void *);
/*! \fn  void check_dev_config( rrh_module_t *mod_enb)
 * \brief this function
 * \param[in] *mod_enb
 * \return none
 * \note
 * @ingroup  _oai
 */
static void check_dev_config( rrh_module_t *mod_enb);
/*! \fn void calc_rt_period_ns( openair0_config_t openair0_cfg)
 * \brief this function
 * \param[in] openair0_cfg
 * \return none
98
99
100
 * \note
 * @ingroup  _oai
 */
101
static void calc_rt_period_ns( openair0_config_t *openair0_cfg);
navid's avatar
navid committed
102
103
104
105



void config_BBU_mod( rrh_module_t *mod_enb, uint8_t RT_flag, uint8_t NRT_flag) {
106
  
navid's avatar
navid committed
107
108
109
110
  int 	             error_code_eNB;
  pthread_t	     main_rrh_eNB_thread;
  pthread_attr_t     attr;
  struct sched_param sched_param_rrh;
111
  
112
113
  RT_flag_eNB=RT_flag;
  NRT_flag_eNB=NRT_flag;
114
  
115
  /* init socket and have handshake-like msg with client to exchange parameters */
116
  mod_enb->eth_dev.trx_start_func(&mod_enb->eth_dev);//change port  make it plus_id
navid's avatar
navid committed
117

118
119
  mod_enb->devs->openair0_cfg = mod_enb->eth_dev.openair0_cfg;

120
  /* check sanity of configuration parameters and print */
Aikaterini Trilyraki's avatar
Aikaterini Trilyraki committed
121
122
123
124
125
  check_dev_config(mod_enb);  
  if (rf_config_file[0] == '\0')  
    mod_enb->devs->openair0_cfg->configFilename = NULL;
  else
    mod_enb->devs->openair0_cfg->configFilename = rf_config_file;
126
127
128
129
  /* initialize and configure the RF device */
  if (openair0_device_load(mod_enb->devs, mod_enb->devs->openair0_cfg)<0) {
    LOG_E(RRH,"Exiting, cannot initialize RF device.\n");
    exit(-1);
Aikaterini Trilyraki's avatar
Aikaterini Trilyraki committed
130
  } else {   
131
132
133
134
135
    if (mod_enb->devs->type != NONE_DEV) {
      /* start RF device */
      if (mod_enb->devs->type == EXMIMO_DEV) {
	//call start function for exmino
      } else {
Aikaterini Trilyraki's avatar
Aikaterini Trilyraki committed
136

137
138
139
140
	if (mod_enb->devs->trx_start_func(mod_enb->devs)!=0)
	  LOG_E(RRH,"Unable to initiate RF device.\n");
	else
	  LOG_I(RRH,"RF device has been initiated.\n");
navid's avatar
navid committed
141
      }
142
      
143
    }
144
  }  
145
  
navid's avatar
navid committed
146
147
148
149
150
151
152
153
  /* create main eNB module thread
     main_rrh_eNB_thread allocates memory 
     for TX/RX buffers and creates TX/RX
     threads for every eNB module */ 
  pthread_attr_init(&attr);
  sched_param_rrh.sched_priority = sched_get_priority_max(SCHED_FIFO);
  pthread_attr_setschedparam(&attr,&sched_param_rrh);
  pthread_attr_setschedpolicy(&attr,SCHED_FIFO);
154
  error_code_eNB = pthread_create(&main_rrh_eNB_thread, &attr, rrh_eNB_thread, (void *)mod_enb);
navid's avatar
navid committed
155

156
  if (error_code_eNB) {
157
    LOG_E(RRH,"Error while creating eNB thread\n");
158
159
    exit(-1);
  }
160
  
161
162
}

navid's avatar
navid committed
163
164
165

void *rrh_eNB_thread(void *arg) {

166
167
168
  rrh_module_t 	       	*dev=(rrh_module_t *)arg;
  pthread_t  	      	eNB_rx_thread, eNB_tx_thread;  
  int 	      		error_code_eNB_rx, error_code_eNB_tx;
169
  int32_t	        i,j;   		
170
171
172
  void 			*tmp;
  unsigned int          samples_per_frame=0;
  
173
  samples_per_frame = dev->eth_dev.openair0_cfg->samples_per_frame;    
navid's avatar
navid committed
174

175
176
  while (rrh_exit==0) {
    
navid's avatar
navid committed
177
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TRX, 1 );    
178
    
navid's avatar
navid committed
179
180
181
    /* calculate packet period */
    calc_rt_period_ns(dev->eth_dev.openair0_cfg);
        
182
183
    /* allocate memory for TX/RX buffers
       each antenna port has a TX and a RX buffer
184
       each TX and RX buffer is of (samples_per_frame + HEADER_SIZE) samples (size of samples is 4 bytes) */
185
186
    rx_buffer_eNB = (int32_t**)malloc16(dev->eth_dev.openair0_cfg->rx_num_channels*sizeof(int32_t*));
    tx_buffer_eNB = (int32_t**)malloc16(dev->eth_dev.openair0_cfg->tx_num_channels*sizeof(int32_t*));    
navid's avatar
navid committed
187
    LOG_D(RRH,"rx_buffer_eNB address =%p tx_buffer_eNB address =%p  \n",rx_buffer_eNB,tx_buffer_eNB);
188
    
189
    /* rx_buffer_eNB points to the beginning of data */
190
    for (i=0; i<dev->eth_dev.openair0_cfg->rx_num_channels; i++) {
navid's avatar
navid committed
191
192
193
194
      tmp=(void *)malloc16(sizeof(int32_t)*(samples_per_frame + 32));
      memset(tmp,0,sizeof(int32_t)*(samples_per_frame + 32));
      rx_buffer_eNB[i]=( tmp + (32*sizeof(int32_t)) );  
      LOG_D(RRH,"i=%d rx_buffer_eNB[i]=%p tmp= %p\n",i,rx_buffer_eNB[i],tmp);
195
196
    }
    /* tx_buffer_eNB points to the beginning of data */
197
    for (i=0; i<dev->eth_dev.openair0_cfg->tx_num_channels; i++) {
navid's avatar
navid committed
198
199
200
201
      tmp=(void *)malloc16(sizeof(int32_t)*(samples_per_frame + 32));
      memset(tmp,0,sizeof(int32_t)*(samples_per_frame + 32));
      tx_buffer_eNB[i]=( tmp + (32*sizeof(int32_t)) );  
      LOG_D(RRH,"i= %d tx_buffer_eNB[i]=%p tmp= %p \n",i,tx_buffer_eNB[i],tmp);
202
203
    }
    /* dummy initialization for TX/RX buffers */
204
    for (i=0; i<dev->eth_dev.openair0_cfg->rx_num_channels; i++) {
205
206
207
208
      for (j=0; j<samples_per_frame; j++) {
	rx_buffer_eNB[i][j]=32+i; 
      } 
    }
209
    /* dummy initialization for TX/RX buffers */
210
    for (i=0; i<dev->eth_dev.openair0_cfg->tx_num_channels; i++) {
211
212
213
      for (j=0; j<samples_per_frame; j++) {
	tx_buffer_eNB[i][j]=12+i; 
      } 
navid's avatar
navid committed
214
215
    }    
    /* allocate TX/RX buffers pointers used in write/read operations */
216
217
    rx_eNB = (void**)malloc16(dev->eth_dev.openair0_cfg->rx_num_channels*sizeof(int32_t*));
    tx_eNB = (void**)malloc16(dev->eth_dev.openair0_cfg->tx_num_channels*sizeof(int32_t*));
navid's avatar
navid committed
218
219

    /* init mutexes */    
220
    for (i=0; i<dev->eth_dev.openair0_cfg->tx_num_channels; i++) {
navid's avatar
navid committed
221
222
223
224
225
226
227
      pthread_mutex_init(&sync_eNB_mutex[i],NULL);
      pthread_cond_init(&sync_eNB_cond[i],NULL);
    }
    /* init mutexes */    
    pthread_mutex_init(&sync_trx_mutex,NULL);

    /* create eNB module's TX/RX threads */    
laurent's avatar
laurent committed
228
#ifdef DEADLINE_SCHEDULER
229
    error_code_eNB_rx = pthread_create(&eNB_rx_thread, NULL, rrh_eNB_rx_thread, (void *)dev);
navid's avatar
navid committed
230
    error_code_eNB_tx = pthread_create(&eNB_tx_thread, NULL, rrh_eNB_tx_thread, (void *)dev);
231
    LOG_I(RRH,"[eNB][SCHED] deadline scheduling applied to eNB TX/RX threads\n");	
232
233
234
#else
    pthread_attr_t	attr_eNB_rx, attr_eNB_tx;
    struct sched_param 	sched_param_eNB_rx, sched_param_eNB_tx;
navid's avatar
navid committed
235

236
237
238
239
240
241
242
243
244
245
246
    pthread_attr_init(&attr_eNB_rx);
    pthread_attr_init(&attr_eNB_tx);	
    sched_param_eNB_rx.sched_priority = sched_get_priority_max(SCHED_FIFO);
    sched_param_eNB_tx.sched_priority = sched_get_priority_max(SCHED_FIFO);
    pthread_attr_setschedparam(&attr_eNB_rx,&sched_param_eNB_rx);
    pthread_attr_setschedparam(&attr_eNB_tx,&sched_param_eNB_tx);
    pthread_attr_setschedpolicy(&attr_eNB_rx,SCHED_FIFO);
    pthread_attr_setschedpolicy(&attr_eNB_tx,SCHED_FIFO);
    
    error_code_eNB_rx = pthread_create(&eNB_rx_thread, &attr_eNB_rx, rrh_eNB_rx_thread, (void *)dev);
    error_code_eNB_tx = pthread_create(&eNB_tx_thread, &attr_eNB_tx, rrh_eNB_tx_thread, (void *)dev);
247
    LOG_I(RRH,"[eNB][SCHED] FIFO scheduling applied to eNB TX/RX threads\n");		
248
249
250
251
252
253
254
255
256
257
#endif

    if (error_code_eNB_rx) {
      LOG_E(RRH,"[eNB] Error while creating eNB RX thread\n");
      exit(-1);
    }
    if (error_code_eNB_tx) {
      LOG_E(RRH,"[eNB] Error while creating eNB TX thread\n");
      exit(-1);
    }
navid's avatar
navid committed
258
259
   
    /* create timer thread; when no RF device is present a software clock is generated */    
260
    if (dev->devs->type == NONE_DEV) {
261

navid's avatar
navid committed
262
263
264
265
266
267
268
269
270
271
272
273
274
275
      int 			error_code_timer;
      pthread_t 		main_timer_proc_thread;
      
      LOG_I(RRH,"Creating timer thread with rt period  %d ns.\n",rt_period);
      
      /* setup the timer to generate an interrupt:
	 -for the first time in (sample_per_packet/sample_rate) ns
	 -and then every (sample_per_packet/sample_rate) ns */
      timerspec.it_value.tv_sec =     rt_period/1000000000;
      timerspec.it_value.tv_nsec =    rt_period%1000000000;
      timerspec.it_interval.tv_sec =  rt_period/1000000000;
      timerspec.it_interval.tv_nsec = rt_period%1000000000;
      
      
laurent's avatar
laurent committed
276
#ifdef DEADLINE_SCHEDULER
navid's avatar
navid committed
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
      error_code_timer = pthread_create(&main_timer_proc_thread, NULL, timer_proc, (void *)&timerspec);
      LOG_I(RRH,"[eNB][SCHED] deadline scheduling applied to timer thread \n");
#else 
      pthread_attr_t attr_timer;
      struct sched_param sched_param_timer;
      
      pthread_attr_init(&attr_timer);
      sched_param_timer.sched_priority = sched_get_priority_max(SCHED_FIFO-1);
      pthread_attr_setschedparam(&attr_timer,&sched_param_timer);
      pthread_attr_setschedpolicy(&attr_timer,SCHED_FIFO-1);
      
      pthread_mutex_init(&timer_mutex,NULL);
      
      error_code_timer = pthread_create(&main_timer_proc_thread, &attr_timer, timer_proc, (void *)&timerspec);
      LOG_I(RRH,"[eNB][SCHED] FIFO scheduling applied to timer thread \n");   	
#endif	
      
      if (error_code_timer) {
	LOG_E(RRH,"Error while creating timer proc thread\n");
	exit(-1);
      }
      
    }
    
301
302
303
304
    while (rrh_exit==0)
      sleep(1);
    
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TRX,0 );
navid's avatar
navid committed
305
306
  }  
  
307
308
309
310
311
  rrh_eNB_thread_status = 0;
  pthread_exit(&rrh_eNB_thread_status);
  return(0);
}

312
/* Receive from RF and transmit to RRH */
313

navid's avatar
navid committed
314
void *rrh_eNB_rx_thread(void *arg) {
315

316
  /* measurement related vars */
317
318
319
320
321
322
323
  struct timespec time0,time1,time2;
  unsigned long long max_rx_time=0, min_rx_time=rt_period, total_rx_time=0, average_rx_time=rt_period, s_period=0, trial=0;
  int trace_cnt=0;

  struct timespec time_req_1us, time_rem_1us;
  rrh_module_t *dev = (rrh_module_t *)arg;
  ssize_t bytes_sent;
navid's avatar
navid committed
324
325
326
  int i=0 ,pck_rx=0, s_cnt=0;
  openair0_timestamp last_hw_counter=0;  //volatile int64_t
  unsigned int samples_per_frame=0,samples_per_subframe=0, spp_rf=0, spp_eth=0;
327
  uint8_t loopback=0,measurements=0;
navid's avatar
navid committed
328
329
  unsigned int subframe=0;
  unsigned int frame=0;
330
331
332

  time_req_1us.tv_sec = 0;
  time_req_1us.tv_nsec =1000;  //time_req_1us.tv_nsec = (int)rt_period/2;--->granularity issue
333
334
  spp_eth =  dev->eth_dev.openair0_cfg->samples_per_packet;
  spp_rf  =  dev->devs->openair0_cfg->samples_per_packet;
navid's avatar
navid committed
335

336
  samples_per_frame = dev->eth_dev.openair0_cfg->samples_per_frame;
navid's avatar
navid committed
337
  samples_per_subframe = (unsigned int)samples_per_frame/10;
338
339
  loopback = dev->loopback;
  measurements = dev->measurements;
navid's avatar
navid committed
340
  next_rx_pos = spp_eth;
341

laurent's avatar
laurent committed
342
#ifdef DEADLINE_SCHEDULER
343
344
345
346
347
348
349
350
351
  struct sched_attr attr;
  unsigned int flags = 0;

  attr.size = sizeof(attr);
  attr.sched_flags = 0;
  attr.sched_nice = 0;
  attr.sched_priority = 0;

  attr.sched_policy   = SCHED_DEADLINE;
navid's avatar
navid committed
352
353
354
355
  attr.sched_runtime  = (0.8 * 100) * 10000;//4 * 10000;
  attr.sched_deadline = (0.9 * 100) * 10000;//rt_period-2000;
  attr.sched_period   = 1 * 1000000;//rt_period;
  
356
357
358
359
360
361
  if (sched_setattr(0, &attr, flags) < 0 ) {
    perror("[SCHED] eNB RX thread: sched_setattr failed (run with sudo)\n");
    exit(-1);
  }
#endif

navid's avatar
navid committed
362
363
  while (rrh_exit == 0) {    
    while (rx_pos <(1 + subframe)*samples_per_subframe) {
364
      //LOG_D(RRH,"starting a new send:%d  %d\n",sync_trx,frame);
navid's avatar
navid committed
365
366
367
368
369
370
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_RX, 1 );
      VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_HW_FRAME_RX, frame);
      VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_HW_SUBFRAME_RX, subframe );  
      VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_PCK, pck_rx );
      LOG_D(RRH,"pack=%d    rx_pos=%d    subframe=%d frame=%d\n ",pck_rx, rx_pos, subframe,frame);
      
371
      if (dev->devs->type == NONE_DEV) {	
navid's avatar
navid committed
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
	VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_HWCNT, hw_counter );
	VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_LHWCNT, last_hw_counter );
	VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_CNT, s_cnt );
	if (!eNB_rx_started) {
	  eNB_rx_started=1; // set this flag to 1 to indicate that eNB started
	  if (RT_flag_eNB==1) {
	    last_hw_counter=hw_counter;//get current counter
	  }
	} else {
	  if (RT_flag_eNB==1) {
	    if (hw_counter > last_hw_counter+1) {
	      printf("LR");
	    } else {
	      while ((hw_counter < last_hw_counter+1)) {
		VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_RX_SLEEP, 1 );
		nanosleep(&time_req_1us,&time_rem_1us);	//rt_sleep_ns(sleep_ns);
		s_cnt++;	
		VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_RX_SLEEP, 0 );
	      } 
	    }
392
393
394
395
396
	  }
	}
      }
      

navid's avatar
navid committed
397
398
      if (measurements == 1 ) clock_gettime(CLOCK_MONOTONIC,&time1);      
    
399
400
401
402
      if (loopback == 1 ) {
	if (sync_eNB_rx[i]==0) {
	  rx_eNB[i] = (void*)&tx_buffer_eNB[i][tx_pos];
	  LOG_I(RRH,"tx_buffer_eNB[i][tx_pos]=%d ,tx_pos=%d\n",tx_buffer_eNB[i][tx_pos],tx_pos);			
navid's avatar
navid committed
403
	} else {
404
405
406
	  rx_eNB[i] = (void*)&rx_buffer_eNB[i][rx_pos];
	  LOG_I(RRH,"rx_buffer_eNB[i][rx_pos]=%d ,rx_pos=%d\n",rx_buffer_eNB[i][rx_pos],rx_pos);	
	}
navid's avatar
navid committed
407
408
       }
       
409
       for (i=0; i<dev->eth_dev.openair0_cfg->rx_num_channels; i++) {
navid's avatar
navid committed
410
411
412
413
	 rx_eNB[i] = (void*)&rx_buffer_eNB[i][rx_pos];
	 LOG_D(RRH," rx_eNB[i]=%p rx_buffer_eNB[i][rx_pos]=%p ,rx_pos=%d, i=%d ts=%d\n",rx_eNB[i],&rx_buffer_eNB[i][rx_pos],rx_pos,i,timestamp_rx);	 
       }  
       VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RXCNT, rx_pos );
414
       if (dev->devs->type != NONE_DEV) {
navid's avatar
navid committed
415
416
417
418
419
420
	 VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_RF, 1 ); 
	 /* Read operation to RF device (RX)*/
	 if ( dev->devs->trx_read_func (dev->devs,
					&timestamp_rx,
					rx_eNB,
					spp_rf,
421
					dev->devs->openair0_cfg->rx_num_channels
navid's avatar
navid committed
422
423
424
425
426
427
428
429
430
431
432
433
					)<0) {
	   perror("RRH eNB : USRP read");
	 }
	 VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_RF, 0 );	
       }
       VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_TS, timestamp_rx&0xffffffff );

       VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 ); 
       if ((bytes_sent = dev->eth_dev.trx_write_func (&dev->eth_dev,
						      timestamp_rx,
						      rx_eNB,
						      spp_eth,
434
						      dev->eth_dev.openair0_cfg->rx_num_channels,
navid's avatar
navid committed
435
436
437
438
439
440
						      0))<0) {
	 perror("RRH eNB : ETHERNET write");
       }    
       VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 );

       /* when there is no RF timestamp is updated by number of samples */
441
       if (dev->devs->type == NONE_DEV) {
navid's avatar
navid committed
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
	 timestamp_rx+=spp_eth;
	 last_hw_counter=hw_counter;
       }
       
       if (measurements == 1 ) {

	 clock_gettime(CLOCK_MONOTONIC,&time2);
	 
	 if (trace_cnt++ > 10) {
	   total_rx_time = (unsigned int)(time2.tv_nsec - time0.tv_nsec);
	   if (total_rx_time < 0)
	     total_rx_time=1000000000-total_rx_time;
	   
	   if ((total_rx_time > 0) && (total_rx_time < 1000000000)) {
	     trial++;
	     if (total_rx_time < min_rx_time)
	       min_rx_time = total_rx_time;
	     if (total_rx_time > max_rx_time){
	       max_rx_time = total_rx_time;
	       LOG_I(RRH,"Max value %d update at rx_position %d \n",total_rx_time,timestamp_rx);
	     }
	     average_rx_time = (long long unsigned int)((average_rx_time*trial)+total_rx_time)/(trial+1);
	   }
	   if (s_period++ == PRINTF_PERIOD) {
	     s_period=0;
467
	     LOG_I(RRH,"Average eNB RX time : %lu ns\tMax RX time : %lu ns\tMin RXX time : %lu ns\n",average_rx_time,max_rx_time,min_rx_time);
navid's avatar
navid committed
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
	   }
	 }
	 
	 memcpy(&time0,&time2,sizeof(struct timespec));
       }
       
       if (loopback == 1 ) {
	 pthread_mutex_lock(&sync_eNB_mutex[i]);
	 sync_eNB_rx[i]--;
	 pthread_mutex_unlock(&sync_eNB_mutex[i]);
       }
       
       rx_pos += spp_eth;    
       pck_rx++;
       next_rx_pos=(rx_pos+spp_eth);
       
       VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_RX, 0 );
485
       /*
navid's avatar
navid committed
486
487
488
489
490
491
492
493
494
       if (frame>50) {
	 pthread_mutex_lock(&sync_trx_mutex);
	 while (sync_trx) {
	   pthread_cond_wait(&sync_trx_cond,&sync_trx_mutex);
	 }
	 sync_trx=1;
	 LOG_D(RRH,"out of while send:%d  %d\n",sync_trx,frame);
	 pthread_cond_signal(&sync_trx_cond);
	 pthread_mutex_unlock(&sync_trx_mutex);
495
	 }*/
navid's avatar
navid committed
496
    } // while 
497
    
navid's avatar
navid committed
498
499
    subframe++;
    s_cnt=0;
500
    
navid's avatar
navid committed
501
    /* wrap around rx buffer index */
502
503
504
505
    if (next_rx_pos >= samples_per_frame)
      next_rx_pos -= samples_per_frame;  
    if (rx_pos >= samples_per_frame)
      rx_pos -= samples_per_frame;
navid's avatar
navid committed
506
507
508
509
510
511
512
    /* wrap around subframe number */       
    if (subframe == 10 ) {
      subframe = 0; 
      frame++;
    }   
   
    
513
  }  //while (eNB_exit==0)
navid's avatar
navid committed
514
  return 0;
515
516
}

517
/* Receive from eNB and transmit to RF */
518

navid's avatar
navid committed
519
void *rrh_eNB_tx_thread(void *arg) {
520
521
522
523
524
525

  struct timespec time0a,time0,time1,time2;

  rrh_module_t *dev = (rrh_module_t *)arg;
  struct timespec time_req_1us, time_rem_1us;
  ssize_t bytes_received;
navid's avatar
navid committed
526
  int i;
527
  openair0_timestamp last_hw_counter=0;
navid's avatar
navid committed
528
529
  unsigned int samples_per_frame=0,samples_per_subframe=0;
  unsigned int  spp_rf=0, spp_eth=0;
530
  uint8_t loopback=0,measurements=0;
navid's avatar
navid committed
531
532
533
  unsigned int subframe=0,frame=0;
  unsigned int pck_tx=0;
  
laurent's avatar
laurent committed
534
#ifdef DEADLINE_SCHEDULER
535
536
  struct sched_attr attr;
  unsigned int flags = 0;
navid's avatar
navid committed
537
  
538
539
540
541
  attr.size = sizeof(attr);
  attr.sched_flags = 0;
  attr.sched_nice = 0;
  attr.sched_priority = 0;
navid's avatar
navid committed
542
  
543
  attr.sched_policy   = SCHED_DEADLINE;
navid's avatar
navid committed
544
545
546
547
  attr.sched_runtime  = (0.8 * 100) * 10000;
  attr.sched_deadline = (0.9 * 100) * 10000;
  attr.sched_period   = 1 * 1000000;
  
548
549
550
551
552
  if (sched_setattr(0, &attr, flags) < 0 ) {
    perror("[SCHED] eNB TX thread: sched_setattr failed\n");
    exit(-1);
  }
#endif	
navid's avatar
navid committed
553
554
555
  
  time_req_1us.tv_sec = 1;
  time_req_1us.tv_nsec = 0;
556
557
558
  spp_eth = dev->eth_dev.openair0_cfg->samples_per_packet;
  spp_rf =  dev->devs->openair0_cfg->samples_per_packet;
  samples_per_frame = dev->eth_dev.openair0_cfg->samples_per_frame;
navid's avatar
navid committed
559
560
  samples_per_subframe = (unsigned int)samples_per_frame/10;
  tx_pos=0;
561

562
563
564
  loopback = dev->loopback;
  measurements = dev->measurements;
  
navid's avatar
navid committed
565
566
567
  while (rrh_exit == 0) {     
    while (tx_pos < (1 + subframe)*samples_per_subframe) {
      
568
569
      //LOG_D(RRH,"bef lock read:%d  %d\n",sync_trx,frame);
      //pthread_mutex_lock(&sync_trx_mutex);
navid's avatar
navid committed
570
      
571
572
573
574
575
      //while (!sync_trx) {
      //LOG_D(RRH,"in sync read:%d  %d\n",sync_trx,frame);
      //pthread_cond_wait(&sync_trx_cond,&sync_trx_mutex);
      //}
      //LOG_D(RRH,"out of while read:%d  %d\n",sync_trx,frame);
navid's avatar
navid committed
576
577
578
579
580
      
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TX, 1 );
      VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_HW_FRAME, frame);
      VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_HW_SUBFRAME, subframe );
      VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TX_PCK, pck_tx );
581
          
navid's avatar
navid committed
582
      if (measurements == 1 ) 	clock_gettime(CLOCK_MONOTONIC,&time1); 
583
      for (i=0; i<dev->eth_dev.openair0_cfg->tx_num_channels; i++) tx_eNB[i] = (void*)&tx_buffer_eNB[i][tx_pos];		
navid's avatar
navid committed
584
      
585
586
      VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TXCNT, tx_pos );
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 );
navid's avatar
navid committed
587
588
589
590
591
592
      
      /* Read operation to ETHERNET device */
      if (( bytes_received = dev->eth_dev.trx_read_func(&dev->eth_dev,
							&timestamp_tx,
							tx_eNB,
							spp_eth,
593
							dev->eth_dev.openair0_cfg->tx_num_channels))<0) {
navid's avatar
navid committed
594
595
	perror("RRH eNB : ETHERNET read");
      }		
596
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );	
navid's avatar
navid committed
597
      
598
      if (dev->devs->type != NONE_DEV) {  
navid's avatar
navid committed
599
600
601
602
603
604
605
	LOG_D(RRH," tx_buffer_eNB[i][tx_pos]=%x t_buffer_eNB[i][tx_pos+1]=%x t_buffer_eNB[i][tx_pos+2]=%x \n",tx_buffer_eNB[0][tx_pos],tx_buffer_eNB[0][tx_pos+1],tx_buffer_eNB[0][tx_pos+2]);	 
	VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_RF, 1 );    
	/* Write operation to RF device (TX)*/
	if ( dev->devs->trx_write_func (dev->devs,
					timestamp_tx,
					tx_eNB,
					spp_rf,
606
					dev->devs->openair0_cfg->tx_num_channels,
607
					1)<0){
navid's avatar
navid committed
608
609
610
	  perror("RRH eNB : USRP write");
	}
	VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_RF, 0 );
611
612
      }
      
navid's avatar
navid committed
613
614
615
      VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TX_TS, timestamp_tx&0xffffffff ); 
      
            
616
      if (dev->devs->type == NONE_DEV)	last_hw_counter=hw_counter;
navid's avatar
navid committed
617
618
    
    
619
620
621
622
623
624
625
      if (loopback ==1 ) { 
	while (sync_eNB_rx[i]==0)
	  nanosleep(&time_req_1us,&time_rem_1us);
	
	pthread_mutex_lock(&sync_eNB_mutex[i]);
	sync_eNB_rx[i]++;
	pthread_mutex_unlock(&sync_eNB_mutex[i]);
navid's avatar
navid committed
626
      }      
627
      
navid's avatar
navid committed
628
629
630
631
632
633
634
635
636
      if (measurements == 1 ) {
	clock_gettime(CLOCK_MONOTONIC,&time2);
	memcpy(&time0,&time2,sizeof(struct timespec));
      }   
      
      prev_tx_pos=tx_pos;
      tx_pos += spp_eth;
      pck_tx++;   
      
637
638
639
640
      //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TX, 0 );
      //sync_trx=0;
      //pthread_cond_signal(&sync_trx_cond);
      //pthread_mutex_unlock(&sync_trx_mutex);
641
642
    }

navid's avatar
navid committed
643
644
645
646
647
648
649
650
651
652
653
654
    /* wrap around tx buffer index */
    if (tx_pos >= samples_per_frame)
      tx_pos -= samples_per_frame;    
    /* wrap around subframe number */ 
    subframe++;
    if (subframe == 10 ) {
      subframe = 0; // the radio frame is complete, start over
      frame++;
    }
    
  } //while (eNB_exit==0)   
  return 0;
655
656
}

navid's avatar
navid committed
657

658
static void calc_rt_period_ns( openair0_config_t *openair0_cfg) {
659

660
  rt_period= (double)(openair0_cfg->samples_per_packet/(openair0_cfg->samples_per_frame/10.0)*1000000);
661
  AssertFatal(rt_period > 0, "Invalid rt period !%u\n", rt_period);
navid's avatar
navid committed
662
  LOG_I(RRH,"[eNB] Real time period is set to %u ns\n", rt_period);	
663
664
665
}


navid's avatar
navid committed
666
static void check_dev_config( rrh_module_t *mod_enb) {
667
    
668
669
670
671
672
673
674
675
676
677
678
679
680
 AssertFatal( (mod_enb->devs->openair0_cfg->num_rb_dl==100 || mod_enb->devs->openair0_cfg->num_rb_dl==50 || mod_enb->devs->openair0_cfg->num_rb_dl==25 || mod_enb->devs->openair0_cfg->num_rb_dl==6) , "Invalid number of resource blocks! %d\n", mod_enb->devs->openair0_cfg->num_rb_dl);
 AssertFatal( mod_enb->devs->openair0_cfg->samples_per_frame  > 0 ,  "Invalid number of samples per frame! %d\n",mod_enb->devs->openair0_cfg->samples_per_frame); 
 AssertFatal( mod_enb->devs->openair0_cfg->sample_rate        > 0.0, "Invalid sample rate! %f\n", mod_enb->devs->openair0_cfg->sample_rate);
 AssertFatal( mod_enb->devs->openair0_cfg->samples_per_packet > 0 ,  "Invalid number of samples per packet! %d\n",mod_enb->devs->openair0_cfg->samples_per_packet);
 AssertFatal( mod_enb->devs->openair0_cfg->rx_num_channels    > 0 ,  "Invalid number of RX antennas! %d\n", mod_enb->devs->openair0_cfg->rx_num_channels); 
 AssertFatal( mod_enb->devs->openair0_cfg->tx_num_channels    > 0 ,  "Invalid number of TX antennas! %d\n", mod_enb->devs->openair0_cfg->tx_num_channels);
 AssertFatal( mod_enb->devs->openair0_cfg->rx_freq[0]         > 0.0 ,"Invalid RX frequency! %f\n", mod_enb->devs->openair0_cfg->rx_freq[0]); 
 AssertFatal( mod_enb->devs->openair0_cfg->tx_freq[0]         > 0.0 ,"Invalid TX frequency! %f\n", mod_enb->devs->openair0_cfg->tx_freq[0]);
 AssertFatal( mod_enb->devs->openair0_cfg->rx_gain[0]         > 0.0 ,"Invalid RX gain! %f\n", mod_enb->devs->openair0_cfg->rx_gain[0]); 
 AssertFatal( mod_enb->devs->openair0_cfg->tx_gain[0]         > 0.0 ,"Invalid TX gain! %f\n", mod_enb->devs->openair0_cfg->tx_gain[0]);
 AssertFatal( mod_enb->devs->openair0_cfg->rx_bw              > 0.0 ,"Invalid RX bw! %f\n", mod_enb->devs->openair0_cfg->rx_bw); 
 AssertFatal( mod_enb->devs->openair0_cfg->tx_bw              > 0.0 ,"Invalid RX bw! %f\n", mod_enb->devs->openair0_cfg->tx_bw);
 AssertFatal( mod_enb->devs->openair0_cfg->autocal[0]         > 0 ,  "Invalid auto calibration choice! %d\n", mod_enb->devs->openair0_cfg->autocal[0]);
681
682
683
 
 printf("\n---------------------RF device configuration parameters---------------------\n");
 
Sandeep Kumar's avatar
Sandeep Kumar committed
684
 printf("\tMod_id=%d\n \tlog level=%d\n \tDL_RB=%d\n \tsamples_per_frame=%d\n \tsample_rate=%f\n \tsamples_per_packet=%d\n \ttx_sample_advance=%d\n \trx_num_channels=%d\n \ttx_num_channels=%d\n \trx_freq_0=%f\n \ttx_freq_0=%f\n \trx_freq_1=%f\n \ttx_freq_1=%f\n \trx_freq_2=%f\n \ttx_freq_2=%f\n \trx_freq_3=%f\n \ttx_freq_3=%f\n \trxg_mode=%d\n \trx_gain_0=%f\n \ttx_gain_0=%f\n  \trx_gain_1=%f\n \ttx_gain_1=%f\n  \trx_gain_2=%f\n \ttx_gain_2=%f\n  \trx_gain_3=%f\n \ttx_gain_3=%f\n \trx_gain_offset_2=%f\n \ttx_gain_offset_3=%f\n  \trx_bw=%f\n \ttx_bw=%f\n \tautocal=%d\n",	
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
	mod_enb->devs->openair0_cfg->Mod_id,
	mod_enb->devs->openair0_cfg->log_level,
	mod_enb->devs->openair0_cfg->num_rb_dl,
	mod_enb->devs->openair0_cfg->samples_per_frame,
	mod_enb->devs->openair0_cfg->sample_rate,
	mod_enb->devs->openair0_cfg->samples_per_packet,
	mod_enb->devs->openair0_cfg->tx_sample_advance,
	mod_enb->devs->openair0_cfg->rx_num_channels,
	mod_enb->devs->openair0_cfg->tx_num_channels,
	mod_enb->devs->openair0_cfg->rx_freq[0],
	mod_enb->devs->openair0_cfg->tx_freq[0],
	mod_enb->devs->openair0_cfg->rx_freq[1],
	mod_enb->devs->openair0_cfg->tx_freq[1],
	mod_enb->devs->openair0_cfg->rx_freq[2],
	mod_enb->devs->openair0_cfg->tx_freq[2],
	mod_enb->devs->openair0_cfg->rx_freq[3],
	mod_enb->devs->openair0_cfg->tx_freq[3],
	mod_enb->devs->openair0_cfg->rxg_mode[0],
	mod_enb->devs->openair0_cfg->tx_gain[0],
	mod_enb->devs->openair0_cfg->tx_gain[0],
	mod_enb->devs->openair0_cfg->rx_gain[1],
	mod_enb->devs->openair0_cfg->tx_gain[1],
	mod_enb->devs->openair0_cfg->rx_gain[2],
	mod_enb->devs->openair0_cfg->tx_gain[2],
	mod_enb->devs->openair0_cfg->rx_gain[3],
	mod_enb->devs->openair0_cfg->tx_gain[3],
	//mod_enb->devs->openair0_cfg->rx_gain_offset[0],
	//mod_enb->devs->openair0_cfg->rx_gain_offset[1],
	mod_enb->devs->openair0_cfg->rx_gain_offset[2],
	mod_enb->devs->openair0_cfg->rx_gain_offset[3],
	mod_enb->devs->openair0_cfg->rx_bw,
	mod_enb->devs->openair0_cfg->tx_bw,
	mod_enb->devs->openair0_cfg->autocal[0]  
718
719
720
721
722
	);
 
 printf("----------------------------------------------------------------------------\n");
 
 
723
}