lte-softmodem.c 35.5 KB
Newer Older
1 2 3 4 5
/*
 * 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
6
 * the OAI Public License, Version 1.1  (the "License"); you may not use this file
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 * 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 23
/*! \file lte-enb.c
 * \brief Top-level threads for eNodeB
24
 * \author R. Knopp, F. Kaltenberger, Navid Nikaein
knopp's avatar
knopp committed
25 26 27
 * \date 2012
 * \version 0.1
 * \company Eurecom
28
 * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr, navid.nikaein@eurecom.fr
knopp's avatar
knopp committed
29 30 31
 * \note
 * \warning
 */
32

33

Cedric Roux's avatar
Cedric Roux committed
34 35 36
#define _GNU_SOURCE             /* See feature_test_macros(7) */
#include <sched.h>

37

38 39
#include "T.h"

40
#include "rt_wrapper.h"
41

42

43 44
#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all

45
#include "assertions.h"
46
#include "msc.h"
47 48

#include "PHY/types.h"
49

50
#include "PHY/defs.h"
51
#include "common/ran_context.h"
52
#include "common/config/config_userapi.h"
oai's avatar
oai committed
53
#include "common/utils/load_module_shlib.h"
54
#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all
knopp's avatar
knopp committed
55
//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all
56

knopp's avatar
knopp committed
57
#include "../../ARCH/COMMON/common_lib.h"
58
#include "../../ARCH/ETHERNET/USERSPACE/LIB/if_defs.h"
knopp's avatar
knopp committed
59

knopp's avatar
knopp committed
60
//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all
61 62 63 64 65 66 67 68 69

#include "PHY/vars.h"
#include "SCHED/vars.h"
#include "LAYER2/MAC/vars.h"

#include "../../SIMU/USER/init_lte.h"

#include "LAYER2/MAC/defs.h"
#include "LAYER2/MAC/vars.h"
70
#include "LAYER2/MAC/proto.h"
71 72 73 74 75 76 77 78
#include "RRC/LITE/vars.h"
#include "PHY_INTERFACE/vars.h"

#ifdef SMBV
#include "PHY/TOOLS/smbv.h"
unsigned short config_frames[4] = {2,9,11,13};
#endif
#include "UTIL/LOG/log_extern.h"
nikaeinn's avatar
nikaeinn committed
79
#include "UTIL/OTG/otg_tx.h"
80
#include "UTIL/OTG/otg_externs.h"
81 82
#include "UTIL/MATH/oml.h"
#include "UTIL/LOG/vcd_signal_dumper.h"
83
#include "UTIL/OPT/opt.h"
84
#include "enb_config.h"
nikaeinn's avatar
nikaeinn committed
85
//#include "PHY/TOOLS/time_meas.h"
86

Florian Kaltenberger's avatar
Florian Kaltenberger committed
87 88 89 90
#ifndef OPENAIR2
#include "UTIL/OTG/otg_vars.h"
#endif

91
#if defined(ENABLE_ITTI)
92 93
#include "intertask_interface_init.h"
#include "create_tasks.h"
94 95
#endif

96 97
#include "system.h"

98 99 100
#ifdef XFORMS
#include "PHY/TOOLS/lte_phy_scope.h"
#include "stats.h"
101
#endif
102
#include "lte-softmodem.h"
103

104
#ifdef XFORMS
105
// current status is that every UE has a DL scope for a SINGLE eNB (eNB_id=0)
106
// at eNB 0, an UL scope for every UE
107
FD_lte_phy_scope_ue  *form_ue[NUMBER_OF_UE_MAX];
108
FD_lte_phy_scope_enb *form_enb[MAX_NUM_CCs][NUMBER_OF_UE_MAX];
109
FD_stats_form                  *form_stats=NULL,*form_stats_l2=NULL;
110
char title[255];
111
unsigned char                   scope_enb_num_ue = 2;
112
static pthread_t                forms_thread; //xforms
113 114
#endif //XFORMS

115 116 117 118 119 120
pthread_cond_t nfapi_sync_cond;
pthread_mutex_t nfapi_sync_mutex;
int nfapi_sync_var=-1; //!< protected by mutex \ref nfapi_sync_mutex

uint8_t nfapi_mode = 0; // Default to monolithic mode

knopp's avatar
knopp committed
121 122
pthread_cond_t sync_cond;
pthread_mutex_t sync_mutex;
123
int sync_var=-1; //!< protected by mutex \ref sync_mutex.
124
int config_sync_var=-1;
125

126 127
uint16_t runtime_phy_rx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100]
uint16_t runtime_phy_tx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100]
knopp's avatar
knopp committed
128

129
#if defined(ENABLE_ITTI)
130 131
volatile int             start_eNB = 0;
volatile int             start_UE = 0;
132
#endif
knopp's avatar
knopp committed
133
volatile int             oai_exit = 0;
134

135
static clock_source_t clock_source = internal;
136
static int wait_for_sync = 0;
knopp's avatar
knopp committed
137

138
unsigned int                    mmapped_dma=0;
139
int                             single_thread_flag=1;
140

141
static int8_t                     threequarter_fs=0;
142

143
uint32_t                 downlink_frequency[MAX_NUM_CCs][4];
144
int32_t                  uplink_frequency_offset[MAX_NUM_CCs][4];
gauthier's avatar
gauthier committed
145

146

147

148
#if defined(ENABLE_ITTI)
149
static char                    *itti_dump_file = NULL;
knopp's avatar
knopp committed
150 151
#endif

152
int UE_scan = 1;
153
int UE_scan_carrier = 0;
154 155
runmode_t mode = normal_txrx;

156 157
FILE *input_fd=NULL;

158

