lte-softmodem.c 73.6 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 25 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
/*******************************************************************************

  Eurecom OpenAirInterface
  Copyright(c) 1999 - 2011 Eurecom

  This program is free software; you can redistribute it and/or modify it
  under the terms and conditions of the GNU General Public License,
  version 2, as published by the Free Software Foundation.

  This program is distributed in the hope 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
  this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.

  The full GNU General Public License is included in this distribution in
  the file called "COPYING".

  Contact Information
  Openair Admin: openair_admin@eurecom.fr
  Openair Tech : openair_tech@eurecom.fr
  Forums       : http://forums.eurecom.fsr/openairinterface
  Address      : Eurecom, 2229, route des crêtes, 06560 Valbonne Sophia Antipolis, France

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

/*! \file lte-softmodem.c
* \brief main program to control HW and scheduling
* \author R. Knopp, F. Kaltenberger
* \date 2012
* \version 0.1
* \company Eurecom
* \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr
* \note
* \warning
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sched.h>
#include <signal.h>
#include <execinfo.h>
#include <getopt.h>

#include "rt_wrapper.h"
55 56
#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all

57
#include "assertions.h"
58 59 60 61 62 63

#ifdef EMOS
#include <gps.h>
#endif

#include "PHY/types.h"
64

65
#include "PHY/defs.h"
66 67 68
#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all
#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all

69
#include "openair0_lib.h"
70
#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all
71 72 73

#include "PHY/vars.h"
#include "MAC_INTERFACE/vars.h"
74
//#include "SCHED/defs.h"
75 76 77 78 79 80 81 82 83 84
#include "SCHED/vars.h"
#include "LAYER2/MAC/vars.h"

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

#ifdef EMOS
#include "SCHED/phy_procedures_emos.h"
#endif

#ifdef OPENAIR2
85
#include "otg_tx.h"
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
#include "LAYER2/MAC/defs.h"
#include "LAYER2/MAC/vars.h"
#ifndef CELLULAR
#include "RRC/LITE/vars.h"
#endif
#include "PHY_INTERFACE/vars.h"
#endif

#ifdef SMBV
#include "PHY/TOOLS/smbv.h"
unsigned short config_frames[4] = {2,9,11,13};
#endif
#include "UTIL/LOG/log_extern.h"
#include "UTIL/OTG/otg.h"
#include "UTIL/OTG/otg_vars.h"
#include "UTIL/MATH/oml.h"
#include "UTIL/LOG/vcd_signal_dumper.h"
103
#include "enb_config.h"
104

105 106
#if defined(ENABLE_ITTI)
# include "intertask_interface_init.h"
107
# include "create_tasks.h"
108 109 110
# if defined(ENABLE_USE_MME)
#   include "s1ap_eNB.h"
# endif
111 112
#endif

113 114 115
#ifdef XFORMS
#include "PHY/TOOLS/lte_phy_scope.h"
#include "stats.h"
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
#endif

#define FRAME_PERIOD    100000000ULL
#define DAQ_PERIOD      66667ULL

#define MY_RF_MODE      (RXEN + TXEN + TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON +LNAMax + RFBBNORM + DMAMODE_RX + DMAMODE_TX)
#define RF_MODE_BASE    (TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON +LNAMax + RFBBNORM)

struct timing_info_t {
  //unsigned int frame, hw_slot, last_slot, next_slot;
  RTIME time_min, time_max, time_avg, time_last, time_now;
  //unsigned int mbox0, mbox1, mbox2, mbox_target;
  unsigned int n_samples;
} timing_info;

gauthier's avatar
gauthier committed
131 132
extern int16_t* sync_corr_ue0;
extern int16_t prach_ifft[4][1024*2];
133 134 135

int init_dlsch_threads(void);
void cleanup_dlsch_threads(void);
gauthier's avatar
gauthier committed
136
int32_t init_rx_pdsch_thread(void);
137 138 139 140 141 142 143 144 145
void cleanup_rx_pdsch_thread(void);
int init_ulsch_threads(void);
void cleanup_ulsch_threads(void);

void setup_ue_buffers(PHY_VARS_UE *phy_vars_ue, LTE_DL_FRAME_PARMS *frame_parms, int carrier);
void setup_eNB_buffers(PHY_VARS_eNB *phy_vars_eNB, LTE_DL_FRAME_PARMS *frame_parms, int carrier);
void test_config(int card, int ant, unsigned int rf_mode, int UE_flag);

#ifdef XFORMS
146 147 148 149
// current status is that every UE has a DL scope for a SINGLE eNB (eNB_id=0)
// at eNB 0, an UL scope for every UE 
FD_lte_phy_scope_ue  *form_ue[NUMBER_OF_UE_MAX];
FD_lte_phy_scope_enb *form_enb[NUMBER_OF_UE_MAX];
150
FD_stats_form                  *form_stats=NULL;
151
char title[255];
152
unsigned char                   scope_enb_num_ue = 1;
153 154 155
#endif //XFORMS

#ifdef RTAI
156
static SEM                     *mutex;
157 158
//static CND *cond;

159 160
static int                      thread0;
static int                      thread1;
161 162
//static int sync_thread;
#else
163 164 165 166
pthread_t                       thread0;
pthread_t                       thread1;
pthread_attr_t                  attr_dlsch_threads;
struct sched_param              sched_param_dlsch;
167 168
#endif

169 170 171 172 173 174
#ifdef XFORMS
static pthread_t                thread2; //xforms
#endif
#ifdef EMOS
static pthread_t                thread3; //emos
#endif
175

176 177 178 179 180 181 182 183
/*
static int instance_cnt=-1; //0 means worker is busy, -1 means its free
int instance_cnt_ptr_kern,*instance_cnt_ptr_user;
int pci_interface_ptr_kern;
*/
//extern unsigned int bigphys_top;
//extern unsigned int mem_base;

184 185 186 187
int                             card = 0;
static exmimo_config_t         *p_exmimo_config;
static exmimo_id_t             *p_exmimo_id;
static volatile unsigned int   *DAQ_MBOX;
188

189
#if defined(ENABLE_ITTI)
190 191
static volatile int             start_eNB = 0;
static volatile int             start_UE = 0;
192
#endif
193 194 195 196 197 198 199 200
volatile int                    oai_exit = 0;

//static int                      time_offset[4] = {-138,-138,-138,-138};
//static int                      time_offset[4] = {-145,-145,-145,-145};
static int                      time_offset[4] = {0,0,0,0};

static int                      fs4_test=0;
static char                     UE_flag=0;
gauthier's avatar
gauthier committed
201
static uint8_t                       eNB_id=0,UE_id=0;
202

gauthier's avatar
gauthier committed
203
uint32_t                             carrier_freq[4] =           {1907600000,1907600000,1907600000,1907600000}; /* For UE! */
204
static uint32_t          downlink_frequency[4] =     {1907600000,1907600000,1907600000,1907600000};
gauthier's avatar
gauthier committed
205
static int32_t                      uplink_frequency_offset[4]= {-120000000,-120000000,-120000000,-120000000};
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
static char                    *conf_config_file_name = NULL;

static char                    *itti_dump_file = NULL;

