rrh_gw.c 12 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 24

/*******************************************************************************
    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
25
   OpenAirInterface Dev  : openair4g-devel@lists.eurecom.fr
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55

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

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

/*! \file rrh_gw.h
 * \brief top-level for the remote radio head gateway (RRH_gw) module reusing the ethernet library 
 * \author Navid Nikaein,  Katerina Trilyraki, Raymond Knopp
 * \date 2015
 * \version 0.1
 * \company Eurecom
 * \maintainer:  navid.nikaein@eurecom.fr
 * \note
 * \warning very experimental 
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <execinfo.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <time.h>

#include "common_lib.h"
#include "rrh_gw.h" // change to rrh_new.h, put externs in rrh_extern.h
#include "rt_wrapper.h"
56
#include "rrh_gw_externs.h" // change to rrh_new.h, put externs in rrh_extern.h
57 58 59 60 61 62


#include "log_if.h"
#include "log_extern.h"
#include "vcd_signal_dumper.h"

63 64 65 66 67 68 69 70 71 72
/*****************************************************************************************
 *                                                                        ----------     *
 *     -------    RRH_BBU_IF    -------    RRH_RF_IF     -------USRP      - COTS_UE-     *
 *     - BBU - ---------------  - RRH -  -------------   -------BLADERF   ----------     *
 *     -------                  -------                  -------EXMIMO                   *
 *                                                                        ---------      *
 *                                                       -------ETH_IF    - EMU_UE-      *
 *                                                                        ---------      *                              
 *****************************************************************************************/

73 74


75
char rrh_ip[20] = "192.168.12.242"; // there is code to detect the my ip address
76 77 78 79 80 81 82 83 84 85 86 87 88 89
int  rrh_port = 50000; // has to be an option

/* log */
int16_t           glog_level          = LOG_DEBUG;
int16_t           glog_verbosity      = LOG_MED;
int16_t           rrh_log_level       = LOG_INFO;
int16_t           rrh_log_verbosity   = LOG_MED;
int16_t           enb_log_level       = LOG_INFO;
int16_t           enb_log_verbosity   = LOG_MED;
int16_t           ue_log_level        = LOG_INFO;
int16_t           ue_log_verbosity    = LOG_MED;


/* flags definitions */
90 91 92 93 94 95 96 97
uint8_t 	eNB_flag=0;
uint8_t 	UE_flag=0;
uint8_t 	EXMIMO_flag=0;
uint8_t 	USRP_flag=0;
uint8_t 	RT_flag=0, NRT_flag=1;
uint8_t 	rrh_exit=0;
uint8_t         loopback_flag=0;
uint8_t         measurements_flag=0;
98 99

/* Default operation as RRH:
100
   - there are neither eNB nor UE modules
101 102
   - no RF hardware is specified (NONE_IF)
   - default ethernet interface is local */
103 104 105 106 107
uint8_t 	    num_eNB_mod=0;
uint8_t 	    num_UE_mod=0;
uint8_t 	    num_EXMIMO_mod=0;
uint8_t 	    num_USRP_mod=0;
uint8_t             hardware_target=NONE_IF;
108
char*               if_name="lo";
109

110 111 112
rrh_module_t 	        *enb_array;
rrh_module_t            *ue_array;

113 114 115 116
openair0_vtimestamp 	hw_counter=0;



117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145

static void debug_init(void);
static void get_options(int argc, char *argv[]);
static void print_help(void);

/*!\fn static rrh_module_t new_module(unsigned int id);
* \brief creation of a eNB/UE module
* \param[in] module id
* \return module
* \note
* @ingroup  _oai
*/
static rrh_module_t new_module(unsigned int id);

/*!\fn static int get_ip_address(char* if_name)
 * \brief retrieves IP address from the specified network interface
 * \param[in] name of network interface
 * \return 0 
 * \note
 * @ingroup  _oai
 */
static int get_ip_address(char* if_name);





int main(int argc, char **argv) {
  
146 147 148 149 150 151
  unsigned int i;
  
  /* parse input arguments */
  get_options(argc, argv);
  /* initialize logger and signal analyzer */
  debug_init();
152
  /* */
153
  set_latency_target();
154
  /* make a graceful exit when ctrl-c is pressed */
155 156
  signal(SIGSEGV, signal_handler);
  signal(SIGINT, signal_handler);
157
  
158
  /* create modules based on input arguments */
159
  if (eNB_flag==1){    
160
    enb_array=(rrh_module_t*)malloc(num_eNB_mod*sizeof(rrh_module_t));	
161 162
    for(i=0;i<num_eNB_mod;i++){  
      enb_array[i]=new_module(i);//enb_array[i]=new_module(i, get_RF_interfaces(&hardware_target));	
163
      config_BBU_mod(&enb_array[i],RT_flag,NRT_flag);
164
      LOG_I(RRH,"[eNB %d] module(s) created (out of %u) \n",i,num_eNB_mod);		
165 166
    }
  }
167
  if (UE_flag==1){    
168 169
    ue_array=(rrh_module_t*)malloc(num_UE_mod*sizeof(rrh_module_t));	
    for(i=0;i<num_UE_mod;i++){
170
      ue_array[i]=new_module(i);
171
      config_UE_mod(&ue_array[i],RT_flag,NRT_flag);			
172
      LOG_I(RRH,"[UE %d] module(s) created (out of %u)\n",i, num_UE_mod);
173 174
    }
  }
175
 
176 177 178 179 180 181 182 183 184
  printf("TYPE <CTRL-C> TO TERMINATE\n");
  
  while (rrh_exit==0)
    sleep(1);

  return EXIT_SUCCESS;
}