159 160
#if MAX_NUM_CCs == 1
rx_gain_t                rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain}};
161 162
double tx_gain[MAX_NUM_CCs][4] = {{20,0,0,0}};
double rx_gain[MAX_NUM_CCs][4] = {{110,0,0,0}};
163 164 165 166
#else
rx_gain_t                rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain},{max_gain,max_gain,max_gain,max_gain}};
double tx_gain[MAX_NUM_CCs][4] = {{20,0,0,0},{20,0,0,0}};
double rx_gain[MAX_NUM_CCs][4] = {{110,0,0,0},{20,0,0,0}};
gauthier's avatar
gauthier committed
167
#endif
knopp's avatar
knopp committed
168

169
double rx_gain_off = 0.0;
170

knopp's avatar
knopp committed
171
double sample_rate=30.72e6;
172
double bw = 10.0e6;
173

174
static int                      tx_max_power[MAX_NUM_CCs]; /* =  {0,0}*/;
175

176 177
char   rf_config_file[1024];

Florian Kaltenberger's avatar
Florian Kaltenberger committed
178
int chain_offset=0;
179
int phy_test = 0;
180
uint8_t usim_test = 0;
Florian Kaltenberger's avatar
Florian Kaltenberger committed
181

182 183 184
uint8_t dci_Format = 0;
uint8_t agregation_Level =0xFF;

185 186
uint8_t nb_antenna_tx = 1;
uint8_t nb_antenna_rx = 1;
187

knopp's avatar
knopp committed
188 189 190
char ref[128] = "internal";
char channels[128] = "0";

191
int                      rx_input_level_dBm;
192

193
#ifdef XFORMS
194
extern int                      otg_enabled;
195
static char                     do_forms=0;
196
#else
197
int                             otg_enabled;
198
#endif
knopp's avatar
knopp committed
199
//int                             number_of_cards =   1;
200

201 202

static LTE_DL_FRAME_PARMS      *frame_parms[MAX_NUM_CCs];
Florian Kaltenberger's avatar
Florian Kaltenberger committed
203
uint32_t target_dl_mcs = 28; //maximum allowed mcs
204
uint32_t target_ul_mcs = 20;
205
uint32_t timing_advance = 0;
206 207
uint8_t exit_missed_slots=1;
uint64_t num_missed_slots=0; // counter for the number of missed slots
208

209

210 211
extern void reset_opp_meas(void);
extern void print_opp_meas(void);
212

213 214 215 216 217 218
extern PHY_VARS_UE* init_ue_vars(LTE_DL_FRAME_PARMS *frame_parms,
			  uint8_t UE_id,
			  uint8_t abstraction_flag);

extern void init_eNB_afterRU(void);

219
int transmission_mode=1;
knopp's avatar
knopp committed
220

221

222

223 224 225
/* struct for ethernet specific parameters given in eNB conf file */
eth_params_t *eth_params;

226 227 228 229
openair0_config_t openair0_cfg[MAX_CARDS];

double cpuf;

230 231
extern char uecap_xer[1024];
char uecap_xer_in=0;
232

233
int oaisim_flag=0;
234
threads_t threads= {-1,-1,-1,-1,-1,-1,-1};
knopp's avatar
knopp committed
235

Cedric Roux's avatar
Cedric Roux committed
236 237 238 239
/* see file openair2/LAYER2/MAC/main.c for why abstraction_flag is needed
 * this is very hackish - find a proper solution
 */
uint8_t abstraction_flag=0;
knopp's avatar
knopp committed
240

241 242 243
/* forward declarations */
void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]);

244 245 246 247 248
/*---------------------BMC: timespec helpers -----------------------------*/

struct timespec min_diff_time = { .tv_sec = 0, .tv_nsec = 0 };
struct timespec max_diff_time = { .tv_sec = 0, .tv_nsec = 0 };

249
struct timespec clock_difftime(struct timespec start, struct timespec end) {
250 251 252 253 254 255 256 257 258
  struct timespec temp;
  if ((end.tv_nsec-start.tv_nsec)<0) {
    temp.tv_sec = end.tv_sec-start.tv_sec-1;
    temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
  } else {
    temp.tv_sec = end.tv_sec-start.tv_sec;
    temp.tv_nsec = end.tv_nsec-start.tv_nsec;
  }
  return temp;
259 260
}

