eNB_transport_IQ.c 27.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*******************************************************************************
    OpenAirInterface
    Copyright(c) 1999 - 2014 Eurecom

    OpenAirInterface is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.


    OpenAirInterface is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with OpenAirInterface.The full GNU General Public License is
    included in this distribution in the file called "COPYING". If not,
    see <http://www.gnu.org/licenses/>.

   Contact Information
   OpenAirInterface Admin: openair_admin@eurecom.fr
   OpenAirInterface Tech : openair_tech@eurecom.fr
24
   OpenAirInterface Dev  : openair4g-devel@lists.eurecom.fr
25 26 27 28 29 30

   Address      : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE

 *******************************************************************************/

/*! \file eNB_transport_IQ.c
31
 * \brief eNB transport IQ samples 
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
 * \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)

57 58
pthread_cond_t          sync_eNB_cond[4];
pthread_mutex_t         sync_eNB_mutex[4];
59 60 61
pthread_mutex_t         sync_trx_mutex=PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t          sync_trx_cond=PTHREAD_COND_INITIALIZER;

62
openair0_timestamp 	nrt_eNB_counter[4]= {0,0,0,0};
63 64 65 66 67 68 69
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;
70 71 72 73 74
int 	        sync_eNB_rx[4]= {-1,-1,-1,-1};
unsigned int    sync_trx=0;

int32_t		**tx_buffer_eNB;
int32_t         **rx_buffer_eNB;
75 76 77
void 		**rx_eNB; //was fixed to 2 ant
void 		**tx_eNB; //was fixed to 2 ant

78 79 80
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;
81

82 83 84
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;
85

86 87
struct itimerspec       timerspec;
pthread_mutex_t         timer_mutex;
88

89 90 91


/*! \fn void *rrh_eNB_rx_thread(void *arg)
92 93
 * \brief this function
 * \param[in]
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
 * \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
127 128 129
 * \note
 * @ingroup  _oai
 */
130
static void calc_rt_period_ns( openair0_config_t *openair0_cfg);
131 132 133 134



void config_BBU_mod( rrh_module_t *mod_enb, uint8_t RT_flag, uint8_t NRT_flag) {
135
  
136 137 138 139
  int 	             error_code_eNB;
  pthread_t	     main_rrh_eNB_thread;
  pthread_attr_t     attr;
  struct sched_param sched_param_rrh;
140
  
141 142
  RT_flag_eNB=RT_flag;
  NRT_flag_eNB=NRT_flag;
143
  
144
  /* init socket and have handshake-like msg with client to exchange parameters */
145
  mod_enb->eth_dev.trx_start_func(&mod_enb->eth_dev);//change port  make it plus_id
146

147 148
  mod_enb->devs->openair0_cfg = mod_enb->eth_dev.openair0_cfg;

149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
  /* check sanity of configuration parameters and print */
  check_dev_config(mod_enb);    
  
  /* 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);
  } else {
    if (mod_enb->devs->type != NONE_DEV) {
      /* start RF device */
      if (mod_enb->devs->type == EXMIMO_DEV) {
	//call start function for exmino
      } else {
	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");
166
      }
167
      
168
    }
169
  }  
170
  
171 172 173 174 175 176 177 178
  /* 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);
179
  error_code_eNB = pthread_create(&main_rrh_eNB_thread, &attr, rrh_eNB_thread, (void *)mod_enb);
180

181
  if (error_code_eNB) {
182
    LOG_E(RRH,"Error while creating eNB thread\n");
183 184
    exit(-1);
  }
185
  
186 187
}

188 189 190

void *rrh_eNB_thread(void *arg) {

191 192 193
  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;
194
  int32_t	        i,j;   		
195 196 197
  void 			*tmp;
  unsigned int          samples_per_frame=0;
  
198
  samples_per_frame = dev->eth_dev.openair0_cfg->samples_per_frame;    
199

200 201
  while (rrh_exit==0) {
    
202
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TRX, 1 );    
203
    
204 205 206
    /* calculate packet period */
    calc_rt_period_ns(dev->eth_dev.openair0_cfg);
        
207 208
    /* allocate memory for TX/RX buffers
       each antenna port has a TX and a RX buffer
209
       each TX and RX buffer is of (samples_per_frame + HEADER_SIZE) samples (size of samples is 4 bytes) */
210 211
    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*));    
212
    LOG_D(RRH,"rx_buffer_eNB address =%p tx_buffer_eNB address =%p  \n",rx_buffer_eNB,tx_buffer_eNB);
213
    
214
    /* rx_buffer_eNB points to the beginning of data */
215
    for (i=0; i<dev->eth_dev.openair0_cfg->rx_num_channels; i++) {
216 217 218 219
      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);
220 221
    }
    /* tx_buffer_eNB points to the beginning of data */
222
    for (i=0; i<dev->eth_dev.openair0_cfg->tx_num_channels; i++) {
223 224 225 226
      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);
227 228
    }
    /* dummy initialization for TX/RX buffers */