static char                     rxg_fname[100];
static char                     txg_fname[100];
static char                     rflo_fname[100];
static char                     rfdc_fname[100];
static FILE                    *rxg_fd=NULL;
static FILE                    *txg_fd=NULL;
static FILE                    *rflo_fd=NULL;
static FILE                    *rfdc_fd=NULL;
static unsigned int             rxg_max[4] =    {133,133,133,133};
static unsigned int             rxg_med[4] =    {127,127,127,127};
static unsigned int             rxg_byp[4] =    {120,120,120,120};
static int                      tx_max_power =  0;
222

223
/*
gauthier's avatar
gauthier committed
224 225 226
uint32_t rf_mode_max[4]     = {55759,55759,55759,55759};
uint32_t rf_mode_med[4]     = {39375,39375,39375,39375};
uint32_t rf_mode_byp[4]     = {22991,22991,22991,22991};
227
*/
gauthier's avatar
gauthier committed
228 229
static uint32_t                      rf_mode[4] =        {MY_RF_MODE,0,0,0};
static uint32_t                      rf_local[4] =       {8255000,8255000,8255000,8255000}; // UE zepto
230 231 232
  //{8254617, 8254617, 8254617, 8254617}; //eNB khalifa
  //{8255067,8254810,8257340,8257340}; // eNB PETRONAS

gauthier's avatar
gauthier committed
233 234 235 236 237
static uint32_t                      rf_vcocal[4] =      {910,910,910,910};
static uint32_t                      rf_vcocal_850[4] =  {2015, 2015, 2015, 2015};
static uint32_t                      rf_rxdc[4] =        {32896,32896,32896,32896};
static uint32_t                      rxgain[4] =         {20,20,20,20};
static uint32_t                      txgain[4] =         {20,20,20,20};
238 239 240

static runmode_t                mode;
static int                      rx_input_level_dBm;
241
static int                      online_log_messages=0;
242
#ifdef XFORMS
243
extern int                      otg_enabled;
244
static char                     do_forms=0;
245
#else
246
int                             otg_enabled;
247
#endif
248
int                             number_of_cards =   1;
249

250 251
static int                      mbox_bounds[20] =   {8,16,24,30,38,46,54,60,68,76,84,90,98,106,114,120,128,136,144, 0}; ///boundaries of slots in terms ob mbox counter rounded up to even numbers
//static int                      mbox_bounds[20] =   {6,14,22,28,36,44,52,58,66,74,82,88,96,104,112,118,126,134,142, 148}; ///boundaries of slots in terms ob mbox counter rounded up to even numbers
252

253
static LTE_DL_FRAME_PARMS      *frame_parms;
254

255
unsigned int build_rflocal(int txi, int txq, int rxi, int rxq)
256 257 258 259 260 261 262 263
{
    return (txi + (txq<<6) + (rxi<<12) + (rxq<<18));
}
unsigned int build_rfdc(int dcoff_i_rxfe, int dcoff_q_rxfe)
{
    return (dcoff_i_rxfe + (dcoff_q_rxfe<<8));
}

264
#if !defined(ENABLE_ITTI)
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
void signal_handler(int sig)
{
  void *array[10];
  size_t size;

  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);
    exit(-1);
  }
  else {
280
    oai_exit = 1;
281 282
  }
}
283
#endif
284 285 286

void exit_fun(const char* s)
{
287
  if (s != NULL) {
gauthier's avatar
gauthier committed
288
    printf("%s %s() Exiting: %s\n",__FILE__, __FUNCTION__, s);
289 290 291 292 293
  }

  oai_exit = 1;

#if defined(ENABLE_ITTI)
294
  itti_terminate_tasks (TASK_UNKNOWN);
295
#endif
296 297 298 299 300 301 302

  //rt_sleep_ns(FRAME_PERIOD);

  //exit (-1);
}

#ifdef XFORMS
303
static void *scope_thread(void *arg) {
304
    char stats_buffer[16384];
305 306
# ifdef ENABLE_XFORMS_WRITE_STATS
    FILE *UE_stats, *eNB_stats;
307
    int len = 0;
308
# endif
309 310 311 312 313 314
    struct sched_param sched_param;

    sched_param.sched_priority = sched_get_priority_min(SCHED_FIFO)+1; 
    sched_setscheduler(0, SCHED_FIFO,&sched_param);

    printf("Scope thread has priority %d\n",sched_param.sched_priority);
315 316 317 318 319 320 321 322 323 324
    
    /*
      if (UE_flag==1) 
      UE_stats  = fopen("UE_stats.txt", "w");
      else 
      eNB_stats = fopen("eNB_stats.txt", "w");
    */
    
    while (!oai_exit) {
        if (UE_flag==1) {
325 326 327 328
# ifdef ENABLE_XFORMS_WRITE_STATS
            len =
# endif
                    dump_ue_stats (PHY_vars_UE_g[0], stats_buffer, 0, mode,rx_input_level_dBm);
329
            fl_set_object_label(form_stats->stats_text, stats_buffer);
330 331 332 333
# ifdef ENABLE_XFORMS_WRITE_STATS
            rewind (UE_stats);
            fwrite (stats_buffer, 1, len, UE_stats);
# endif
334 335 336 337 338 339
            phy_scope_UE(form_ue[UE_id], 
                         PHY_vars_UE_g[UE_id],
                         eNB_id,
                         UE_id,7);
            
        } else {
340 341 342 343
# ifdef ENABLE_XFORMS_WRITE_STATS
            len =
# endif
                    dump_eNB_stats (PHY_vars_eNB_g[0], stats_buffer, 0);
344
            fl_set_object_label(form_stats->stats_text, stats_buffer);
345 346 347 348
# ifdef ENABLE_XFORMS_WRITE_STATS
            rewind (eNB_stats);
            fwrite (stats_buffer, 1, len, eNB_stats);
# endif
349 350 351 352 353 354 355 356
            for(UE_id=0;UE_id<scope_enb_num_ue;UE_id++) {
                phy_scope_eNB(form_enb[UE_id], 
                              PHY_vars_eNB_g[eNB_id],
                              UE_id);
            }
              
        }
        //printf("doing forms\n");
357
        usleep(100000); // 100 ms
358 359
    }
    
360 361 362 363
# ifdef ENABLE_XFORMS_WRITE_STATS
    fclose (UE_stats);
    fclose (eNB_stats);
# endif
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
    
    pthread_exit((void*)arg);
}
#endif

int dummy_tx_buffer[3840*4] __attribute__((aligned(16)));

#ifdef EMOS
#define NO_ESTIMATES_DISK 100 //No. of estimates that are aquired before dumped to disk