261
void print_difftimes(void) {
262
#ifdef DEBUG
263
  printf("difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec);
264
#else
265
  LOG_I(HW,"difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec);
266 267 268
#endif
}

269
void update_difftimes(struct timespec start, struct timespec end) {
270 271 272
  struct timespec diff_time = { .tv_sec = 0, .tv_nsec = 0 };
  int             changed = 0;
  diff_time = clock_difftime(start, end);
273 274 275 276 277 278 279 280
  if ((min_diff_time.tv_nsec == 0) || (diff_time.tv_nsec < min_diff_time.tv_nsec)) {
    min_diff_time.tv_nsec = diff_time.tv_nsec;
    changed = 1;
  }
  if ((max_diff_time.tv_nsec == 0) || (diff_time.tv_nsec > max_diff_time.tv_nsec)) {
    max_diff_time.tv_nsec = diff_time.tv_nsec;
    changed = 1;
  }
281
#if 1
282
  if (changed) print_difftimes();
283 284 285 286 287
#endif
}

/*------------------------------------------------------------------------*/

288
unsigned int build_rflocal(int txi, int txq, int rxi, int rxq) {
knopp's avatar
knopp committed
289
  return (txi + (txq<<6) + (rxi<<12) + (rxq<<18));
290
}
291
unsigned int build_rfdc(int dcoff_i_rxfe, int dcoff_q_rxfe) {
knopp's avatar
knopp committed
292
  return (dcoff_i_rxfe + (dcoff_q_rxfe<<8));
293 294
}

295
#if !defined(ENABLE_ITTI)
296
void signal_handler(int sig) {
297 298 299 300 301 302
  void *array[10];
  size_t size;

  if (sig==SIGSEGV) {
    // get void*'s for all entries on the stack
    size = backtrace(array, 10);
303

304 305 306 307
    // print out all the frames to stderr
    fprintf(stderr, "Error: signal %d:\n", sig);
    backtrace_symbols_fd(array, size, 2);
    exit(-1);
308 309
  } else {
    printf("trying to exit gracefully...\n");
310
    oai_exit = 1;
311 312
  }
}
313
#endif
314 315 316 317 318 319
#define KNRM  "\x1B[0m"
#define KRED  "\x1B[31m"
#define KGRN  "\x1B[32m"
#define KBLU  "\x1B[34m"
#define RESET "\033[0m"

320

Raymond Knopp's avatar
Raymond Knopp committed
321

322 323
void exit_fun(const char* s)
{
324

325
  int ru_id;
Raymond Knopp's avatar
Raymond Knopp committed
326

327
  if (s != NULL) {
328
    printf("%s %s() Exiting OAI softmodem: %s\n",__FILE__, __FUNCTION__, s);
329 330 331
  }

  oai_exit = 1;
332

333 334 335

    if (RC.ru == NULL)
        exit(-1); // likely init not completed, prevent crash or hang, exit now...
336
    for (ru_id=0; ru_id<RC.nb_RU;ru_id++) {
337
      if (RC.ru[ru_id] && RC.ru[ru_id]->rfdevice.trx_end_func)
338
	RC.ru[ru_id]->rfdevice.trx_end_func(&RC.ru[ru_id]->rfdevice);
339
      if (RC.ru[ru_id] && RC.ru[ru_id]->ifdevice.trx_end_func)
340 341
	RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice);  
    }
342

343 344

#if defined(ENABLE_ITTI)
345 346
    sleep(1); //allow lte-softmodem threads to exit first
    itti_terminate_tasks (TASK_UNKNOWN);
347
#endif
348 349


350
}
351

352
#ifdef XFORMS
353

354

355 356
void reset_stats(FL_OBJECT *button, long arg)
{
357
  int i,j,k;
358
  PHY_VARS_eNB *phy_vars_eNB = RC.eNB[0][0];
359 360 361

  for (i=0; i<NUMBER_OF_UE_MAX; i++) {
    for (k=0; k<8; k++) { //harq_processes
362
      for (j=0; j<phy_vars_eNB->dlsch[i][0]->Mlimit; j++) {
363 364 365
	phy_vars_eNB->UE_stats[i].dlsch_NAK[k][j]=0;
	phy_vars_eNB->UE_stats[i].dlsch_ACK[k][j]=0;
	phy_vars_eNB->UE_stats[i].dlsch_trials[k][j]=0;
366
      }
367

368 369 370
      phy_vars_eNB->UE_stats[i].dlsch_l2_errors[k]=0;
      phy_vars_eNB->UE_stats[i].ulsch_errors[k]=0;
      phy_vars_eNB->UE_stats[i].ulsch_consecutive_errors=0;
371 372


373 374 375
      phy_vars_eNB->UE_stats[i].dlsch_sliding_cnt=0;
      phy_vars_eNB->UE_stats[i].dlsch_NAK_round0=0;
      phy_vars_eNB->UE_stats[i].dlsch_mcs_offset=0;
376 377 378 379
    }
  }
}

380
static void *scope_thread(void *arg) {
381
 
382
# ifdef ENABLE_XFORMS_WRITE_STATS
383
  FILE *eNB_stats;
384
# endif
knopp's avatar
knopp committed
385
  struct sched_param sched_param;
386
  int UE_id, CC_id;
387
  int ue_cnt=0;
388

389
  sched_param.sched_priority = sched_get_priority_min(SCHED_FIFO)+1;
knopp's avatar
knopp committed
390
  sched_setscheduler(0, SCHED_FIFO,&sched_param);
391

knopp's avatar
knopp committed
392
  printf("Scope thread has priority %d\n",sched_param.sched_priority);
393

394
# ifdef ENABLE_XFORMS_WRITE_STATS
395

396
  eNB_stats = fopen("eNB_stats.txt", "w");
397

398
#endif
399

knopp's avatar
knopp committed
400
  while (!oai_exit) {
401

402 403
      ue_cnt=0;
      for(UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) {
404
	for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
405
	  if ((ue_cnt<scope_enb_num_ue)) {
gauthier's avatar
gauthier committed
406
	    phy_scope_eNB(form_enb[CC_id][ue_cnt],
407
			  RC.eNB[0][CC_id],
408 409 410
			  UE_id);
	    ue_cnt++;
	  }
411
	}
412
      }	
Florian Kaltenberger's avatar
Florian Kaltenberger committed
413
    sleep(1);
knopp's avatar
knopp committed
414
  }
415

416
  //  printf("%s",stats_buffer);
417

418
# ifdef ENABLE_XFORMS_WRITE_STATS
419

420 421 422 423 424
    if (eNB_stats) {
      rewind (eNB_stats);
      fwrite (stats_buffer, 1, len, eNB_stats);
      fclose (eNB_stats);
    }
425

426
# endif
427

knopp's avatar
knopp committed
428
  pthread_exit((void*)arg);
429 430 431
}
#endif

432

433

434

knopp's avatar
knopp committed
435
#if defined(ENABLE_ITTI)
436
void *l2l1_task(void *arg) {
knopp's avatar
knopp committed
437 438 439 440 441
  MessageDef *message_p = NULL;
  int         result;

  itti_set_task_real_time(TASK_L2L1);
  itti_mark_task_ready(TASK_L2L1);
442

knopp's avatar
knopp committed
443
    /* Wait for the initialize message */
444
    printf("Wait for the ITTI initialize message\n");
445
    do {
knopp's avatar
knopp committed
446
      if (message_p != NULL) {
447 448
	result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p);
	AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
knopp's avatar
knopp committed
449
      }
450

451 452 453
      itti_receive_msg (TASK_L2L1, &message_p);

      switch (ITTI_MSG_ID(message_p)) {
knopp's avatar
knopp committed
454
      case INITIALIZE_MESSAGE:
455 456 457 458
	/* Start eNB thread */
	LOG_D(EMU, "L2L1 TASK received %s\n", ITTI_MSG_NAME(message_p));
	start_eNB = 1;
	break;
knopp's avatar
knopp committed
459 460

      case TERMINATE_MESSAGE:
461 462
	printf("received terminate message\n");
	oai_exit=1;
463
        start_eNB = 0;
464 465
	itti_exit_task ();
	break;
knopp's avatar
knopp committed
466 467

      default:
468 469
	LOG_E(EMU, "Received unexpected message %s\n", ITTI_MSG_NAME(message_p));
	break;
470
      }
knopp's avatar
knopp committed
471
    } while (ITTI_MSG_ID(message_p) != INITIALIZE_MESSAGE);