185
static rrh_module_t new_module (unsigned int id) {
186 187 188

  rrh_module_t 	  	rrh_mod;
  openair0_config_t 	openair0_cfg;
189

190 191 192
  rrh_mod.id=id;
  rrh_mod.loopback=loopback_flag;
  rrh_mod.measurements=measurements_flag;
193

194 195
  /* each module is associated with an ethernet device */
  rrh_mod.eth_dev.type=ETH_IF;
196
  /* ethernet device is functioning within RRH */
197
  rrh_mod.eth_dev.func_type=RRH_FUNC; 
198
  /* specify IP address */
199
  get_ip_address(if_name);
200 201 202
  openair0_cfg.my_ip=&rrh_ip[0];
  openair0_cfg.my_port=rrh_port;

203
  /* ethernet device initialization */
204 205 206 207
  if (openair0_dev_init_eth(&rrh_mod.eth_dev, &openair0_cfg)<0){
    LOG_E(RRH,"Exiting, cannot initialize ethernet interface.\n");
    exit(-1);
  }
208 209

  /* allocate space and specify associated RF device */
210 211 212 213 214 215 216 217 218
  openair0_device *oai_dv = (openair0_device *)malloc(sizeof(openair0_device));
  memset(oai_dv,0, sizeof(openair0_device));

#ifdef EXMIMO
  rrh_mod.devs=oai_dv;   
  rrh_mod.devs->type=EXMIMO_IF;
  LOG_I(RRH,"Setting RF device to EXMIMO\n");	   
#elif OAI_USRP
  rrh_mod.devs=oai_dv;	
219
  rrh_mod.devs->type=USRP_B200_IF;
220 221 222 223 224 225 226 227 228 229
  LOG_I(RRH,"Setting RF device to USRP\n");    	 
#elif OAI_BLADERF
  rrh_mod.devs=oai_dv;	
  rrh_mod.devs->type=BLADERF_IF;
  LOG_I(RRH,"Setting RF device to BLADERF\n");
#else
  rrh_mod.devs=oai_dv;
  rrh_mod.devs->type=NONE_IF;
  LOG_I(RRH,"Setting RF interface to NONE_IF... \n");
#endif  
230 231 232 233 234
  
  return rrh_mod;
}

static void debug_init(void) {
235
  
236 237 238 239 240 241 242 243 244 245
  // log initialization
  logInit();
  set_glog(glog_level,  glog_verbosity);
  
  set_comp_log(RRH,     rrh_log_level,   rrh_log_verbosity, 1);
  //set_comp_log(ENB_LOG, enb_log_level,   enb_log_verbosity, 1);
  //set_comp_log(UE_LOG,  ue_log_level,    ue_log_verbosity,  1);
  
  // vcd initialization
  if (ouput_vcd) {
246
    vcd_signal_dumper_init("/tmp/openair_dump_rrh.vcd");
247
    
248
  }
249
}
250

251

252 253 254 255
static void get_options(int argc, char *argv[]) {

  int 	opt;

256
  while ((opt = getopt(argc, argv, "xvhlte:n:u:g:r:w:i:")) != -1) {
257 258 259 260 261 262 263 264 265 266 267 268 269
    
    switch (opt) {
    case 'n':
      eNB_flag=1;
      num_eNB_mod=atoi(optarg);
      break;
    case 'u':
      UE_flag=1;
      num_UE_mod=atoi(optarg);
      break;
    case 'g':
      glog_level=atoi(optarg);
      break;
270 271 272 273 274 275
    case 'i':  
      if (optarg) {
	if_name=strdup(optarg); 
	printf("RRH interface name is set to %s\n", if_name);	
      }
      break;
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
    case 'r':
      //rrh_log_level=atoi(optarg);
      break;
    case 'e':
      //enb_log_level=atoi(optarg);
      break;
    case 'x':
      rt_period = DEFAULT_PERIOD_NS;
      RT_flag=1;
      NRT_flag=0;
      break;
    case 'v':
      /* extern from vcd */
      ouput_vcd=1;  
      break;
    case 'l':
      /*In loopback mode rrh sends back to bbu what it receives*/
      loopback_flag=1; 
      break;
    case 't':
      /*When measurements are enabled statistics related to TX/RX time are printed*/
      measurements_flag=1; 
      break;
    case 'w':
300 301
      /* force to use this target*/    
      hardware_target=1;
302
      break;
303 304 305
  case 'h':
    print_help();
    exit(-1);
306 307 308 309 310 311
    default: /* '?' */
      //fprintf(stderr, "Usage: \n", argv[0]);
      exit(-1);
  }
}

312 313
}