229
    for (i=0; i<dev->eth_dev.openair0_cfg->rx_num_channels; i++) {
230 231 232 233
      for (j=0; j<samples_per_frame; j++) {
	rx_buffer_eNB[i][j]=32+i; 
      } 
    }
234
    /* dummy initialization for TX/RX buffers */
235
    for (i=0; i<dev->eth_dev.openair0_cfg->tx_num_channels; i++) {
236 237 238
      for (j=0; j<samples_per_frame; j++) {
	tx_buffer_eNB[i][j]=12+i; 
      } 
239 240
    }    
    /* allocate TX/RX buffers pointers used in write/read operations */
241 242
    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*));
243 244

    /* init mutexes */    
245
    for (i=0; i<dev->eth_dev.openair0_cfg->tx_num_channels; i++) {
246 247 248 249 250 251 252
      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 */    
253 254
#ifdef LOWLATENCY
    error_code_eNB_rx = pthread_create(&eNB_rx_thread, NULL, rrh_eNB_rx_thread, (void *)dev);
255
    error_code_eNB_tx = pthread_create(&eNB_tx_thread, NULL, rrh_eNB_tx_thread, (void *)dev);
256
    LOG_I(RRH,"[eNB][SCHED] deadline scheduling applied to eNB TX/RX threads\n");	
257 258 259
#else
    pthread_attr_t	attr_eNB_rx, attr_eNB_tx;
    struct sched_param 	sched_param_eNB_rx, sched_param_eNB_tx;
260

261 262 263 264 265 266 267 268 269 270 271
    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);
272
    LOG_I(RRH,"[eNB][SCHED] FIFO scheduling applied to eNB TX/RX threads\n");		
273 274 275 276 277 278 279 280 281 282
#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);
    }
283 284
   
    /* create timer thread; when no RF device is present a software clock is generated */    
285
    if (dev->devs->type == NONE_DEV) {
286

287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
      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;
      
      
#ifdef LOWLATENCY
      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);
      }
      
    }
    
326 327 328 329
    while (rrh_exit==0)
      sleep(1);
    
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_TRX,0 );
330 331
  }  
  
332 333 334 335 336
  rrh_eNB_thread_status = 0;
  pthread_exit(&rrh_eNB_thread_status);
  return(0);
}

337
/* Receive from RF and transmit to RRH */
338

339
void *rrh_eNB_rx_thread(void *arg) {
340

341
  /* measurement related vars */
342 343 344 345 346 347 348
  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;
349 350 351
  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;
352
  uint8_t loopback=0,measurements=0;
353 354
  unsigned int subframe=0;
  unsigned int frame=0;
355 356 357

  time_req_1us.tv_sec = 0;
  time_req_1us.tv_nsec =1000;  //time_req_1us.tv_nsec = (int)rt_period/2;--->granularity issue
358 359
  spp_eth =  dev->eth_dev.openair0_cfg->samples_per_packet;
  spp_rf  =  dev->devs->openair0_cfg->samples_per_packet;
360

361
  samples_per_frame = dev->eth_dev.openair0_cfg->samples_per_frame;
362
  samples_per_subframe = (unsigned int)samples_per_frame/10;
363 364
  loopback = dev->loopback;
  measurements = dev->measurements;
365
  next_rx_pos = spp_eth;
366 367 368 369 370 371 372 373 374 375 376

#ifdef LOWLATENCY
  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;
377 378 379 380
  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;
  
381 382 383 384 385 386
  if (sched_setattr(0, &attr, flags) < 0 ) {
    perror("[SCHED] eNB RX thread: sched_setattr failed (run with sudo)\n");
    exit(-1);
  }
#endif

387 388
  while (rrh_exit == 0) {    
    while (rx_pos <(1 + subframe)*samples_per_subframe) {
389
      //LOG_D(RRH,"starting a new send:%d  %d\n",sync_trx,frame);
390 391 392 393 394 395
      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);
      
396
      if (dev->devs->type == NONE_DEV) {	
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
	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 );
	      } 
	    }
417 418 419 420 421
	  }
	}
      }
      

422 423
      if (measurements == 1 ) clock_gettime(CLOCK_MONOTONIC,&time1);      
    
424 425 426 427
      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);			
428
	} else {
429 430 431
	  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);	
	}
432 433
       }
       
434
       for (i=0; i<dev->eth_dev.openair0_cfg->rx_num_channels; i++) {
435 436 437 438
	 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 );
439
       if (dev->devs->type != NONE_DEV) {
440 441 442 443 444 445
	 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,
446
					dev->devs->openair0_cfg->rx_num_channels
447 448 449 450 451 452 453 454 455 456 457 458
					)<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,
459
						      dev->eth_dev.openair0_cfg->rx_num_channels,
460 461 462 463 464 465
						      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 */
466
       if (dev->devs->type == NONE_DEV) {
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
	 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;
492
	     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);
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509
	   }
	 }
	 
	 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 );
510
       /*
511 512 513 514 515 516 517 518 519
       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);
520
	 }*/
521
    } // while 
522
    