472

knopp's avatar
knopp committed
473 474
    result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p);
    AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
475
/* ???? no else but seems to be UE only ??? 
knopp's avatar
knopp committed
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
  do {
    // Wait for a message
    itti_receive_msg (TASK_L2L1, &message_p);

    switch (ITTI_MSG_ID(message_p)) {
    case TERMINATE_MESSAGE:
      oai_exit=1;
      itti_exit_task ();
      break;

    case ACTIVATE_MESSAGE:
      start_UE = 1;
      break;

    case DEACTIVATE_MESSAGE:
      start_UE = 0;
      break;
493

knopp's avatar
knopp committed
494 495 496 497 498 499 500 501 502 503 504
    case MESSAGE_TEST:
      LOG_I(EMU, "Received %s\n", ITTI_MSG_NAME(message_p));
      break;

    default:
      LOG_E(EMU, "Received unexpected message %s\n", ITTI_MSG_NAME(message_p));
      break;
    }

    result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p);
    AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
505
  } while(!oai_exit);
506
*/
knopp's avatar
knopp committed
507
  return NULL;
508 509 510
}
#endif

511

512
static void get_options(void) {
513
 
514
  int tddflag, nonbiotflag;
515 516
 
  
517 518
  uint32_t online_log_messages;
  uint32_t glog_level, glog_verbosity;
oai's avatar
oai committed
519
  uint32_t start_telnetsrv;
520

521
  paramdef_t cmdline_params[] =CMDLINE_PARAMS_DESC ;
522
  paramdef_t cmdline_logparams[] =CMDLINE_LOGPARAMS_DESC ;
523 524 525 526 527 528 529 530 531 532 533 534 535

  config_process_cmdline( cmdline_params,sizeof(cmdline_params)/sizeof(paramdef_t),NULL); 

  if (strlen(in_path) > 0) {
      opt_type = OPT_PCAP;
      opt_enabled=1;
      printf("Enabling OPT for PCAP  with the following file %s \n",in_path);
  }
  if (strlen(in_ip) > 0) {
      opt_enabled=1;
      opt_type = OPT_WIRESHARK;
      printf("Enabling OPT for wireshark for local interface");
  }
536 537 538 539 540 541 542 543

  config_process_cmdline( cmdline_logparams,sizeof(cmdline_logparams)/sizeof(paramdef_t),NULL);
  if(config_isparamset(cmdline_logparams,CMDLINE_ONLINELOG_IDX)) {
      set_glog_onlinelog(online_log_messages);
  }
  if(config_isparamset(cmdline_logparams,CMDLINE_GLOGLEVEL_IDX)) {
      set_glog(glog_level, -1);
  }
544
  if(config_isparamset(cmdline_logparams,CMDLINE_GLOGVERBO_IDX)) {
545 546
      set_glog(-1, glog_verbosity);
  }
oai's avatar
oai committed
547
  if (start_telnetsrv) {
548
     load_module_shlib("telnetsrv",NULL,0);
oai's avatar
oai committed
549 550
  }

551 552 553 554 555
#if T_TRACER
  paramdef_t cmdline_ttraceparams[] =CMDLINE_TTRACEPARAMS_DESC ;
  config_process_cmdline( cmdline_ttraceparams,sizeof(cmdline_ttraceparams)/sizeof(paramdef_t),NULL);   
#endif

556 557 558
  if ( !(CONFIG_ISFLAGSET(CONFIG_ABORT)) ) {
      memset((void*)&RC,0,sizeof(RC));
      /* Read RC configuration file */
559
      RCConfig();
560 561
      NB_eNB_INST = RC.nb_inst;
      NB_RU	  = RC.nb_RU;
562
      printf("Configuration: nb_rrc_inst %d, nb_L1_inst %d, nb_ru %d\n",NB_eNB_INST,RC.nb_L1_inst,NB_RU);
563
   }
564 565 566
}


567
#if T_TRACER
568
int T_nowait = 0;     /* by default we wait for the tracer */
569
int T_port = 2021;    /* default port to listen to to wait for the tracer */
570
int T_dont_fork = 0;  /* default is to fork, see 'T_init' to understand */
571 572
#endif

573

574