void *emos_thread (void *arg)
{
  char c;
  char *fifo2file_buffer, *fifo2file_ptr;

  int fifo, counter=0, bytes;

  FILE  *dumpfile_id;
  char  dumpfile_name[1024];
  time_t starttime_tmp;
  struct tm starttime;
  
  int channel_buffer_size;
  
  time_t timer;
  struct tm *now;

  struct gps_data_t *gps_data = NULL;
  struct gps_fix_t dummy_gps_data;
393 394 395 396 397 398 399

  struct sched_param sched_param;
  
  sched_param.sched_priority = sched_get_priority_max(SCHED_FIFO)-1; 
  sched_setscheduler(0, SCHED_FIFO,&sched_param);
  
  printf("EMOS thread has priority %d\n",sched_param.sched_priority);
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
 
  timer = time(NULL);
  now = localtime(&timer);

  memset(&dummy_gps_data,1,sizeof(struct gps_fix_t));
  
  gps_data = gps_open("127.0.0.1","2947");
  if (gps_data == NULL) 
    {
      printf("[EMOS] Could not open GPS\n");
      //exit(-1);
    }
#if GPSD_API_MAJOR_VERSION>=4
  else if (gps_stream(gps_data, WATCH_ENABLE,NULL) != 0)
#else
  else if (gps_query(gps_data, "w+x") != 0)
#endif
    {
      //sprintf(tmptxt,"Error sending command to GPS, gps_data = %x", gps_data);
      printf("[EMOS] Error sending command to GPS\n");
      //exit(-1);
    }
422 423
  else 
    printf("[EMOS] Opened GPS, gps_data=%p\n");
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
  
  if (UE_flag==0)
    channel_buffer_size = sizeof(fifo_dump_emos_eNB);
  else
    channel_buffer_size = sizeof(fifo_dump_emos_UE);

  // allocate memory for NO_FRAMES_DISK channes estimations
  fifo2file_buffer = malloc(NO_ESTIMATES_DISK*channel_buffer_size);
  fifo2file_ptr = fifo2file_buffer;

  if (fifo2file_buffer == NULL)
    {
      printf("[EMOS] Cound not allocate memory for fifo2file_buffer\n");
      exit(EXIT_FAILURE);
    }

  if ((fifo = open(CHANSOUNDER_FIFO_DEV, O_RDONLY)) < 0)
    {
      fprintf(stderr, "[EMOS] Error opening the fifo\n");
      exit(EXIT_FAILURE);
    }


  time(&starttime_tmp);
  localtime_r(&starttime_tmp,&starttime);
  snprintf(dumpfile_name,1024,"/tmp/%s_data_%d%02d%02d_%02d%02d%02d.EMOS",
	   (UE_flag==0) ? "eNB" : "UE",
	   1900+starttime.tm_year, starttime.tm_mon+1, starttime.tm_mday, starttime.tm_hour, starttime.tm_min, starttime.tm_sec);

  dumpfile_id = fopen(dumpfile_name,"w");
  if (dumpfile_id == NULL)
    {
      fprintf(stderr, "[EMOS] Error opening dumpfile %s\n",dumpfile_name);
      exit(EXIT_FAILURE);
    }


  printf("[EMOS] starting dump, channel_buffer_size=%d ...\n",channel_buffer_size);
  while (!oai_exit)
    {
      bytes = rtf_read_timed(fifo, fifo2file_ptr, channel_buffer_size,100);
      if (bytes==0)
	continue;

      /*
469
      if (UE_flag==0)
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
	printf("eNB: count %d, frame %d, read: %d bytes from the fifo\n",counter, ((fifo_dump_emos_eNB*)fifo2file_ptr)->frame_tx,bytes);
      else
	printf("UE: count %d, frame %d, read: %d bytes from the fifo\n",counter, ((fifo_dump_emos_UE*)fifo2file_ptr)->frame_rx,bytes);
      */

      fifo2file_ptr += channel_buffer_size;
      counter ++;

      if (counter == NO_ESTIMATES_DISK)
        {
          //reset stuff
          fifo2file_ptr = fifo2file_buffer;
          counter = 0;

          //flush buffer to disk
	  if (UE_flag==0)
	    printf("[EMOS] eNB: count %d, frame %d, flushing buffer to disk\n",
		   counter, ((fifo_dump_emos_eNB*)fifo2file_ptr)->frame_tx);
	  else
	    printf("[EMOS] UE: count %d, frame %d, flushing buffer to disk\n",
		   counter, ((fifo_dump_emos_UE*)fifo2file_ptr)->frame_rx);


          if (fwrite(fifo2file_buffer, sizeof(char), NO_ESTIMATES_DISK*channel_buffer_size, dumpfile_id) != NO_ESTIMATES_DISK*channel_buffer_size)
            {
              fprintf(stderr, "[EMOS] Error writing to dumpfile\n");
              exit(EXIT_FAILURE);
            }
	  if (gps_data)
	    {
	      if (gps_poll(gps_data) != 0) {
		printf("[EMOS] problem polling data from gps\n");
	      }
	      else {
		printf("[EMOS] lat %g, lon %g\n",gps_data->fix.latitude,gps_data->fix.longitude);
	      }
	      if (fwrite(&(gps_data->fix), sizeof(char), sizeof(struct gps_fix_t), dumpfile_id) != sizeof(struct gps_fix_t))
		{
		  printf("[EMOS] Error writing to dumpfile, stopping recording\n");
		  exit(EXIT_FAILURE);
		}
	    }
	  else
	    {
	      printf("[EMOS] WARNING: No GPS data available, storing dummy packet\n");
	      if (fwrite(&(dummy_gps_data), sizeof(char), sizeof(struct gps_fix_t), dumpfile_id) != sizeof(struct gps_fix_t))
		{
		  printf("[EMOS] Error writing to dumpfile, stopping recording\n");
		  exit(EXIT_FAILURE);
		}
	    } 
        }
    }
  
  free(fifo2file_buffer);
  fclose(dumpfile_id);
  close(fifo);
  
  pthread_exit((void*) arg);

}
#endif

533
#if defined(ENABLE_ITTI)
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
static void wait_system_ready (char *message, volatile int *start_flag)
{
  /* Wait for eNB application initialization to be complete (eNB registration to MME) */
  {
    static char *indicator[] = {".    ", "..   ", "...  ", ".... ", ".....",
                                " ....", "  ...", "   ..", "    .", "     "};
    int i = 0;

    while ((!oai_exit) && (*start_flag == 0)) {
      LOG_N(EMU, message, indicator[i]);
      i = (i + 1) % (sizeof(indicator) / sizeof(indicator[0]));
      usleep(200000);
    }
    LOG_D(EMU,"\n");
  }
}
#endif

  #if defined(ENABLE_ITTI)
553
void *l2l1_task(void *arg)
554
{
555
    MessageDef *message_p = NULL;
556
    int         result;
557

558
    itti_set_task_real_time(TASK_L2L1);
559 560
    itti_mark_task_ready(TASK_L2L1);

561 562 563 564
    if (UE_flag == 0) {
      /* Wait for the initialize message */
      do {
        if (message_p != NULL) {
565 566
          result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p);
          AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
567 568
        }
        itti_receive_msg (TASK_L2L1, &message_p);
569 570 571 572

        switch (ITTI_MSG_ID(message_p)) {
          case INITIALIZE_MESSAGE:
            /* Start eNB thread */
573
            LOG_D(EMU, "L2L1 TASK received %s\n", ITTI_MSG_NAME(message_p));
574 575 576 577 578 579 580 581 582 583 584 585
            start_eNB = 1;
            break;

          case TERMINATE_MESSAGE:
            oai_exit=1;
            itti_exit_task ();
            break;

          default:
            LOG_E(EMU, "Received unexpected message %s\n", ITTI_MSG_NAME(message_p));
            break;
        }
586
      } while (ITTI_MSG_ID(message_p) != INITIALIZE_MESSAGE);
587 588
      result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p);
      AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
589 590
    }

591 592 593 594 595 596 597 598 599 600
    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;

601 602 603 604 605 606 607 608
        case ACTIVATE_MESSAGE:
          start_UE = 1;
          break;

        case DEACTIVATE_MESSAGE:
          start_UE = 0;
          break;

609 610 611 612 613 614 615 616 617
        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;
      }

618 619
      result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p);
      AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
620 621
    } while(1);

