eNB_transport_IQ.c 27.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The OpenAirInterface Software Alliance licenses this file to You under
 * the OAI Public License, Version 1.0  (the "License"); you may not use this file
 * except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.openairinterface.org/?page_id=698
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *-------------------------------------------------------------------------------
 * For more information about the OpenAirInterface (OAI) Software Alliance:
 *      contact@openairinterface.org
 */

22
/*! \file eNB_transport_IQ.c
navid's avatar
navid committed
23
 * \brief eNB transport IQ samples 
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
 * \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)

49 50
pthread_cond_t          sync_eNB_cond[4];
pthread_mutex_t         sync_eNB_mutex[4];
navid's avatar
navid committed
51 52 53
pthread_mutex_t         sync_trx_mutex=PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t          sync_trx_cond=PTHREAD_COND_INITIALIZER;

54
openair0_timestamp 	nrt_eNB_counter[4]= {0,0,0,0};
55 56 57 58 59 60 61
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
62 63 64 65 66
int 	        sync_eNB_rx[4]= {-1,-1,-1,-1};
unsigned int    sync_trx=0;

int32_t		**tx_buffer_eNB;
int32_t         **rx_buffer_eNB;
67 68 69
void 		**rx_eNB; //was fixed to 2 ant
void 		**tx_eNB; //was fixed to 2 ant

navid's avatar
navid committed
70 71 72
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;
73

navid's avatar
navid committed
74 75 76
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;
77

navid's avatar
navid committed
78 79
struct itimerspec       timerspec;
pthread_mutex_t         timer_mutex;
80

navid's avatar
navid committed
81 82 83


/*! \fn void *rrh_eNB_rx_thread(void *arg)
84 85
 * \brief this function
 * \param[in]
navid's avatar
navid committed
86 87 88 89 90 91 92 93 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
 * \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
119 120 121
 * \note
 * @ingroup  _oai
 */
122
static void calc_rt_period_ns( openair0_config_t *openair0_cfg);
navid's avatar
navid committed
123 124 125 126



void config_BBU_mod( rrh_module_t *mod_enb, uint8_t RT_flag, uint8_t NRT_flag) {
127
  
navid's avatar
navid committed
128 129 130 131
  int 	             error_code_eNB;
  pthread_t	     main_rrh_eNB_thread;
  pthread_attr_t     attr;
  struct sched_param sched_param_rrh;
132
  
133 134
  RT_flag_eNB=RT_flag;
  NRT_flag_eNB=NRT_flag;
135
  
136
  /* init socket and have handshake-like msg with client to exchange parameters */
137
  mod_enb->eth_dev.trx_start_func(&mod_enb->eth_dev);//change port  make it plus_id
navid's avatar
navid committed
138

139 140
  mod_enb->devs->openair0_cfg = mod_enb->eth_dev.openair0_cfg;

141
  /* check sanity of configuration parameters and print */
Aikaterini Trilyraki's avatar
Aikaterini Trilyraki committed
142 143 144 145 146
  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;
147 148 149 150
  /* 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
151
  } else {   
152 153 154 155 156
    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
157

158 159 160 161
	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
162
      }
163
      
164
    }
165
  }  
166
  
navid's avatar
navid committed
167 168 169 170 171 172 173 174
  /* 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);
175
  error_code_eNB = pthread_create(&main_rrh_eNB_thread, &attr, rrh_eNB_thread, (void *)mod_enb);
navid's avatar
navid committed
176

177
  if (error_code_eNB) {
178
    LOG_E(RRH,"Error while creating eNB thread\n");
179 180
    exit(-1);
  }
181
  
182 183
}

navid's avatar
navid committed
184 185 186

void *rrh_eNB_thread(void *arg) {

187 188 189
  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;
190
  int32_t	        i,j;   		
191 192 193
  void 			*tmp;
  unsigned int          samples_per_frame=0;
  
194
  samples_per_frame = dev->eth_dev.openair0_cfg->samples_per_frame;    
navid's avatar
navid committed
195

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

    /* init mutexes */    
241
    for (i=0; i<dev->eth_dev.openair0_cfg->tx_num_channels; i++) {
navid's avatar
navid committed
242 243 244 245 246 247 248
      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
249
#ifdef DEADLINE_SCHEDULER
250
    error_code_eNB_rx = pthread_create(&eNB_rx_thread, NULL, rrh_eNB_rx_thread, (void *)dev);
navid's avatar
navid committed
251
    error_code_eNB_tx = pthread_create(&eNB_tx_thread, NULL, rrh_eNB_tx_thread, (void *)dev);
252
    LOG_I(RRH,"[eNB][SCHED] deadline scheduling applied to eNB TX/RX threads\n");	
253 254 255
#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
256

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

navid's avatar
navid committed
283 284 285 286 287 288 289 290 291 292 293 294 295 296
      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
297
#ifdef DEADLINE_SCHEDULER
navid's avatar
navid committed
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
      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);
      }
      
    }
    