knopp's avatar
knopp committed
575
void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) {
knopp's avatar
knopp committed
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590

  int CC_id;

  for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
    frame_parms[CC_id] = (LTE_DL_FRAME_PARMS*) malloc(sizeof(LTE_DL_FRAME_PARMS));
    /* Set some default values that may be overwritten while reading options */
    frame_parms[CC_id]->frame_type          = FDD;
    frame_parms[CC_id]->tdd_config          = 3;
    frame_parms[CC_id]->tdd_config_S        = 0;
    frame_parms[CC_id]->N_RB_DL             = 100;
    frame_parms[CC_id]->N_RB_UL             = 100;
    frame_parms[CC_id]->Ncp                 = NORMAL;
    frame_parms[CC_id]->Ncp_UL              = NORMAL;
    frame_parms[CC_id]->Nid_cell            = 0;
    frame_parms[CC_id]->num_MBSFN_config    = 0;
591
    frame_parms[CC_id]->nb_antenna_ports_eNB  = 1;
knopp's avatar
knopp committed
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
    frame_parms[CC_id]->nb_antennas_tx      = 1;
    frame_parms[CC_id]->nb_antennas_rx      = 1;

    frame_parms[CC_id]->nushift             = 0;

    frame_parms[CC_id]->phich_config_common.phich_resource = oneSixth;
    frame_parms[CC_id]->phich_config_common.phich_duration = normal;
    // UL RS Config
    frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift = 0;//n_DMRS1 set to 0
    frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled = 0;
    frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled = 0;
    frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH = 0;

    frame_parms[CC_id]->prach_config_common.rootSequenceIndex=22;
    frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig=1;
    frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_ConfigIndex=0;
    frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.highSpeedFlag=0;
    frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_FreqOffset=0;

611 612 613 614
//    downlink_frequency[CC_id][0] = 2680000000; // Use float to avoid issue with frequency over 2^31.
//    downlink_frequency[CC_id][1] = downlink_frequency[CC_id][0];
//    downlink_frequency[CC_id][2] = downlink_frequency[CC_id][0];
//    downlink_frequency[CC_id][3] = downlink_frequency[CC_id][0];
knopp's avatar
knopp committed
615
    //printf("Downlink for CC_id %d frequency set to %u\n", CC_id, downlink_frequency[CC_id][0]);
616
    frame_parms[CC_id]->dl_CarrierFreq=downlink_frequency[CC_id][0];
oai's avatar
oai committed
617

knopp's avatar
knopp committed
618 619 620 621
  }

}

knopp's avatar
knopp committed
622

623
void init_openair0(void) {
knopp's avatar
knopp committed
624 625 626 627 628 629 630 631 632 633 634 635

  int card;
  int i;

  for (card=0; card<MAX_CARDS; card++) {

    openair0_cfg[card].mmapped_dma=mmapped_dma;
    openair0_cfg[card].configFilename = NULL;

    if(frame_parms[0]->N_RB_DL == 100) {
      if (frame_parms[0]->threequarter_fs) {
	openair0_cfg[card].sample_rate=23.04e6;
636
	openair0_cfg[card].samples_per_frame = 230400;
knopp's avatar
knopp committed
637 638
	openair0_cfg[card].tx_bw = 10e6;
	openair0_cfg[card].rx_bw = 10e6;
639
      } else {
knopp's avatar
knopp committed
640
	openair0_cfg[card].sample_rate=30.72e6;
641
	openair0_cfg[card].samples_per_frame = 307200;
knopp's avatar
knopp committed
642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
	openair0_cfg[card].tx_bw = 10e6;
	openair0_cfg[card].rx_bw = 10e6;
      }
    } else if(frame_parms[0]->N_RB_DL == 50) {
      openair0_cfg[card].sample_rate=15.36e6;
      openair0_cfg[card].samples_per_frame = 153600;
      openair0_cfg[card].tx_bw = 5e6;
      openair0_cfg[card].rx_bw = 5e6;
    } else if (frame_parms[0]->N_RB_DL == 25) {
      openair0_cfg[card].sample_rate=7.68e6;
      openair0_cfg[card].samples_per_frame = 76800;
      openair0_cfg[card].tx_bw = 2.5e6;
      openair0_cfg[card].rx_bw = 2.5e6;
    } else if (frame_parms[0]->N_RB_DL == 6) {
      openair0_cfg[card].sample_rate=1.92e6;
      openair0_cfg[card].samples_per_frame = 19200;
      openair0_cfg[card].tx_bw = 1.5e6;
      openair0_cfg[card].rx_bw = 1.5e6;
    }


    if (frame_parms[0]->frame_type==TDD)
      openair0_cfg[card].duplex_mode = duplex_mode_TDD;
    else //FDD
      openair0_cfg[card].duplex_mode = duplex_mode_FDD;

    printf("HW: Configuring card %d, nb_antennas_tx/rx %d/%d\n",card,
669 670
	   RC.eNB[0][0]->frame_parms.nb_antennas_tx ,
	   RC.eNB[0][0]->frame_parms.nb_antennas_rx );
knopp's avatar
knopp committed
671 672 673
    openair0_cfg[card].Mod_id = 0;

    openair0_cfg[card].num_rb_dl=frame_parms[0]->N_RB_DL;
674

675
    openair0_cfg[card].clock_source = clock_source;
676

677

678 679
    openair0_cfg[card].tx_num_channels=min(2,RC.eNB[0][0]->frame_parms.nb_antennas_tx );
    openair0_cfg[card].rx_num_channels=min(2,RC.eNB[0][0]->frame_parms.nb_antennas_rx );
680

knopp's avatar
knopp committed
681
    for (i=0; i<4; i++) {
682

knopp's avatar
knopp committed
683
      if (i<openair0_cfg[card].tx_num_channels)
684
	openair0_cfg[card].tx_freq[i] = downlink_frequency[0][i] ;
knopp's avatar
knopp committed
685 686
      else
	openair0_cfg[card].tx_freq[i]=0.0;
687

knopp's avatar
knopp committed
688
      if (i<openair0_cfg[card].rx_num_channels)
689
	openair0_cfg[card].rx_freq[i] =downlink_frequency[0][i] + uplink_frequency_offset[0][i] ;
knopp's avatar
knopp committed
690 691 692 693 694
      else
	openair0_cfg[card].rx_freq[i]=0.0;

      openair0_cfg[card].autocal[i] = 1;
      openair0_cfg[card].tx_gain[i] = tx_gain[0][i];
695 696
      openair0_cfg[card].rx_gain[i] = RC.eNB[0][0]->rx_total_gain_dB;

knopp's avatar
knopp committed
697

698
      openair0_cfg[card].configFilename = rf_config_file;
699
      printf("Card %d, channel %d, Setting tx_gain %f, rx_gain %f, tx_freq %f, rx_freq %f\n",
700 701 702 703
	     card,i, openair0_cfg[card].tx_gain[i],
	     openair0_cfg[card].rx_gain[i],
	     openair0_cfg[card].tx_freq[i],
	     openair0_cfg[card].rx_freq[i]);
704
    }
705
  } /* for loop on cards */
knopp's avatar
knopp committed
706
}
707