523 524
    subframe++;
    s_cnt=0;
525
    
526
    /* wrap around rx buffer index */
527 528 529 530
    if (next_rx_pos >= samples_per_frame)
      next_rx_pos -= samples_per_frame;  
    if (rx_pos >= samples_per_frame)
      rx_pos -= samples_per_frame;
531 532 533 534 535 536 537
    /* wrap around subframe number */       
    if (subframe == 10 ) {
      subframe = 0; 
      frame++;
    }   
   
    
538
  }  //while (eNB_exit==0)
539
  return 0;
540 541
}

542
/* Receive from eNB and transmit to RF */
543

544
void *rrh_eNB_tx_thread(void *arg) {
545 546 547 548 549 550

  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;
551
  int i;
552
  openair0_timestamp last_hw_counter=0;
553 554
  unsigned int samples_per_frame=0,samples_per_subframe=0;
  unsigned int  spp_rf=0, spp_eth=0;
555
  uint8_t loopback=0,measurements=0;
556 557 558
  unsigned int subframe=0,frame=0;
  unsigned int pck_tx=0;
  
559 560 561
#ifdef LOWLATENCY
  struct sched_attr attr;
  unsigned int flags = 0;
562
  
563 564 565 566
  attr.size = sizeof(attr);
  attr.sched_flags = 0;
  attr.sched_nice = 0;
  attr.sched_priority = 0;
567
  
568
  attr.sched_policy   = SCHED_DEADLINE;
569 570 571 572
  attr.sched_runtime  = (0.8 * 100) * 10000;
  attr.sched_deadline = (0.9 * 100) * 10000;
  attr.sched_period   = 1 * 1000000;
  
573 574 575 576 577
  if (sched_setattr(0, &attr, flags) < 0 ) {
    perror("[SCHED] eNB TX thread: sched_setattr failed\n");
    exit(-1);
  }
#endif	
578 579 580
  
  time_req_1us.tv_sec = 1;
  time_req_1us.tv_nsec = 0;
581 582 583
  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;
584 585
  samples_per_subframe = (unsigned int)samples_per_frame/10;
  tx_pos=0;
586

587 588 589
  loopback = dev->loopback;
  measurements = dev->measurements;
  
590 591 592
  while (rrh_exit == 0) {     
    while (tx_pos < (1 + subframe)*samples_per_subframe) {
      
593 594
      //LOG_D(RRH,"bef lock read:%d  %d\n",sync_trx,frame);
      //pthread_mutex_lock(&sync_trx_mutex);
595
      
596 597 598 599 600
      //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);
601 602 603 604 605
      
      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 );
606
          
607
      if (measurements == 1 ) 	clock_gettime(CLOCK_MONOTONIC,&time1); 
608
      for (i=0; i<dev->eth_dev.openair0_cfg->tx_num_channels; i++) tx_eNB[i] = (void*)&tx_buffer_eNB[i][tx_pos];		
609
      
610 611
      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 );
612 613 614 615 616 617
      
      /* Read operation to ETHERNET device */
      if (( bytes_received = dev->eth_dev.trx_read_func(&dev->eth_dev,
							&timestamp_tx,
							tx_eNB,
							spp_eth,
618
							dev->eth_dev.openair0_cfg->tx_num_channels))<0) {
619 620
	perror("RRH eNB : ETHERNET read");
      }		
621
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );	
622
      
623
      if (dev->devs->type != NONE_DEV) {  
624 625 626 627 628 629 630
	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,
631
					dev->devs->openair0_cfg->tx_num_channels,
632
					1)<0){
633 634 635
	  perror("RRH eNB : USRP write");
	}
	VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_RF, 0 );
636 637
      }
      
638 639 640
      VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TX_TS, timestamp_tx&0xffffffff ); 
      
            
641
      if (dev->devs->type == NONE_DEV)	last_hw_counter=hw_counter;
642 643
    
    
644 645 646 647 648 649 650
      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]);
651
      }      
652
      
653 654 655 656 657 658 659 660 661
      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++;   
      
662 663 664 665
      //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);
666 667
    }

668 669 670 671 672 673 674 675 676 677 678 679
    /* 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;
680 681
}

682

683
static void calc_rt_period_ns( openair0_config_t *openair0_cfg) {
684

685
  rt_period= (double)(openair0_cfg->samples_per_packet/(openair0_cfg->samples_per_frame/10.0)*1000000);
686
  AssertFatal(rt_period > 0, "Invalid rt period !%u\n", rt_period);
687
  LOG_I(RRH,"[eNB] Real time period is set to %u ns\n", rt_period);	
688 689 690
}


691
static void check_dev_config( rrh_module_t *mod_enb) {
692
    
693 694 695 696 697 698 699 700 701 702 703 704 705
 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]);
706 707 708
 
 printf("\n---------------------RF device configuration parameters---------------------\n");
 
709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743
 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_scheduling_advance=%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",	
	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_scheduling_advance,
	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]  
744 745 746 747 748
	);
 
 printf("----------------------------------------------------------------------------\n");
 
 
749
}