622 623 624 625
    return NULL;
}
#endif

626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641
/* This is the main eNB thread. It gets woken up by the kernel driver using the RTAI message mechanism (rt_send and rt_receive). */
static void *eNB_thread(void *arg)
{
#ifdef RTAI
  RT_TASK *task;
#endif
  unsigned char slot=0,last_slot, next_slot;
  int hw_slot,frame=0;
  unsigned int aa,slot_offset, slot_offset_F;
  int diff;
  int delay_cnt;
  RTIME time_in, time_diff;
  int mbox_target=0,mbox_current=0;
  int i,ret;
  int tx_offset;

642 643
#if defined(ENABLE_ITTI)
  /* Wait for eNB application initialization to be complete (eNB registration to MME) */
644
  wait_system_ready ("Waiting for eNB application to be ready %s\r", &start_eNB);
645 646
#endif

647
#ifdef RTAI
648 649 650 651 652 653
    task = rt_task_init_schmod(nam2num("TASK0"), 0, 0, 0, SCHED_FIFO, 0xF);
#endif

  if (!oai_exit) {
#ifdef RTAI
    LOG_D(HW,"Started eNB thread (id %p)\n",task);
654 655 656
#endif

#ifdef HARD_RT
657
    rt_make_hard_real_time();
658 659
#endif

660
    mlockall(MCL_CURRENT | MCL_FUTURE);
661

662 663 664 665
    timing_info.time_min = 100000000ULL;
    timing_info.time_max = 0;
    timing_info.time_avg = 0;
    timing_info.n_samples = 0;
666

667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688
    while (!oai_exit)
      {
        hw_slot = (((((volatile unsigned int *)DAQ_MBOX)[0]+1)%150)<<1)/15;
        //LOG_D(HW,"eNB frame %d, time %llu: slot %d, hw_slot %d (mbox %d)\n",frame,rt_get_time_ns(),slot,hw_slot,((unsigned int *)DAQ_MBOX)[0]);
        //this is the mbox counter where we should be
        //mbox_target = ((((slot+1)%20)*15+1)>>1)%150;
        mbox_target = mbox_bounds[slot];
        //this is the mbox counter where we are
        mbox_current = ((volatile unsigned int *)DAQ_MBOX)[0];
        //this is the time we need to sleep in order to synchronize with the hw (in multiples of DAQ_PERIOD)
        if ((mbox_current>=135) && (mbox_target<15)) //handle the frame wrap-arround
            diff = 150-mbox_current+mbox_target;
        else if ((mbox_current<15) && (mbox_target>=135))
            diff = -150+mbox_target-mbox_current;
        else
            diff = mbox_target - mbox_current;

        if (((slot%2==0) && (diff < (-14))) || ((slot%2==1) && (diff < (-7)))) {
          // at the eNB, even slots have double as much time since most of the processing is done here and almost nothing in odd slots
          LOG_D(HW,"eNB Frame %d, time %llu: missed slot, proceeding with next one (slot %d, hw_slot %d, diff %d)\n",frame, rt_get_time_ns(), slot, hw_slot, diff);
          slot++;
          if (frame > 0) {
winckel's avatar
winckel committed
689
            exit_fun("[HW][eNB] missed slot");
690 691 692 693 694 695
          }
          if (slot==20){
            slot=0;
            frame++;
          }
          continue;
696
        }
697 698
        if (diff>8)
            LOG_D(HW,"eNB Frame %d, time %llu: skipped slot, waiting for hw to catch up (slot %d, hw_slot %d, mbox_current %d, mbox_target %d, diff %d)\n",frame, rt_get_time_ns(), slot, hw_slot, mbox_current, mbox_target, diff);
699

700 701 702 703 704 705 706 707 708 709 710 711 712 713 714
        delay_cnt = 0;
        while ((diff>0) && (!oai_exit))
          {
            time_in = rt_get_time_ns();
            //LOG_D(HW,"eNB Frame %d delaycnt %d : hw_slot %d (%d), slot %d, (slot+1)*15=%d, diff %d, time %llu\n",frame,delay_cnt,hw_slot,((unsigned int *)DAQ_MBOX)[0],slot,(((slot+1)*15)>>1),diff,time_in);
            //LOG_D(HW,"eNB Frame %d, time %llu: sleeping for %llu (slot %d, hw_slot %d, diff %d, mbox %d, delay_cnt %d)\n", frame, time_in, diff*DAQ_PERIOD,slot,hw_slot,diff,((volatile unsigned int *)DAQ_MBOX)[0],delay_cnt);
            ret = rt_sleep_ns(diff*DAQ_PERIOD);
            if (ret)
              LOG_D(HW,"eNB Frame %d, time %llu: rt_sleep_ns returned %d\n",frame, time_in);
            hw_slot = (((((volatile unsigned int *)DAQ_MBOX)[0]+1)%150)<<1)/15;
            //LOG_D(HW,"eNB Frame %d : hw_slot %d, time %llu\n",frame,hw_slot,rt_get_time_ns());
            delay_cnt++;
            if (delay_cnt == 10)
              {
                LOG_D(HW,"eNB Frame %d: HW stopped ... \n",frame);
winckel's avatar
winckel committed
715
                exit_fun("[HW][eNB] HW stopped");
716 717 718 719 720 721 722 723 724
              }
            mbox_current = ((volatile unsigned int *)DAQ_MBOX)[0];
            if ((mbox_current>=135) && (mbox_target<15)) //handle the frame wrap-arround
              diff = 150-mbox_current+mbox_target;
            else if ((mbox_current<15) && (mbox_target>=135))
              diff = -150+mbox_target-mbox_current;
            else
              diff = mbox_target - mbox_current;
          }
725

726 727 728 729
        last_slot = (slot)%LTE_SLOTS_PER_FRAME;
        if (last_slot <0)
          last_slot+=20;
        next_slot = (slot+3)%LTE_SLOTS_PER_FRAME;
730

731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750
        //PHY_vars_eNB_g[0]->frame = frame;
        if (frame>5)
          {
            /*
            if (frame%100==0)
              LOG_D(HW,"frame %d (%d), slot %d, hw_slot %d, next_slot %d (before): DAQ_MBOX %d\n",frame, PHY_vars_eNB_g[0]->frame, slot, hw_slot,next_slot,DAQ_MBOX[0]);
            */

            //if (PHY_vars_eNB_g[0]->frame>5) {
              timing_info.time_last = timing_info.time_now;
              timing_info.time_now = rt_get_time_ns();

              if (timing_info.n_samples>0) {
                time_diff = timing_info.time_now - timing_info.time_last;
                if (time_diff < timing_info.time_min)
                  timing_info.time_min = time_diff;
                if (time_diff > timing_info.time_max)
                  timing_info.time_max = time_diff;
                timing_info.time_avg += time_diff;
              }
751

752 753 754 755 756 757 758 759 760 761 762
              timing_info.n_samples++;
              /*
              if ((timing_info.n_samples%2000)==0) {
                LOG_D(HW,"frame %d (%d), slot %d, hw_slot %d: diff=%llu, min=%llu, max=%llu, avg=%llu (n_samples %d)\n",
                      frame, PHY_vars_eNB_g[0]->frame, slot, hw_slot,time_diff,
                      timing_info.time_min,timing_info.time_max,timing_info.time_avg/timing_info.n_samples,timing_info.n_samples);
                timing_info.n_samples = 0;
                timing_info.time_avg = 0;
              }
              */
              //}
763

764 765 766
            if (fs4_test==0)
              {
                phy_procedures_eNB_lte (last_slot, next_slot, PHY_vars_eNB_g[0], 0, no_relay,NULL);
767
#ifndef IFFT_FPGA
768 769 770 771 772 773 774 775 776 777 778 779 780 781 782
                slot_offset_F = (next_slot)*
                                (PHY_vars_eNB_g[0]->lte_frame_parms.ofdm_symbol_size)*
                                ((PHY_vars_eNB_g[0]->lte_frame_parms.Ncp==1) ? 6 : 7);
                slot_offset = (next_slot)*
                              (PHY_vars_eNB_g[0]->lte_frame_parms.samples_per_tti>>1);
                if ((subframe_select(&PHY_vars_eNB_g[0]->lte_frame_parms,next_slot>>1)==SF_DL)||
                    ((subframe_select(&PHY_vars_eNB_g[0]->lte_frame_parms,next_slot>>1)==SF_S)&&((next_slot&1)==0)))
                  {
                    //	  LOG_D(HW,"Frame %d: Generating slot %d\n",frame,next_slot);

                    for (aa=0; aa<PHY_vars_eNB_g[0]->lte_frame_parms.nb_antennas_tx; aa++)
                      {
                        if (PHY_vars_eNB_g[0]->lte_frame_parms.Ncp == 1)
                          {
                            PHY_ofdm_mod(&PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdataF[0][aa][slot_offset_F],
783
#ifdef BIT8_TX
784
                                         &PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa][slot_offset>>1],
785
#else
786
                                         dummy_tx_buffer,//&PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa][slot_offset],
787
#endif
788 789 790 791 792 793 794 795 796 797
                                         PHY_vars_eNB_g[0]->lte_frame_parms.log2_symbol_size,
                                         6,
                                         PHY_vars_eNB_g[0]->lte_frame_parms.nb_prefix_samples,
                                         PHY_vars_eNB_g[0]->lte_frame_parms.twiddle_ifft,
                                         PHY_vars_eNB_g[0]->lte_frame_parms.rev,
                                         CYCLIC_PREFIX);
                          }
                        else
                          {
                            normal_prefix_mod(&PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdataF[0][aa][slot_offset_F],
798
#ifdef BIT8_TX
799
                                              &PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa][slot_offset>>1],
800
#else
801
                                              dummy_tx_buffer,//&PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa][slot_offset],
802
#endif
803 804 805
                                              7,
                                              &(PHY_vars_eNB_g[0]->lte_frame_parms));
                          }
806
#ifdef EXMIMO
807 808 809 810 811 812 813 814 815 816 817 818
                        for (i=0; i<PHY_vars_eNB_g[0]->lte_frame_parms.samples_per_tti/2; i++)
                          {
                            tx_offset = (int)slot_offset+time_offset[aa]+i;
                            if (tx_offset<0)
                              tx_offset += LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*PHY_vars_eNB_g[0]->lte_frame_parms.samples_per_tti;
                            if (tx_offset>=(LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*PHY_vars_eNB_g[0]->lte_frame_parms.samples_per_tti))
                              tx_offset -= LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*PHY_vars_eNB_g[0]->lte_frame_parms.samples_per_tti;
                            ((short*)&PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa][tx_offset])[0]=
                              ((short*)dummy_tx_buffer)[2*i]<<4;
                            ((short*)&PHY_vars_eNB_g[0]->lte_eNB_common_vars.txdata[0][aa][tx_offset])[1]=
                              ((short*)dummy_tx_buffer)[2*i+1]<<4;
                          }
819
#endif //EXMIMO
820 821 822
                      }
                  }
              }
823 824

#endif //IFFT_FPGA
825 826 827 828 829
            /*
            if (frame%100==0)
              LOG_D(HW,"hw_slot %d (after): DAQ_MBOX %d\n",hw_slot,DAQ_MBOX[0]);
            */
          }