708

709
void wait_RUs(void) {
710

711
  LOG_I(PHY,"Waiting for RUs to be configured ... RC.ru_mask:%02lx\n", RC.ru_mask);
712 713 714 715 716

  // wait for all RUs to be configured over fronthaul
  pthread_mutex_lock(&RC.ru_mutex);
  while (RC.ru_mask>0) {
    pthread_cond_wait(&RC.ru_cond,&RC.ru_mutex);
717
    printf("RC.ru_mask:%02lx\n", RC.ru_mask);
718
  }
719
  pthread_mutex_unlock(&RC.ru_mutex);
720 721 722 723

  LOG_I(PHY,"RUs configured\n");
}

724
void wait_eNBs(void) {
725 726 727 728 729 730

  int i,j;
  int waiting=1;


  while (waiting==1) {
Cedric Roux's avatar
Cedric Roux committed
731 732
    printf("Waiting for eNB L1 instances to all get configured ... sleeping 50ms (nb_L1_inst %d)\n",RC.nb_L1_inst);
    usleep(50*1000);
733
    waiting=0;
734 735 736 737 738
    for (i=0;i<RC.nb_L1_inst;i++) {

      printf("RC.nb_L1_CC[%d]:%d\n", i, RC.nb_L1_CC[i]);

      for (j=0;j<RC.nb_L1_CC[i];j++) {
739 740 741
	if (RC.eNB[i][j]->configured==0) {
	  waiting=1;
	  break;
742 743 744
        } 
      }
    }
745 746 747
  }
  printf("eNB L1 are configured\n");
}
748

749
#if defined(ENABLE_ITTI)
750 751
/*
 * helper function to terminate a certain ITTI task
752
 */
753
void terminate_task(task_id_t task_id, module_id_t mod_id)
754
{
755 756 757 758 759 760
  LOG_I(ENB_APP, "sending TERMINATE_MESSAGE to task %s (%d)\n", itti_get_task_name(task_id), task_id);
  MessageDef *msg;
  msg = itti_alloc_new_message (ENB_APP, TERMINATE_MESSAGE);
  itti_send_msg_to_task (task_id, ENB_MODULE_ID_TO_INSTANCE(mod_id), msg);
}

761
extern void  free_transport(PHY_VARS_eNB *);
762 763
extern void  phy_free_RU(RU_t*);

764
int stop_L1L2(module_id_t enb_id)
765 766
{
  LOG_W(ENB_APP, "stopping lte-softmodem\n");
767
  oai_exit = 1;
768

769 770 771 772 773 774 775 776 777 778 779 780
  if (!RC.ru) {
    LOG_F(ENB_APP, "no RU configured\n");
    return -1;
  }

  /* stop trx devices, multiple carrier currently not supported by RU */
  if (RC.ru[enb_id]) {
    if (RC.ru[enb_id]->rfdevice.trx_stop_func) {
      RC.ru[enb_id]->rfdevice.trx_stop_func(&RC.ru[enb_id]->rfdevice);
      LOG_I(ENB_APP, "turned off RU rfdevice\n");
    } else {
      LOG_W(ENB_APP, "can not turn off rfdevice due to missing trx_stop_func callback, proceding anyway!\n");
781
    }
782 783 784 785 786
    if (RC.ru[enb_id]->ifdevice.trx_stop_func) {
      RC.ru[enb_id]->ifdevice.trx_stop_func(&RC.ru[enb_id]->ifdevice);
      LOG_I(ENB_APP, "turned off RU ifdevice\n");
    } else {
      LOG_W(ENB_APP, "can not turn off ifdevice due to missing trx_stop_func callback, proceding anyway!\n");
787
    }
788 789 790
  } else {
    LOG_W(ENB_APP, "no RU found for index %d\n", enb_id);
    return -1;
791 792 793 794 795
  }

  /* these tasks need to pick up new configuration */
  terminate_task(TASK_RRC_ENB, enb_id);
  terminate_task(TASK_L2L1, enb_id);
796
  LOG_I(ENB_APP, "calling kill_eNB_proc() for instance %d\n", enb_id);
797
  kill_eNB_proc(enb_id);
798 799
  LOG_I(ENB_APP, "calling kill_RU_proc() for instance %d\n", enb_id);
  kill_RU_proc(enb_id);
800
  oai_exit = 0;
801 802 803 804
  for (int cc_id = 0; cc_id < RC.nb_CC[enb_id]; cc_id++) {
    free_transport(RC.eNB[enb_id][cc_id]);
    phy_free_lte_eNB(RC.eNB[enb_id][cc_id]);
  }
805
  phy_free_RU(RC.ru[enb_id]);
806
  free_lte_top();
807 808 809 810
  return 0;
}

/*
811
 * Restart the lte-softmodem after it has been soft-stopped with stop_L1L2()
812
 */