322 323 324 325
    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
326 327
  }  
  
328 329 330 331 332
  rrh_eNB_thread_status = 0;
  pthread_exit(&rrh_eNB_thread_status);
  return(0);
}

333
/* Receive from RF and transmit to RRH */
334

navid's avatar
navid committed
335
void *rrh_eNB_rx_thread(void *arg) {
336

337
  /* measurement related vars */
338 339 340 341 342 343 344
  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
345 346 347
  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;
348
  uint8_t loopback=0,measurements=0;
navid's avatar
navid committed
349 350
  unsigned int subframe=0;
  unsigned int frame=0;
351 352 353

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

357
  samples_per_frame = dev->eth_dev.openair0_cfg->samples_per_frame;
navid's avatar
navid committed
358
  samples_per_subframe = (unsigned int)samples_per_frame/10;
359 360
  loopback = dev->loopback;
  measurements = dev->measurements;
navid's avatar
navid committed
361
  next_rx_pos = spp_eth;
362

laurent's avatar
laurent committed
363
#ifdef DEADLINE_SCHEDULER
364 365 366 367 368 369 370 371 372
  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
373 374 375 376
  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;
  
377 378 379 380 381 382
  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
383 384
  while (rrh_exit == 0) {    
    while (rx_pos <(1 + subframe)*samples_per_subframe) {
385
      //LOG_D(RRH,"starting a new send:%d  %d\n",sync_trx,frame);
navid's avatar
navid committed
386 387 388 389 390 391
      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);
      
392
      if (dev->devs->type == NONE_DEV) {	
navid's avatar
navid committed
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
	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 );
	      } 
	    }
413 414 415 416 417
	  }
	}
      }
      

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

538
/* Receive from eNB and transmit to RF */
539

navid's avatar
navid committed
540
void *rrh_eNB_tx_thread(void *arg) {
541 542 543 544 545 546

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

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

navid's avatar
navid committed
664 665 666 667 668 669 670 671 672 673 674 675
    /* 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;
676 677
}

navid's avatar
navid committed
678

679
static void calc_rt_period_ns( openair0_config_t *openair0_cfg) {
680

681
  rt_period= (double)(openair0_cfg->samples_per_packet/(openair0_cfg->samples_per_frame/10.0)*1000000);
682
  AssertFatal(rt_period > 0, "Invalid rt period !%u\n", rt_period);
navid's avatar
navid committed
683
  LOG_I(RRH,"[eNB] Real time period is set to %u ns\n", rt_period);	
684 685 686
}


navid's avatar
navid committed
687
static void check_dev_config( rrh_module_t *mod_enb) {
688
    
689 690 691 692 693 694 695 696 697 698 699 700 701
 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]);
702 703 704
 
 printf("\n---------------------RF device configuration parameters---------------------\n");
 
Sandeep Kumar's avatar
Sandeep Kumar committed
705
 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",	
706 707 708 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
	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]  
739 740 741 742 743
	);
 
 printf("----------------------------------------------------------------------------\n");
 
 
744
}