830

831 832 833 834
        /*
        if ((slot%2000)<10)
        LOG_D(HW,"fun0: doing very hard work\n");
        */
835

836 837 838 839 840
        slot++;
        if (slot==20) {
          slot=0;
          frame++;
        }
841
#if defined(ENABLE_ITTI)
842
        itti_update_lte_time(frame, slot);
843
#endif
844
      }
845

846
      LOG_D(HW,"eNB_thread: finished, ran %d times.\n",frame);
847 848

#ifdef HARD_RT
849
      rt_make_soft_real_time();
850
#endif
851
  }
852 853 854 855 856 857 858 859 860 861 862 863 864 865 866

  // clean task
#ifdef RTAI
  rt_task_delete(task);
#endif
  LOG_D(HW,"Task deleted. returning\n");
  return 0;
}

/* This is the main UE thread. Initially it is doing a periodic get_frame. One synchronized it gets woken up by the kernel driver using the RTAI message mechanism (rt_send and rt_receive). */
static void *UE_thread(void *arg)
{
#ifdef RTAI
  RT_TASK *task;
#endif
867
  // RTIME in, out, diff;
868
  int slot=0,frame=0,hw_slot,last_slot, next_slot;
869
  // unsigned int aa;
870 871 872 873 874 875 876
  static int is_synchronized = 0;
  int delay_cnt;
  RTIME time_in;
  int hw_slot_offset=0,rx_offset_mbox=0,mbox_target=0,mbox_current=0;
  int diff2;
  int i, ret;

877 878
#if defined(ENABLE_ITTI) && defined(ENABLE_USE_MME)
  /* Wait for NAS UE to start cell selection */
879
  wait_system_ready ("Waiting for UE to be activated by UserProcess %s\r", &start_UE);
880 881
#endif

882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908
#ifdef RTAI
  task = rt_task_init_schmod(nam2num("TASK0"), 0, 0, 0, SCHED_FIFO, 0xF);
  LOG_D(HW,"Started UE thread (id %p)\n",task);
#endif

#ifdef HARD_RT
  rt_make_hard_real_time();
#endif

  mlockall(MCL_CURRENT | MCL_FUTURE);

  openair_daq_vars.freq_offset = 0; //-7500;
  /*
  if (mode == rx_calib_ue) {
    openair_daq_vars.freq_offset = -7500;
    for (i=0; i<4; i++) {
        p_exmimo_config->rf.rf_freq_rx[i] = p_exmimo_config->rf.rf_freq_rx[i]+openair_daq_vars.freq_offset;
        p_exmimo_config->rf.rf_freq_tx[i] = p_exmimo_config->rf.rf_freq_rx[i]+openair_daq_vars.freq_offset;
    }
    openair0_dump_config(card);
  }
  */
  while (!oai_exit)
    {
      hw_slot = (((((volatile unsigned int *)DAQ_MBOX)[0]+1)%150)<<1)/15; //the slot the hw is about to store
      
      if (is_synchronized) {
winckel's avatar
winckel committed
909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975
        //this is the mbox counter that indicates the start of the frame
        rx_offset_mbox = (PHY_vars_UE_g[0]->rx_offset * 150) / (10*PHY_vars_UE_g[0]->lte_frame_parms.samples_per_tti);
        //this is the mbox counter where we should be
        mbox_target = (((((slot+1)%20)*15+1)>>1) + rx_offset_mbox + 1)%150;
        // round up to the next multiple of two (mbox counter from express MIMO gives only even numbers)
        mbox_target = ((mbox_target+1)-((mbox_target-1)%2))%150;
        //this is the mbox counter where we are
        mbox_current = ((volatile unsigned int *)DAQ_MBOX)[0];
        //this is the time we need to sleep in order to synchronize with the hw (in multiples of DAQ_PERIOD)
        if ((mbox_current>=120) && (mbox_target<30)) //handle the frame wrap-arround
          diff2 = 150-mbox_current+mbox_target;
        else if ((mbox_current<30) && (mbox_target>=120))
          diff2 = -150+mbox_target-mbox_current;
        else
          diff2 = mbox_target - mbox_current;

        if (diff2 <(-7)) {
          LOG_D(HW,"UE Frame %d: missed slot, proceeding with next one (slot %d, hw_slot %d, diff %d)\n",frame, slot, hw_slot, diff2);
          if (frame>0)
            exit_fun("[HW][UE] missed slot");
          slot++;
          if (slot==20) {
            slot=0;
            frame++;
          }
          continue;
        }
        if (diff2>8)
          LOG_D(HW,"UE Frame %d: skipped slot, waiting for hw to catch up (slot %d, hw_slot %d, mbox_current %d, mbox_target %d, diff %d)\n",frame, slot, hw_slot, mbox_current, mbox_target, diff2);

        /*
          if (frame%100==0)
          LOG_D(HW,"frame %d (%d), slot %d, hw_slot %d, rx_offset_mbox %d, mbox_target %d, mbox_current %d, diff %d\n",frame, PHY_vars_UE_g[0]->frame, slot,hw_slot,rx_offset_mbox,mbox_target,mbox_current,diff2);
        */
        vcd_signal_dumper_dump_variable_by_name(VCD_SIGNAL_DUMPER_VARIABLES_DAQ_MBOX, *((volatile unsigned int *) openair0_exmimo_pci[card].rxcnt_ptr[0]));
        vcd_signal_dumper_dump_variable_by_name(VCD_SIGNAL_DUMPER_VARIABLES_DIFF, diff2);

        delay_cnt = 0;
        while ((diff2>0) && (!oai_exit) && (is_synchronized) )
          {
            time_in = rt_get_time_ns();
            //LOG_D(HW,"eNB Frame %d delaycnt %d : hw_slot %d (%d), slot %d (%d), diff %d, time %llu\n",frame,delay_cnt,hw_slot,((volatile unsigned int *)DAQ_MBOX)[0],slot,mbox_target,diff2,time_in);
            vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_RT_SLEEP,1);
            ret = rt_sleep_ns(diff2*DAQ_PERIOD);
            vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_RT_SLEEP,0);
            if (ret)
              LOG_D(HW,"eNB Frame %d, time %llu: rt_sleep_ns returned %d\n",frame, time_in);

            hw_slot = (((((volatile unsigned int *)DAQ_MBOX)[0]+1)%150)<<1)/15;
            //LOG_D(HW,"eNB Frame %d : hw_slot %d, time %llu\n",frame,hw_slot,rt_get_time_ns());
            delay_cnt++;
            if (delay_cnt == 30)
              {
                LOG_D(HW,"UE frame %d: HW stopped ... \n",frame);
                exit_fun("[HW][UE] HW stopped");
              }
            mbox_current = ((volatile unsigned int *)DAQ_MBOX)[0];
            if ((mbox_current>=135) && (mbox_target<15)) //handle the frame wrap-arround
              diff2 = 150-mbox_current+mbox_target;
            else if ((mbox_current<15) && (mbox_target>=135))
              diff2 = -150+mbox_target-mbox_current;
            else
              diff2 = mbox_target - mbox_current;

            vcd_signal_dumper_dump_variable_by_name(VCD_SIGNAL_DUMPER_VARIABLES_DAQ_MBOX, *((volatile unsigned int *) openair0_exmimo_pci[card].rxcnt_ptr[0]));
            vcd_signal_dumper_dump_variable_by_name(VCD_SIGNAL_DUMPER_VARIABLES_DIFF, diff2);
          }
976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991
	
      }

      last_slot = (slot)%LTE_SLOTS_PER_FRAME;
      if (last_slot <0)
        last_slot+=LTE_SLOTS_PER_FRAME;
      next_slot = (slot+3)%LTE_SLOTS_PER_FRAME;

      if (is_synchronized)
        {

	  /*
          if (frame%100==0)
            LOG_D(HW,"frame %d (%d), slot %d, hw_slot %d, last_slot %d (before): DAQ_MBOX %d\n",frame, PHY_vars_UE_g[0]->frame, slot,hw_slot,last_slot,DAQ_MBOX[0]);
	  */

992
          // in = rt_get_time_ns();
993
          phy_procedures_UE_lte (last_slot, next_slot, PHY_vars_UE_g[0], 0, 0,mode,0,NULL);
994 995
          // out = rt_get_time_ns();
          // diff = out-in;
996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029

	  /*
          if (frame % 100 == 0)
            LOG_D(HW,"hw_slot %d (after): DAQ_MBOX %d\n",hw_slot,DAQ_MBOX[0]);
	  
            LOG_D(HW,"Frame %d: last_slot %d, phy_procedures_lte_ue time_in %llu, time_out %llu, diff %llu\n",
                      frame, last_slot,in,out,diff);
	  */

        }
      else   // we are not yet synchronized
        {
          hw_slot_offset = 0;

          slot = 0;
          openair0_get_frame(card);
          //          LOG_D(HW,"after get_frame\n");
          //          rt_sleep_ns(FRAME_PERIOD);
          //          LOG_D(HW,"after sleep\n");

          if (initial_sync(PHY_vars_UE_g[0],mode)==0) {
              /*
              lte_adjust_synch(&PHY_vars_UE_g[0]->lte_frame_parms,
                   PHY_vars_UE_g[0],
                   0,
                   1,
                   16384);
              */
              //for better visualization afterwards
              /*
              for (aa=0; aa<PHY_vars_UE_g[0]->lte_frame_parms.nb_antennas_rx; aa++)
              memset(PHY_vars_UE_g[0]->lte_ue_common_vars.rxdata[aa],0,
                 PHY_vars_UE_g[0]->lte_frame_parms.samples_per_tti*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*sizeof(int));
              */
1030
            if (mode == rx_calib_ue) {
winckel's avatar
winckel committed
1031
                exit_fun("[HW][UE] UE in RX calibration mode");
1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052
              }
              else {
                is_synchronized = 1;
                //start the DMA transfers
                //LOG_D(HW,"Before openair0_start_rt_acquisition \n");
                openair0_start_rt_acquisition(card);

                hw_slot_offset = (PHY_vars_UE_g[0]->rx_offset<<1) / PHY_vars_UE_g[0]->lte_frame_parms.samples_per_tti;
                LOG_D(HW,"Got synch: hw_slot_offset %d\n",hw_slot_offset);
              }
          }
          else {
            if (openair_daq_vars.freq_offset >= 0) {
              openair_daq_vars.freq_offset += 100;
              openair_daq_vars.freq_offset *= -1;
            }
            else {
              openair_daq_vars.freq_offset *= -1;
            }
            if (abs(openair_daq_vars.freq_offset) > 7500) {
              LOG_I(PHY,"[initial_sync] No cell synchronization found, abondoning\n");
gauthier's avatar
gauthier committed
1053
              mac_xface->macphy_exit("No cell synchronization found, abondoning");
1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
            }
            else {
              LOG_I(PHY,"[initial_sync] trying carrier off %d Hz\n",openair_daq_vars.freq_offset);
              for (i=0; i<4; i++) {
                if (p_exmimo_config->rf.rf_freq_rx[i])
                  p_exmimo_config->rf.rf_freq_rx[i] = carrier_freq[i]+openair_daq_vars.freq_offset;
                if (p_exmimo_config->rf.rf_freq_tx[i])
                  p_exmimo_config->rf.rf_freq_tx[i] = carrier_freq[i]+openair_daq_vars.freq_offset;
              }
              openair0_dump_config(card);
              rt_sleep_ns(FRAME_PERIOD);
            }
          }
1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077
        }

      /*
      if ((slot%2000)<10)
        LOG_D(HW,"fun0: doing very hard work\n");
      */
      slot++;
      if (slot==20) {
          slot=0;
          frame++;
      }