813
int restart_L1L2(module_id_t enb_id)
814
{
815 816 817
  RU_t *ru = RC.ru[enb_id];
  int cc_id;
  MessageDef *msg_p = NULL;
818 819 820 821 822 823

  LOG_W(ENB_APP, "restarting lte-softmodem\n");

  /* block threads */
  sync_var = -1;

824 825
  for (cc_id = 0; cc_id < RC.nb_L1_CC[enb_id]; cc_id++) {
    RC.eNB[enb_id][cc_id]->configured = 0;
826 827
  }

828 829 830 831 832
  RC.ru_mask |= (1 << ru->idx);
  /* copy the changed frame parameters to the RU */
  /* TODO this should be done for all RUs associated to this eNB */
  memcpy(&ru->frame_parms, &RC.eNB[enb_id][0]->frame_parms, sizeof(LTE_DL_FRAME_PARMS));
  set_function_spec_param(RC.ru[enb_id]);
833 834 835 836 837 838 839 840 841 842 843 844 845 846 847

  LOG_I(ENB_APP, "attempting to create ITTI tasks\n");
  if (itti_create_task (TASK_RRC_ENB, rrc_enb_task, NULL) < 0) {
    LOG_E(RRC, "Create task for RRC eNB failed\n");
    return -1;
  } else {
    LOG_I(RRC, "Re-created task for RRC eNB successfully\n");
  }
  if (itti_create_task (TASK_L2L1, l2l1_task, NULL) < 0) {
    LOG_E(PDCP, "Create task for L2L1 failed\n");
    return -1;
  } else {
    LOG_I(PDCP, "Re-created task for L2L1 successfully\n");
  }

848 849 850 851 852
  /* pass a reconfiguration request which will configure everything down to
   * RC.eNB[i][j]->frame_parms, too */
  msg_p = itti_alloc_new_message(TASK_ENB_APP, RRC_CONFIGURATION_REQ);
  RRC_CONFIGURATION_REQ(msg_p) = RC.rrc[enb_id]->configuration;
  itti_send_msg_to_task(TASK_RRC_ENB, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p);
853 854
  /* TODO XForms might need to be restarted, but it is currently (09/02/18)
   * broken, so we cannot test it */
855

856 857 858 859 860 861
  wait_eNBs();
  init_RU_proc(ru);
  ru->rf_map.card = 0;
  ru->rf_map.chain = 0; /* CC_id + chain_offset;*/
  wait_RUs();
  init_eNB_afterRU();
862 863 864 865 866 867 868 869

  printf("Sending sync to all threads\n");
  pthread_mutex_lock(&sync_mutex);
  sync_var=0;
  pthread_cond_broadcast(&sync_cond);
  pthread_mutex_unlock(&sync_mutex);

  return 0;
870
}
871
#endif
872

873
static  void wait_nfapi_init(char *thread_name) {
874 875 876 877 878 879 880 881 882 883 884 885

  printf( "waiting for NFAPI PNF connection and population of global structure (%s)\n",thread_name);
  pthread_mutex_lock( &nfapi_sync_mutex );
  
  while (nfapi_sync_var<0)
    pthread_cond_wait( &nfapi_sync_cond, &nfapi_sync_mutex );
  
  pthread_mutex_unlock(&nfapi_sync_mutex);
  
  printf( "NFAPI: got sync (%s)\n", thread_name);
}