314
static int get_ip_address(char* if_name) {
315 316 317 318
  
  int fd;
  struct ifreq ifr;
  
319
  
320 321 322 323
  fd = socket(AF_INET, SOCK_DGRAM, 0);
  
  /* I want to get an IPv4 IP address */
  ifr.ifr_addr.sa_family = AF_INET;
324 325
  
  /* I want IP address attached to "if_name" */
326
  strncpy(ifr.ifr_name, if_name, IFNAMSIZ-1);
327 328 329 330 331 332 333 334 335 336 337
  
  if ( ioctl(fd, SIOCGIFADDR, &ifr)<0 ) {
    perror("IOCTL:");
    exit(-1);
  } 
  
  close(fd);
  
  /* display result */
  snprintf(&rrh_ip[0],20,"%s", inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
  LOG_I(RRH,"Got IP address %s from interface %s\n", rrh_ip,if_name);
338

339
  return 0;
340
}
341

342

343 344 345 346 347 348 349 350
static void print_help(void) {

  puts("Usage: \n");
  puts("     sudo -E chrt 99 ./rrh -n1 -g6 -v -t");
  puts("Options:\n");
  puts("\t -n create eNB module\n");
  puts("\t -u create UE module\n");
  puts("\t -g define global log level\n");
351
  puts("\t -i set the RRH interface (default lo)\n");
352 353 354 355 356 357 358 359 360 361 362
  puts("\t -r define rrh log level\n");
  puts("\t -e define eNB log level\n");
  puts("\t -x enable real time bahaviour\n");
  puts("\t -v enable vcd dump\n");
  puts("\t -l enable loopback mode\n");
  puts("\t -t enable measurements\n");
  puts("\t -w force to use specified HW\n");
  puts("\t -h display info\n");

}

363

364
void *timer_proc(void *arg) {
365

366 367 368
  timer_t             timerid;    
  struct itimerspec   *timer= (struct itimerspec *)arg ; // the timer data structure
  struct itimerspec   *old_value;
369

370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
  
#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;
  attr.sched_runtime  =  (0.1  *  100) * 10000; // 
  attr.sched_deadline =  rt_period-30000;//(0.1  *  100) * 10000; 
  attr.sched_period   =  rt_period;//(0.1  *  100) * 10000; // each TX/RX thread has, as a function of RT PERIOD ?? 
  
  if (sched_setattr(0, &attr, flags) < 0 ) {
    perror("[SCHED] timer thread: sched_setattr failed\n");
    exit(-1);
  }
#endif  
  
 if (timer_create (CLOCK_REALTIME, NULL, &timerid) == -1) {
    fprintf (stderr, "couldn't create a timer\n");
    perror (NULL);
    exit (EXIT_FAILURE);
  }
  
  signal(SIGALRM, timer_signal_handler);
  LOG_I(RRH,"Timer has started!\n");
  timer_settime (timerid, 0, timer, old_value);
400

401 402 403 404 405 406 407
  while (!rrh_exit) {
    sleep(1);
  }
  
  timer_delete(timerid);
  
  return (0);
408 409 410
}


411
void timer_signal_handler(int sig) {
412
  
413 414 415 416 417 418 419
  if (sig == SIGALRM) {
    pthread_mutex_lock(&timer_mutex);
    hw_counter ++;
    pthread_mutex_unlock(&timer_mutex);
     VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_CNT, hw_counter);//USED ELSEWHERE
  }
}
420

421 422

void signal_handler(int sig) {
423
  
424 425
  void *array[10];
  size_t size;
426
  
427 428 429 430 431 432 433
  if (sig==SIGSEGV) {
    // get void*'s for all entries on the stack
    size = backtrace(array, 10);
    
    // print out all the frames to stderr
    fprintf(stderr, "Error: signal %d:\n", sig);
    backtrace_symbols_fd(array, size, 2);
434
    exit(-1);
435 436 437
  } else {
    printf("trying to exit gracefully...\n");
    rrh_exit = 1;
438 439
  }
}
440 441 442 443 444 445 446 447 448 449

void exit_fun(const char* s) {
  if (s != NULL) {
    printf("%s %s() Exiting RRH: %s\n",__FILE__, __FUNCTION__, s);
  }
  rrh_exit = 1;
  exit (-1);
}