1078 1079 1080
#if defined(ENABLE_ITTI)
      itti_update_lte_time(frame, slot);
#endif
1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
    }
  LOG_D(HW,"UE_thread: finished, ran %d times.\n",frame);

#ifdef HARD_RT
  rt_make_soft_real_time();
#endif

  // clean task
#ifdef RTAI
  rt_task_delete(task);
#endif
  LOG_D(HW,"Task deleted. returning\n");
  return 0;
}

1096
static void get_options (int argc, char **argv)
1097
{
1098 1099 1100 1101
  int                           c;
  char                          line[1000];
  int                           l;
  const Enb_properties_array_t *enb_properties;
1102

winckel's avatar
winckel committed
1103 1104 1105
  enum long_option_e {
    LONG_OPTION_START = 0x100, /* Start after regular single char options */

1106
    LONG_OPTION_ULSCH_MAX_CONSECUTIVE_ERRORS,
winckel's avatar
winckel committed
1107 1108 1109 1110 1111 1112 1113 1114 1115
    LONG_OPTION_CALIB_UE_RX,
    LONG_OPTION_CALIB_UE_RX_MED,
    LONG_OPTION_CALIB_UE_RX_BYP,

    LONG_OPTION_DEBUG_UE_PRACH,

    LONG_OPTION_NO_L2_CONNECT,
  };

1116
  static const struct option long_options[] = {
1117 1118 1119 1120 1121 1122 1123
      {"ulsch-max-errors",required_argument,  NULL, LONG_OPTION_ULSCH_MAX_CONSECUTIVE_ERRORS},
      {"calib-ue-rx",     required_argument,  NULL, LONG_OPTION_CALIB_UE_RX},
      {"calib-ue-rx-med", required_argument,  NULL, LONG_OPTION_CALIB_UE_RX_MED},
      {"calib-ue-rx-byp", required_argument,  NULL, LONG_OPTION_CALIB_UE_RX_BYP},
      {"debug-ue-prach",  no_argument,        NULL, LONG_OPTION_DEBUG_UE_PRACH},
      {"no-L2-connect",   no_argument,        NULL, LONG_OPTION_NO_L2_CONNECT},
          {NULL, 0, NULL, 0}};
1124

1125
  while ((c = getopt_long (argc, argv, "C:dF:K:qO:ST:UVR",long_options,NULL)) != -1)
1126 1127 1128
    {
      switch (c)
        {
1129 1130 1131 1132 1133
        case LONG_OPTION_ULSCH_MAX_CONSECUTIVE_ERRORS:
          ULSCH_max_consecutive_errors = atoi(optarg);
          printf("Set ULSCH_max_consecutive_errors = %d\n",ULSCH_max_consecutive_errors);
          break;

1134 1135 1136 1137
        case LONG_OPTION_CALIB_UE_RX:
          mode = rx_calib_ue;
          rx_input_level_dBm = atoi(optarg);
          printf("Running with UE calibration on (LNA max), input level %d dBm\n",rx_input_level_dBm);
1138
          break;
1139 1140 1141 1142 1143

        case LONG_OPTION_CALIB_UE_RX_MED:
          mode = rx_calib_ue_med;
          rx_input_level_dBm = atoi(optarg);
          printf("Running with UE calibration on (LNA med), input level %d dBm\n",rx_input_level_dBm);
1144
          break;
1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159

        case LONG_OPTION_CALIB_UE_RX_BYP:
          mode = rx_calib_ue_byp;
          rx_input_level_dBm = atoi(optarg);
          printf("Running with UE calibration on (LNA byp), input level %d dBm\n",rx_input_level_dBm);
          break;

        case LONG_OPTION_DEBUG_UE_PRACH:
          mode = debug_prach;
          break;

        case LONG_OPTION_NO_L2_CONNECT:
          mode = no_L2_connect;
          break;

1160
        case 'C':
1161 1162 1163 1164
          downlink_frequency[0] = atof(optarg); // Use float to avoid issue with frequency over 2^31.
          downlink_frequency[1] = downlink_frequency[0];
          downlink_frequency[2] = downlink_frequency[0];
          downlink_frequency[3] = downlink_frequency[0];
1165 1166 1167 1168
          carrier_freq[0] = downlink_frequency[0];
          carrier_freq[1] = downlink_frequency[1];
          carrier_freq[2] = downlink_frequency[2];
          carrier_freq[3] = downlink_frequency[3];
1169
          printf("Downlink frequency set to %u\n", downlink_frequency[0]);
1170
          break;
1171 1172 1173 1174

        case 'd':
#ifdef XFORMS
          do_forms=1;
1175 1176
#endif
          break;
1177

1178 1179 1180 1181 1182 1183 1184 1185 1186
        case 'F':
          sprintf(rxg_fname,"%srxg.lime",optarg);
          rxg_fd = fopen(rxg_fname,"r");
          if (rxg_fd) {
            printf("Loading RX Gain parameters from %s\n",rxg_fname);
            l=0;
            while (fgets(line, sizeof(line), rxg_fd)) {
              if ((strlen(line)==0) || (*line == '#')) continue; //ignore empty or comment lines
              else {
1187 1188 1189 1190
                if (l==0) sscanf(line,"%d %d %d %d",&rxg_max[0],&rxg_max[1],&rxg_max[2],&rxg_max[3]);
                if (l==1) sscanf(line,"%d %d %d %d",&rxg_med[0],&rxg_med[1],&rxg_med[2],&rxg_med[3]);
                if (l==2) sscanf(line,"%d %d %d %d",&rxg_byp[0],&rxg_byp[1],&rxg_byp[2],&rxg_byp[3]);
                l++;
1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203
              }
            }
          }
          else
            printf("%s not found, running with defaults\n",rxg_fname);

          sprintf(txg_fname,"%stxg.lime",optarg);
          txg_fd = fopen(txg_fname,"r");
          if (txg_fd) {
            printf("Loading TX Gain parameters from %s\n",txg_fname);
            l=0;
            while (fgets(line, sizeof(line), txg_fd)) {
              if ((strlen(line)==0) || (*line == '#')) {
1204
                continue; //ignore empty or comment lines
1205 1206
              }
              else {
1207 1208 1209
                if (l==0) sscanf(line,"%d %d %d %d",&txgain[0],&txgain[1],&txgain[2],&txgain[3]);
                if (l==1) sscanf(line,"%d",&tx_max_power);
                l++;
1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234
              }
            }
          }
          else
            printf("%s not found, running with defaults\n",txg_fname);

          sprintf(rflo_fname,"%srflo.lime",optarg);
          rflo_fd = fopen(rflo_fname,"r");
          if (rflo_fd) {
            printf("Loading RF LO parameters from %s\n",rflo_fname);
            if (fscanf(rflo_fd,"%d %d %d %d",&rf_local[0],&rf_local[1],&rf_local[2],&rf_local[3]) < 4)
                  LOG_E(EMU, "Error parsing \"%s\"", rflo_fname);
          }
          else
            printf("%s not found, running with defaults\n",rflo_fname);

          sprintf(rfdc_fname,"%srfdc.lime",optarg);
          rfdc_fd = fopen(rfdc_fname,"r");
          if (rfdc_fd) {
            printf("Loading RF DC parameters from %s\n",rfdc_fname);
            if (fscanf(rfdc_fd,"%d %d %d %d",&rf_rxdc[0],&rf_rxdc[1],&rf_rxdc[2],&rf_rxdc[3]) < 4)
              LOG_E(EMU, "Error parsing \"%s\"", rfdc_fname);
          }
          else
            printf("%s not found, running with defaults\n",rfdc_fname);
1235
          break;
1236

1237 1238 1239 1240 1241 1242
        case 'K':
#if defined(ENABLE_ITTI)
          itti_dump_file = strdup(optarg);
#else
          printf("-K option is disabled when ENABLE_ITTI is not defined\n");
#endif
1243
          break;
1244 1245 1246

        case 'O':
          conf_config_file_name = optarg;
1247
          break;
1248 1249 1250

        case 'S':
          fs4_test=1;
1251
          break;
1252 1253 1254 1255 1256

        case 'T':
#ifdef ENABLE_TCXO
          tcxo=atoi(optarg);
#endif
1257
          break;
1258 1259 1260

        case 'U':
          UE_flag = 1;
1261
          break;
1262 1263 1264

        case 'V':
          ouput_vcd = 1;
1265
          break;
1266
	case  'q': 
1267 1268
	  opp_enabled = 1;
	  break;
1269
	case  'R' :
1270
	  online_log_messages =1;
1271
	  break;
1272 1273 1274 1275 1276
        default:
          break;
        }
    }

1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294
  if ((UE_flag == 0) && (conf_config_file_name != NULL)) {
    int i;

    NB_eNB_INST = 1;

    /* Read eNB configuration file */
    enb_properties = enb_config_init(conf_config_file_name);

    AssertFatal (NB_eNB_INST <= enb_properties->number,
                 "Number of eNB is greater than eNB defined in configuration file %s (%d/%d)!",
                 conf_config_file_name, NB_eNB_INST, enb_properties->number);

    /* Update some simulation parameters */
    frame_parms->frame_type =       enb_properties->properties[0]->frame_type;
    frame_parms->tdd_config =       enb_properties->properties[0]->tdd_config;
    frame_parms->tdd_config_S =     enb_properties->properties[0]->tdd_config_s;
    for (i = 0 ; i < (sizeof(downlink_frequency) / sizeof (downlink_frequency[0])); i++) {
      downlink_frequency[i] =       enb_properties->properties[0]->downlink_frequency;
1295
      printf("Downlink frequency set to %u\n", downlink_frequency[i]);
1296 1297 1298
      uplink_frequency_offset[i] =  enb_properties->properties[0]->uplink_frequency_offset;
    }
  }
1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309
}