886 887
int main( int argc, char **argv )
{
888
  int i;
889
#if defined (XFORMS)
knopp's avatar
knopp committed
890
  void *status;
891
#endif
892

knopp's avatar
knopp committed
893
  int CC_id;
894
  int ru_id;
knopp's avatar
knopp committed
895
#if defined (XFORMS)
896 897
  int ret;
#endif
898

899
  start_background_system();
900 901 902 903
  if ( load_configmodule(argc,argv) == NULL) {
    exit_fun("[SOFTMODEM] Error, configuration module init failed\n");
  } 
      
904 905 906 907 908
#ifdef DEBUG_CONSOLE
  setvbuf(stdout, NULL, _IONBF, 0);
  setvbuf(stderr, NULL, _IONBF, 0);
#endif

909
  mode = normal_txrx;
910
  memset(&openair0_cfg[0],0,sizeof(openair0_config_t)*MAX_CARDS);
911

912
  memset(tx_max_power,0,sizeof(int)*MAX_NUM_CCs);
913

knopp's avatar
knopp committed
914
  set_latency_target();
915

916
  logInit();
knopp's avatar
knopp committed
917

918
  printf("Reading in command-line options\n");
919

920
  get_options (); 
921
  if (CONFIG_ISFLAGSET(CONFIG_ABORT) ) {
922 923
      fprintf(stderr,"Getting configuration failed\n");
      exit(-1);
924
  }
knopp's avatar
knopp committed
925 926


927
#if T_TRACER
928
  T_init(T_port, 1-T_nowait, T_dont_fork);
929 930
#endif

931

932

933 934
  //randominit (0);
  set_taus_seed (0);
knopp's avatar
knopp committed
935

936
  printf("configuring for RAU/RRU\n");
937

938

knopp's avatar
knopp committed
939
  if (ouput_vcd) {
gauthier's avatar
gauthier committed
940
      VCD_SIGNAL_DUMPER_INIT("/tmp/openair_dump_eNB.vcd");
knopp's avatar
knopp committed
941
  }
942

943
  if (opp_enabled ==1) {
944
    reset_opp_meas();
945 946
  }
  cpuf=get_cpu_freq_GHz();
947

948
#if defined(ENABLE_ITTI)
949
  log_set_instance_type (LOG_INSTANCE_ENB);
950

951
  printf("ITTI init\n");
knopp's avatar
knopp committed
952
  itti_init(TASK_MAX, THREAD_MAX, MESSAGES_ID_MAX, tasks_info, messages_info, messages_definition_xml, itti_dump_file);
953

954 955
  // initialize mscgen log after ITTI
  MSC_INIT(MSC_E_UTRAN, THREAD_MAX+TASK_MAX);
956
#endif
957

958 959
  if (opt_type != OPT_NONE) {
    radio_type_t radio_type;
960

961 962
    if (frame_parms[0]->frame_type == FDD)
      radio_type = RADIO_TYPE_FDD;
963
    else
964
      radio_type = RADIO_TYPE_TDD;
965

966 967 968
    if (init_opt(in_path, in_ip, NULL, radio_type) == -1)
      LOG_E(OPT,"failed to run OPT \n");
  }
969

970
#ifdef PDCP_USE_NETLINK
971
  printf("PDCP netlink\n");
knopp's avatar
knopp committed
972
  netlink_init();
973 974 975
#if defined(PDCP_USE_NETLINK_QUEUES)
  pdcp_netlink_init();
#endif
976 977
#endif

978
#if !defined(ENABLE_ITTI)
knopp's avatar
knopp committed
979 980 981
  // to make a graceful exit when ctrl-c is pressed
  signal(SIGSEGV, signal_handler);
  signal(SIGINT, signal_handler);
982
#endif
983

984

knopp's avatar
knopp committed
985 986
  check_clock();

987 988 989 990 991 992
#ifndef PACKAGE_VERSION
#  define PACKAGE_VERSION "UNKNOWN-EXPERIMENTAL"
#endif

  LOG_I(HW, "Version: %s\n", PACKAGE_VERSION);

knopp's avatar
knopp committed
993 994


knopp's avatar
knopp committed
995

996
  printf("Before CC \n");
997

998
  printf("Runtime table\n");
999 1000
  fill_modeled_runtime_table(runtime_phy_rx,runtime_phy_tx);
  cpuf=get_cpu_freq_GHz();
1001 1002 1003
  
  
  
laurent's avatar
laurent committed
1004
#ifndef DEADLINE_SCHEDULER
1005
  
1006
  printf("NO deadline scheduler\n");
1007
  /* Currently we set affinity for UHD to CPU 0 for eNB/UE and only if number of CPUS >2 */
1008 1009 1010 1011 1012
  
  cpu_set_t cpuset;
  int s;
  char cpu_affinity[1024];
  CPU_ZERO(&cpuset);
1013
#ifdef CPU_AFFINITY
1014 1015 1016
  if (get_nprocs() > 2) {
    CPU_SET(0, &cpuset);
    s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
1017
    if (s != 0) {
1018 1019
      perror( "pthread_setaffinity_np");
      exit_fun("Error setting processor affinity");
1020
    }
1021 1022
    LOG_I(HW, "Setting the affinity of main function to CPU 0, for device library to use CPU 0 only!\n");
  }
1023
#endif
1024
  
1025 1026
  /* Check the actual affinity mask assigned to the thread */
  s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
1027 1028 1029 1030
  if (s != 0) {
    perror( "pthread_getaffinity_np");
    exit_fun("Error getting processor affinity ");
  }
1031
  memset(cpu_affinity, 0 , sizeof(cpu_affinity));
1032 1033 1034 1035 1036
  for (int j = 0; j < CPU_SETSIZE; j++) {
    if (CPU_ISSET(j, &cpuset)) {
      char temp[1024];
      sprintf(temp, " CPU_%d ", j);
      strcat(cpu_affinity, temp);
1037
    }
1038
  }
1039
  LOG_I(HW, "CPU Affinity of main() function is... %s\n", cpu_affinity);
1040
#endif
1041
  
1042

1043
  
1044
  
1045
#if defined(ENABLE_ITTI)
1046
  if (RC.nb_inst > 0)  {
1047
    
knopp's avatar
knopp committed
1048
    // don't create if node doesn't connect to RRC/S1/GTP
1049 1050 1051 1052
      if (create_tasks(1) < 0) {
        printf("cannot create ITTI tasks\n");
        exit(-1); // need a softer mode
      }
1053 1054 1055
    printf("ITTI tasks created\n");
  }
  else {
1056 1057
    printf("No ITTI, Initializing L1\n");
    RCconfig_L1();
1058
  }
1059
#endif
1060

1061
  /* Start the agent. If it is turned off in the configuration, it won't start */
1062 1063 1064 1065 1066 1067 1068 1069
  RCconfig_flexran();
  for (i = 0; i < RC.nb_L1_inst; i++) {
    flexran_agent_start(i);
  }

  // init UE_PF_PO and mutex lock
  pthread_mutex_init(&ue_pf_po_mutex, NULL);
  memset (&UE_PF_PO[0][0], 0, sizeof(UE_PF_PO_t)*NUMBER_OF_UE_MAX*MAX_NUM_CCs);
1070
  
knopp's avatar
knopp committed
1071
  mlockall(MCL_CURRENT | MCL_FUTURE);
1072
  
knopp's avatar
knopp committed
1073 1074
  pthread_cond_init(&sync_cond,NULL);
  pthread_mutex_init(&sync_mutex, NULL);
1075
  
1076
#ifdef XFORMS
1077
  int UE_id;
1078
  
1079 1080
  printf("XFORMS\n");

knopp's avatar
knopp committed
1081 1082
  if (do_forms==1) {
    fl_initialize (&argc, argv, NULL, 0, 0);
1083
    
1084
      form_stats_l2 = create_form_stats_form();
1085 1086 1087
      fl_show_form (form_stats_l2->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "l2 stats");
      form_stats = create_form_stats_form();
      fl_show_form (form_stats->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "stats");
1088
      
1089
      for(UE_id=0; UE_id<scope_enb_num_ue; UE_id++) {
1090 1091 1092 1093
	for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
	  form_enb[CC_id][UE_id] = create_lte_phy_scope_enb();
	  sprintf (title, "LTE UL SCOPE eNB for CC_id %d, UE %d",CC_id,UE_id);
	  fl_show_form (form_enb[CC_id][UE_id]->lte_phy_scope_enb, FL_PLACE_HOTSPOT, FL_FULLBORDER, title);
1094
	  
1095 1096 1097 1098 1099 1100 1101
	  if (otg_enabled) {
	    fl_set_button(form_enb[CC_id][UE_id]->button_0,1);
	    fl_set_object_label(form_enb[CC_id][UE_id]->button_0,"DL Traffic ON");
	  } else {
	    fl_set_button(form_enb[CC_id][UE_id]->button_0,0);
	    fl_set_object_label(form_enb[CC_id][UE_id]->button_0,"DL Traffic OFF");
	  }
1102 1103
	} // CC_id
      } // UE_id
1104
    
knopp's avatar
knopp committed
1105
    ret =