int main(int argc, char **argv) {
#ifdef RTAI
  // RT_TASK *task;
#endif
  int i,j,aa;
#if defined (XFORMS) || defined (EMOS) || (! defined (RTAI))
  void *status;
#endif

gauthier's avatar
gauthier committed
1310 1311
  uint16_t Nid_cell = 0;
  uint8_t  cooperation_flag=0, transmission_mode=1, abstraction_flag=0;
1312
#ifndef OPENAIR2
gauthier's avatar
gauthier committed
1313
  uint8_t beta_ACK=0,beta_RI=0,beta_CQI=2;
1314 1315 1316 1317 1318 1319 1320
#endif

#ifdef ENABLE_TCXO
  unsigned int tcxo = 114;
#endif

  int amp;
gauthier's avatar
gauthier committed
1321
  // uint8_t prach_fmt;
1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332
  // int N_ZC;

  int ret, ant;
  int ant_offset=0;

#if defined (EMOS) || (! defined (RTAI))
  int error_code;
#endif

  mode = normal_txrx;

1333
  frame_parms = (LTE_DL_FRAME_PARMS*) malloc(sizeof(LTE_DL_FRAME_PARMS));
1334
  /* Set some default values that may be overwritten while reading options */
1335
  frame_parms->frame_type         = 1; /* TDD */
1336 1337
  frame_parms->tdd_config         = 3;
  frame_parms->tdd_config_S       = 0;
1338

1339
  get_options (argc, argv); //Command-line options
1340

winckel's avatar
winckel committed
1341 1342 1343 1344 1345 1346
  //randominit (0);
  set_taus_seed (0);

  // initialize the log (see log.h for details)
  logInit();

1347
  set_glog(LOG_WARNING, LOG_MED);
1348
  if (UE_flag==1)
1349
  {
1350
    printf("configuring for UE\n");
1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363

    set_comp_log(HW,      LOG_DEBUG,  LOG_HIGH, 1);
#ifdef OPENAIR2
    set_comp_log(PHY,     LOG_INFO,   LOG_HIGH, 1);
#else
    set_comp_log(PHY,     LOG_INFO,   LOG_HIGH, 1);
#endif
    set_comp_log(MAC,     LOG_INFO,   LOG_HIGH, 1);
    set_comp_log(RLC,     LOG_INFO,   LOG_HIGH, 1);
    set_comp_log(PDCP,    LOG_INFO,   LOG_HIGH, 1);
    set_comp_log(OTG,     LOG_INFO,   LOG_HIGH, 1);
    set_comp_log(RRC,     LOG_INFO,   LOG_HIGH, 1);
#if defined(ENABLE_ITTI)
1364
    set_comp_log(EMU,     LOG_INFO,   LOG_MED, 1);
1365 1366 1367 1368 1369
# if defined(ENABLE_USE_MME)
    set_comp_log(NAS,     LOG_INFO,   LOG_HIGH, 1);
# endif
#endif
  }
1370
  else
1371
  {
1372 1373
    printf("configuring for eNB\n");

1374 1375 1376 1377 1378 1379 1380
    set_comp_log(HW,      LOG_DEBUG,  LOG_HIGH, 1);
#ifdef OPENAIR2
    set_comp_log(PHY,     LOG_INFO,   LOG_HIGH, 1);
#else
    set_comp_log(PHY,     LOG_INFO,   LOG_HIGH, 1);
#endif
    set_comp_log(MAC,     LOG_INFO,   LOG_HIGH, 1);
1381
    set_comp_log(RLC,     LOG_TRACE,   LOG_HIGH, 1);
1382
    set_comp_log(PDCP,    LOG_DEBUG,   LOG_HIGH, 1);
1383
    set_comp_log(OTG,     LOG_INFO,   LOG_HIGH, 1);
1384
    set_comp_log(RRC,     LOG_DEBUG,   LOG_HIGH, 1);
1385
#if defined(ENABLE_ITTI)
1386
    set_comp_log(EMU,     LOG_INFO,   LOG_MED, 1);