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

  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
knopp's avatar
 
knopp committed
31 32 33 34 35 36 37 38 39
 * \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
 */
knopp's avatar
 
knopp committed
40
#define _GNU_SOURCE
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
#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"
56 57
#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all

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

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

#include "PHY/types.h"
65

66
#include "PHY/defs.h"
67 68 69
#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

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

#include "PHY/vars.h"
#include "MAC_INTERFACE/vars.h"
75
//#include "SCHED/defs.h"
76 77 78 79 80 81 82 83 84 85
#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
86
#include "otg_tx.h"
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
#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"
104
#include "enb_config.h"
105

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

114 115 116
#ifdef XFORMS
#include "PHY/TOOLS/lte_phy_scope.h"
#include "stats.h"
117 118 119 120 121
#endif

#define FRAME_PERIOD    100000000ULL
#define DAQ_PERIOD      66667ULL

knopp's avatar
 
knopp committed
122 123
#define DEBUG_THREADS 1

124 125 126 127 128 129 130
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
void cleanup_rx_pdsch_thread(void);
knopp's avatar
 
knopp committed
138 139


knopp's avatar
 
knopp committed
140 141
s32 *rxdata;
s32 *txdata;
142 143 144 145
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);

#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

knopp's avatar
 
knopp committed
169 170 171 172 173
pthread_attr_t                  attr_eNB_proc_tx[10];
pthread_attr_t                  attr_eNB_proc_rx[10];
struct sched_param              sched_param_eNB_proc_tx[10];
struct sched_param              sched_param_eNB_proc_rx[10];

174 175 176 177 178 179
#ifdef XFORMS
static pthread_t                thread2; //xforms
#endif
#ifdef EMOS
static pthread_t                thread3; //emos
#endif
180

knopp's avatar
 
knopp committed
181 182 183
openair0_device openair0;
openair0_timestamp timestamp;

184
/*
knopp's avatar
 
knopp committed
185 186 187
  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;
188 189 190 191
*/
//extern unsigned int bigphys_top;
//extern unsigned int mem_base;

192
int                             card = 0;
knopp's avatar
 
knopp committed
193

194

195
#if defined(ENABLE_ITTI)
196 197
static volatile int             start_eNB = 0;
static volatile int             start_UE = 0;
198
#endif
199 200 201 202 203 204
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};

knopp's avatar
 
knopp committed
205

206
static char                     UE_flag=0;
gauthier's avatar
gauthier committed
207
static uint8_t                       eNB_id=0,UE_id=0;
208

gauthier's avatar
gauthier committed
209
uint32_t                             carrier_freq[4] =           {1907600000,1907600000,1907600000,1907600000}; /* For UE! */
210
static uint32_t          downlink_frequency[4] =     {1907600000,1907600000,1907600000,1907600000};
gauthier's avatar
gauthier committed
211
static int32_t                      uplink_frequency_offset[4]= {-120000000,-120000000,-120000000,-120000000};
212 213
static char                    *conf_config_file_name = NULL;

knopp's avatar
 
knopp committed
214
#ifdef ITTI_ENABLED
215
static char                    *itti_dump_file = NULL;
knopp's avatar
 
knopp committed
216 217 218 219
#endif

double tx_gain = 50;
double rx_gain = 30;
knopp's avatar
 
knopp committed
220

221

knopp's avatar
 
knopp committed
222
#ifndef USRP
223 224 225 226
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;
227

knopp's avatar
 
knopp committed
228

knopp's avatar
 
knopp committed
229
#else
knopp's avatar
 
knopp committed
230
double sample_rate=30.72e6;
knopp's avatar
 
knopp committed
231 232 233 234
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;
knopp's avatar
 
knopp committed
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
double bw = 14e6;
char ref[128] = "internal";
char channels[128] = "0";

int samples_per_frame = 307200;
int samples_per_packets = 2048; // samples got every recv or send
int tx_forward_nsamps;

int sf_bounds_5[10] = {8, 15, 23, 30, 38, 45, 53, 60, 68, 75};
int sf_bounds_10[10] = {8, 15, 23, 30, 38, 45, 53, 60, 68, 75};
int sf_bounds_20[10] = {15, 30, 45, 60, 75, 90, 105, 120, 135, 150};
int *sf_bounds;
int max_cnt;
int tx_delay;

#endif
251
/*
knopp's avatar
 
knopp committed
252 253 254
  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};
255
*/
knopp's avatar
 
knopp committed
256 257
//static uint32_t                      rf_mode[4] =        {MY_RF_MODE,0,0,0};
//static uint32_t                      rf_local[4] =       {8255000,8255000,8255000,8255000}; // UE zepto
knopp's avatar
 
knopp committed
258 259
//{8254617, 8254617, 8254617, 8254617}; //eNB khalifa
//{8255067,8254810,8257340,8257340}; // eNB PETRONAS
260

knopp's avatar
 
knopp committed
261 262 263 264 265
//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};
266 267 268

static runmode_t                mode;
static int                      rx_input_level_dBm;
269
static int                      online_log_messages=0;
270
#ifdef XFORMS
271
extern int                      otg_enabled;
272
static char                     do_forms=0;
273
#else
274
int                             otg_enabled;
275
#endif
knopp's avatar
 
knopp committed
276
//int                             number_of_cards =   1;
277

278 279
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
280

281
static LTE_DL_FRAME_PARMS      *frame_parms;
282

knopp's avatar
 
knopp committed
283
int multi_thread=0;
knopp's avatar
 
knopp committed
284
int N_RB_DL=25;
knopp's avatar
 
knopp committed
285

286
unsigned int build_rflocal(int txi, int txq, int rxi, int rxq)
287
{
knopp's avatar
 
knopp committed
288
  return (txi + (txq<<6) + (rxi<<12) + (rxq<<18));
289 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 297 298 299 300 301 302 303 304 305 306 307 308 309 310
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 {
311
    oai_exit = 1;
312 313
  }
}
314
#endif
315 316 317

void exit_fun(const char* s)
{
318
  if (s != NULL) {
gauthier's avatar
gauthier committed
319
    printf("%s %s() Exiting: %s\n",__FILE__, __FUNCTION__, s);
320 321 322 323 324
  }

  oai_exit = 1;

#if defined(ENABLE_ITTI)
325
  itti_terminate_tasks (TASK_UNKNOWN);
326
#endif
327 328 329 330 331 332 333

  //rt_sleep_ns(FRAME_PERIOD);

  //exit (-1);
}

#ifdef XFORMS
334
static void *scope_thread(void *arg) {
knopp's avatar
 
knopp committed
335
  char stats_buffer[16384];
336
# ifdef ENABLE_XFORMS_WRITE_STATS
knopp's avatar
 
knopp committed
337 338
  FILE *UE_stats, *eNB_stats;
  int len = 0;
339
# endif
knopp's avatar
 
knopp committed
340
  struct sched_param sched_param;
341

knopp's avatar
 
knopp committed
342 343
  sched_param.sched_priority = sched_get_priority_min(SCHED_FIFO)+1; 
  sched_setscheduler(0, SCHED_FIFO,&sched_param);
344

knopp's avatar
 
knopp committed
345
  printf("Scope thread has priority %d\n",sched_param.sched_priority);
346
    
knopp's avatar
 
knopp committed
347 348 349 350 351 352
  /*
    if (UE_flag==1) 
    UE_stats  = fopen("UE_stats.txt", "w");
    else 
    eNB_stats = fopen("eNB_stats.txt", "w");
  */
353
    
knopp's avatar
 
knopp committed
354 355
  while (!oai_exit) {
    if (UE_flag==1) {
356
# ifdef ENABLE_XFORMS_WRITE_STATS
knopp's avatar
 
knopp committed
357
      len =
358
# endif
knopp's avatar
 
knopp committed
359 360
	dump_ue_stats (PHY_vars_UE_g[0], stats_buffer, 0, mode,rx_input_level_dBm);
      fl_set_object_label(form_stats->stats_text, stats_buffer);
361
# ifdef ENABLE_XFORMS_WRITE_STATS
knopp's avatar
 
knopp committed
362 363
      rewind (UE_stats);
      fwrite (stats_buffer, 1, len, UE_stats);
364
# endif
knopp's avatar
 
knopp committed
365 366 367 368
      phy_scope_UE(form_ue[UE_id], 
		   PHY_vars_UE_g[UE_id],
		   eNB_id,
		   UE_id,7);
369
            
knopp's avatar
 
knopp committed
370
    } else {
371
# ifdef ENABLE_XFORMS_WRITE_STATS
knopp's avatar
 
knopp committed
372
      len =
373
# endif
knopp's avatar
 
knopp committed
374 375
	dump_eNB_stats (PHY_vars_eNB_g[0], stats_buffer, 0);
      fl_set_object_label(form_stats->stats_text, stats_buffer);
376
# ifdef ENABLE_XFORMS_WRITE_STATS
knopp's avatar
 
knopp committed
377 378
      rewind (eNB_stats);
      fwrite (stats_buffer, 1, len, eNB_stats);
379
# endif
knopp's avatar
 
knopp committed
380 381 382 383 384
      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);
      }
385 386
              
    }
knopp's avatar
 
knopp committed
387 388 389
    //printf("doing forms\n");
    usleep(100000); // 100 ms
  }
390
    
391
# ifdef ENABLE_XFORMS_WRITE_STATS
knopp's avatar
 
knopp committed
392 393
  fclose (UE_stats);
  fclose (eNB_stats);
394
# endif
395
    
knopp's avatar
 
knopp committed
396
  pthread_exit((void*)arg);
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423
}
#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;
424 425 426 427 428 429 430

  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);
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
 
  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);
    }
453 454
  else 
    printf("[EMOS] Opened GPS, gps_data=%p\n");
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
  
  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;

      /*
knopp's avatar
 
knopp committed
500
	if (UE_flag==0)
501
	printf("eNB: count %d, frame %d, read: %d bytes from the fifo\n",counter, ((fifo_dump_emos_eNB*)fifo2file_ptr)->frame_tx,bytes);
knopp's avatar
 
knopp committed
502
	else
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 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
	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

564
#if defined(ENABLE_ITTI)
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582
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

knopp's avatar
 
knopp committed
583
#if defined(ENABLE_ITTI)
584
void *l2l1_task(void *arg)
585
{
knopp's avatar
 
knopp committed
586 587 588 589 590
  MessageDef *message_p = NULL;
  int         result;

  itti_set_task_real_time(TASK_L2L1);
  itti_mark_task_ready(TASK_L2L1);
591

knopp's avatar
 
knopp committed
592 593
  if (UE_flag == 0) {
    /* Wait for the initialize message */
594
    do {
knopp's avatar
 
knopp committed
595 596 597 598
      if (message_p != NULL) {
	result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p);
	AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
      }
599 600 601
      itti_receive_msg (TASK_L2L1, &message_p);

      switch (ITTI_MSG_ID(message_p)) {
knopp's avatar
 
knopp committed
602 603 604 605 606 607 608 609 610 611 612 613 614 615
      case INITIALIZE_MESSAGE:
	/* Start eNB thread */
	LOG_D(EMU, "L2L1 TASK received %s\n", ITTI_MSG_NAME(message_p));
	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;
616
      }
knopp's avatar
 
knopp committed
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
    } while (ITTI_MSG_ID(message_p) != INITIALIZE_MESSAGE);
    result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p);
    AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
  }

  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;
639

knopp's avatar
 
knopp committed
640 641 642 643 644 645 646 647 648 649 650 651
    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);
  } while(1);
652

knopp's avatar
 
knopp committed
653
  return NULL;
654 655 656
}
#endif

knopp's avatar
 
knopp committed
657 658 659 660 661 662 663 664 665 666 667 668 669 670

void do_OFDM_mod(int subframe,PHY_VARS_eNB *phy_vars_eNB) {

  unsigned int aa,slot_offset, slot_offset_F;
  int dummy_tx_b[7680*4] __attribute__((aligned(16)));
  int i, tx_offset;

  slot_offset_F = (subframe<<1)*
    (phy_vars_eNB->lte_frame_parms.ofdm_symbol_size)*
    ((phy_vars_eNB->lte_frame_parms.Ncp==1) ? 6 : 7);
  slot_offset = (subframe<<1)*
    (phy_vars_eNB->lte_frame_parms.samples_per_tti>>1);
  if ((subframe_select(&phy_vars_eNB->lte_frame_parms,subframe)==SF_DL)||
      ((subframe_select(&phy_vars_eNB->lte_frame_parms,subframe)==SF_S))) {
knopp's avatar
 
knopp committed
671
    //	  LOG_D(HW,"Frame %d: Generating slot %d\n",frame,next_slot);
knopp's avatar
 
knopp committed
672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709
      
    for (aa=0; aa<phy_vars_eNB->lte_frame_parms.nb_antennas_tx; aa++) {
      if (phy_vars_eNB->lte_frame_parms.Ncp == EXTENDED){ 
	PHY_ofdm_mod(&phy_vars_eNB->lte_eNB_common_vars.txdataF[0][aa][slot_offset_F],
		     dummy_tx_b,
		     phy_vars_eNB->lte_frame_parms.log2_symbol_size,
		     6,
		     phy_vars_eNB->lte_frame_parms.nb_prefix_samples,
		     phy_vars_eNB->lte_frame_parms.twiddle_ifft,
		     phy_vars_eNB->lte_frame_parms.rev,
		     CYCLIC_PREFIX);
      }
      else {
	normal_prefix_mod(&phy_vars_eNB->lte_eNB_common_vars.txdataF[0][aa][slot_offset_F],
			  dummy_tx_b,
			  7,
			  &(phy_vars_eNB->lte_frame_parms));
      }
#ifdef EXMIMO
      for (i=0; i<phy_vars_eNB->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->lte_frame_parms.samples_per_tti;
	if (tx_offset>=(LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->lte_frame_parms.samples_per_tti))
	  tx_offset -= LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->lte_frame_parms.samples_per_tti;
	((short*)&phy_vars_eNB->lte_eNB_common_vars.txdata[0][aa][tx_offset])[0]=
	  ((short*)dummy_tx_b)[2*i]<<4;
	((short*)&phy_vars_eNB->lte_eNB_common_vars.txdata[0][aa][tx_offset])[1]=
	  ((short*)dummy_tx_b)[2*i+1]<<4;
      }
#endif //EXMIMO
    }
  }
}


int eNB_thread_tx_status[10];
static void * eNB_thread_tx(void *param) {
knopp's avatar
 
knopp committed
710 711 712

  //unsigned long cpuid;
  eNB_proc_t *proc = (eNB_proc_t*)param;
knopp's avatar
 
knopp committed
713 714 715
  int i;
  int subframe_tx;
  //  RTIME time_in,time_out;
knopp's avatar
 
knopp committed
716 717 718 719 720 721 722
#ifdef RTAI
  RT_TASK *task;
  char task_name[8];
#endif
  int dummy_tx_b[7680*4] __attribute__((aligned(16)));
  unsigned int aa,slot_offset,slot_offset_F,slot_offset_F2;

knopp's avatar
 
knopp committed
723 724 725 726 727
#if defined(ENABLE_ITTI)
  /* Wait for eNB application initialization to be complete (eNB registration to MME) */
  wait_system_ready ("Waiting for eNB application to be ready %s\r", &start_eNB);
#endif

knopp's avatar
 
knopp committed
728
#ifdef RTAI
knopp's avatar
 
knopp committed
729
  sprintf(task_name,"eNB_proc_TX %d",proc->subframe);
knopp's avatar
 
knopp committed
730 731 732
  task = rt_task_init_schmod(nam2num(task_name), 0, 0, 0, SCHED_FIFO, 0xF);

  if (task==NULL) {
knopp's avatar
 
knopp committed
733
    LOG_E(PHY,"[SCHED][eNB] Problem starting eNB_proc_TX thread_index %d (%s)!!!!\n",proc->subframe,task_name);
knopp's avatar
 
knopp committed
734 735 736
    return 0;
  }
  else {
knopp's avatar
 
knopp committed
737
    LOG_I(PHY,"[SCHED][eNB] eNB TX thread %d started with id %p on CPU %d\n",
knopp's avatar
 
knopp committed
738
	  proc->subframe,
knopp's avatar
 
knopp committed
739
	  task,rtai_cpuid());
knopp's avatar
 
knopp committed
740
  }
knopp's avatar
 
knopp committed
741 742 743
#else
  LOG_I(PHY,"[SCHED][eNB] eNB TX thread %d started on CPU %d\n",
	proc->subframe,sched_getcpu());
knopp's avatar
 
knopp committed
744 745 746 747 748 749 750 751 752 753 754 755
#endif

  mlockall(MCL_CURRENT | MCL_FUTURE);

  //rt_set_runnable_on_cpuid(task,1);
  //cpuid = rtai_cpuid();

#ifdef HARD_RT
  rt_make_hard_real_time();
#endif


knopp's avatar
 
knopp committed
756
  subframe_tx = (proc->subframe+1)%10;
knopp's avatar
 
knopp committed
757
  
knopp's avatar
 
knopp committed
758
  while (!oai_exit){
knopp's avatar
 
knopp committed
759
    
knopp's avatar
 
knopp committed
760
    vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_TX0+(2*proc->subframe),0);
knopp's avatar
 
knopp committed
761 762
    
    
knopp's avatar
 
knopp committed
763 764 765
    //    LOG_I(PHY,"Locking mutex for eNB proc %d (IC %d,mutex %p)\n",proc->subframe,proc->instance_cnt,&proc->mutex);
    if (pthread_mutex_lock(&proc->mutex_tx) != 0) {
      LOG_E(PHY,"[SCHED][eNB] error locking mutex for eNB TX proc %d\n",proc->subframe);
knopp's avatar
 
knopp committed
766 767
    }
    else {
knopp's avatar
 
knopp committed
768
      
knopp's avatar
 
knopp committed
769 770
      while (proc->instance_cnt_tx < 0) {
	//	LOG_I(PHY,"Waiting and unlocking mutex for eNB proc %d (IC %d,lock %d)\n",proc->subframe,proc->instance_cnt,pthread_mutex_trylock(&proc->mutex));
knopp's avatar
 
knopp committed
771
	
knopp's avatar
 
knopp committed
772
	pthread_cond_wait(&proc->cond_tx,&proc->mutex_tx);
knopp's avatar
 
knopp committed
773
      }
knopp's avatar
 
knopp committed
774 775 776
      //      LOG_I(PHY,"Waking up and unlocking mutex for eNB proc %d\n",proc->subframe);
      if (pthread_mutex_unlock(&proc->mutex_tx) != 0) {	
	LOG_E(PHY,"[SCHED][eNB] error unlocking mutex for eNB TX proc %d\n",proc->subframe);
knopp's avatar
 
knopp committed
777 778
      }
    }
knopp's avatar
 
knopp committed
779 780 781
    vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_TX0+(2*proc->subframe),1);    
    vcd_signal_dumper_dump_variable_by_name(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_ENB, proc->frame_tx);
    vcd_signal_dumper_dump_variable_by_name(VCD_SIGNAL_DUMPER_VARIABLES_SLOT_NUMBER_ENB, proc->subframe*2);
knopp's avatar
 
knopp committed
782
    
knopp's avatar
 
knopp committed
783 784
    if (oai_exit) break;
    
knopp's avatar
 
knopp committed
785
    if ((((PHY_vars_eNB_g[0]->lte_frame_parms.frame_type == TDD)&&(subframe_select(&PHY_vars_eNB_g[0]->lte_frame_parms,subframe_tx)==SF_DL))||
knopp's avatar
 
knopp committed
786
	 (PHY_vars_eNB_g[0]->lte_frame_parms.frame_type == FDD))) {
knopp's avatar
 
knopp committed
787
      phy_procedures_eNB_TX(subframe_tx,PHY_vars_eNB_g[0],0,no_relay,NULL);
knopp's avatar
 
knopp committed
788
    }
knopp's avatar
 
knopp committed
789 790
    if ((subframe_select(&PHY_vars_eNB_g[0]->lte_frame_parms,subframe_tx)==SF_S)) {
      phy_procedures_eNB_TX(subframe_tx,PHY_vars_eNB_g[0],0,no_relay,NULL);
knopp's avatar
 
knopp committed
791
    }
knopp's avatar
 
knopp committed
792
    do_OFDM_mod(subframe_tx,PHY_vars_eNB_g[0]);  
knopp's avatar
 
knopp committed
793
    
knopp's avatar
 
knopp committed
794 795
    if (pthread_mutex_lock(&proc->mutex_tx) != 0) {
      printf("[openair][SCHED][eNB] error locking mutex for eNB TX proc %d\n",proc->subframe);
knopp's avatar
 
knopp committed
796
    }
knopp's avatar
 
knopp committed
797 798
    else {
      proc->instance_cnt_tx--;
knopp's avatar
 
knopp committed
799
      
knopp's avatar
 
knopp committed
800 801 802 803
      if (pthread_mutex_unlock(&proc->mutex_tx) != 0) {	
	printf("[openair][SCHED][eNB] error unlocking mutex for eNB TX proc %d\n",proc->subframe);
      }
    }
knopp's avatar
 
knopp committed
804
    
knopp's avatar
 
knopp committed
805 806 807
    proc->frame_tx++;
    if (proc->frame_tx==1024)
      proc->frame_tx=0;
knopp's avatar
 
knopp committed
808
  }    
knopp's avatar
 
knopp committed
809 810 811 812
  vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_TX0+(2*proc->subframe),0);        
#ifdef HARD_RT
  rt_make_soft_real_time();
#endif
knopp's avatar
 
knopp committed
813
  
knopp's avatar
 
knopp committed
814 815 816 817 818 819 820 821 822 823
#ifdef DEBUG_THREADS
  printf("Exiting eNB thread TX %d\n",proc->subframe);
#endif
  // clean task
#ifdef RTAI
  rt_task_delete(task);
#else
  eNB_thread_tx_status[proc->subframe]=0;
  pthread_exit(&eNB_thread_tx_status[proc->subframe]);
#endif
knopp's avatar
 
knopp committed
824
  
knopp's avatar
 
knopp committed
825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892
#ifdef DEBUG_THREADS
  printf("Exiting eNB TX thread %d\n",proc->subframe);
#endif
}

int eNB_thread_rx_status[10];
static void * eNB_thread_rx(void *param) {

  //unsigned long cpuid;
  eNB_proc_t *proc = (eNB_proc_t*)param;
  int i;
  int subframe_rx;
  //  RTIME time_in,time_out;
#ifdef RTAI
  RT_TASK *task;
  char task_name[8];
#endif

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

#ifdef RTAI
  sprintf(task_name,"eNB_proc_RX %d",proc->subframe);
  task = rt_task_init_schmod(nam2num(task_name), 0, 0, 0, SCHED_FIFO, 0xF);

  if (task==NULL) {
    LOG_E(PHY,"[SCHED][eNB] Problem starting eNB_proc_RX thread_index %d (%s)!!!!\n",proc->subframe,task_name);
    return 0;
  }
  else {
    LOG_I(PHY,"[SCHED][eNB] eNB RX thread %d started with id %p on CPU %d\n",
	  proc->subframe,
	  task,rtai_cpuid());
  }
#else
  LOG_I(PHY,"[SCHED][eNB] eNB RX thread %d started on CPU %d\n",
	proc->subframe,sched_getcpu());
#endif

  mlockall(MCL_CURRENT | MCL_FUTURE);

  //rt_set_runnable_on_cpuid(task,1);
  //cpuid = rtai_cpuid();

#ifdef HARD_RT
  rt_make_hard_real_time();
#endif


  subframe_rx = (proc->subframe+9)%10;

  while (!oai_exit){

    vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RX0+(2*proc->subframe),0);


    //    LOG_I(PHY,"Locking mutex for eNB proc %d (IC %d,mutex %p)\n",proc->subframe,proc->instance_cnt,&proc->mutex);
    if (pthread_mutex_lock(&proc->mutex_rx) != 0) {
      LOG_E(PHY,"[SCHED][eNB] error locking mutex for eNB RX proc %d\n",proc->subframe);
    }
    else {
        
      while (proc->instance_cnt_rx < 0) {
	//	LOG_I(PHY,"Waiting and unlocking mutex for eNB proc %d (IC %d,lock %d)\n",proc->subframe,proc->instance_cnt,pthread_mutex_trylock(&proc->mutex));

	pthread_cond_wait(&proc->cond_rx,&proc->mutex_rx);
knopp's avatar
 
knopp committed
893
      }
knopp's avatar
 
knopp committed
894 895 896
      //      LOG_I(PHY,"Waking up and unlocking mutex for eNB proc %d\n",proc->subframe);
      if (pthread_mutex_unlock(&proc->mutex_rx) != 0) {	
	LOG_E(PHY,"[SCHED][eNB] error unlocking mutex for eNB RX proc %d\n",proc->subframe);
knopp's avatar
 
knopp committed
897 898
      }
    }
knopp's avatar
 
knopp committed
899 900 901 902 903 904 905 906 907 908 909 910 911 912
    vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RX0+(2*proc->subframe),1);    

    if (oai_exit) break;
    
    if ((((PHY_vars_eNB_g[0]->lte_frame_parms.frame_type == TDD )&&(subframe_select(&PHY_vars_eNB_g[0]->lte_frame_parms,subframe_rx)==SF_UL)) ||
	 (PHY_vars_eNB_g[0]->lte_frame_parms.frame_type == FDD))){
      phy_procedures_eNB_RX(subframe_rx,PHY_vars_eNB_g[0],0,no_relay);
    }
    if ((subframe_select(&PHY_vars_eNB_g[0]->lte_frame_parms,subframe_rx)==SF_S)){
      phy_procedures_eNB_S_RX(subframe_rx,PHY_vars_eNB_g[0],0,no_relay);
    }
      
    if (pthread_mutex_lock(&proc->mutex_rx) != 0) {
      printf("[openair][SCHED][eNB] error locking mutex for eNB RX proc %d\n",proc->subframe);
knopp's avatar
 
knopp committed
913 914
    }
    else {
knopp's avatar
 
knopp committed
915
      proc->instance_cnt_rx--;
knopp's avatar
 
knopp committed
916
      
knopp's avatar
 
knopp committed
917 918
      if (pthread_mutex_unlock(&proc->mutex_rx) != 0) {	
	printf("[openair][SCHED][eNB] error unlocking mutex for eNB RX proc %d\n",proc->subframe);
knopp's avatar
 
knopp committed
919 920
      }
    }
knopp's avatar
 
knopp committed
921 922 923 924

    proc->frame_rx++;
    if (proc->frame_rx==1024)
      proc->frame_rx=0;
knopp's avatar
 
knopp committed
925
    
knopp's avatar
 
knopp committed
926 927
  }
  vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RX0+(2*proc->subframe),0);        
knopp's avatar
 
knopp committed
928
#ifdef HARD_RT
knopp's avatar
 
knopp committed
929 930 931 932 933 934 935 936 937 938 939 940
  rt_make_soft_real_time();
#endif

#ifdef DEBUG_THREADS
  printf("Exiting eNB thread RX %d\n",proc->subframe);
#endif
  // clean task
#ifdef RTAI
  rt_task_delete(task);
#else
  eNB_thread_rx_status[proc->subframe]=0;
  pthread_exit(&eNB_thread_rx_status[proc->subframe]);
knopp's avatar
 
knopp committed
941 942
#endif

knopp's avatar
 
knopp committed
943 944 945
#ifdef DEBUG_THREADS
  printf("Exiting eNB RX thread %d\n",proc->subframe);
#endif
knopp's avatar
 
knopp committed
946 947 948 949 950 951 952 953
}



void init_eNB_proc() {

  int i;

knopp's avatar
 
knopp committed
954 955


knopp's avatar
 
knopp committed
956
  for (i=0;i<10;i++) {
knopp's avatar
 
knopp committed
957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972
    pthread_attr_init (&attr_eNB_proc_tx[i]);
    pthread_attr_setstacksize(&attr_eNB_proc_tx[i],OPENAIR_THREAD_STACK_SIZE);
    //attr_dlsch_threads.priority = 1;
    sched_param_eNB_proc_tx[i].sched_priority = sched_get_priority_max(SCHED_FIFO)-1; //OPENAIR_THREAD_PRIORITY;
    pthread_attr_setschedparam  (&attr_eNB_proc_tx[i], &sched_param_eNB_proc_tx);
    pthread_attr_setschedpolicy (&attr_eNB_proc_tx[i], SCHED_FIFO);

    pthread_attr_init (&attr_eNB_proc_rx[i]);
    pthread_attr_setstacksize(&attr_eNB_proc_rx[i],OPENAIR_THREAD_STACK_SIZE);
    //attr_dlsch_threads.priority = 1;
    sched_param_eNB_proc_rx[i].sched_priority = sched_get_priority_max(SCHED_FIFO)-1; //OPENAIR_THREAD_PRIORITY;
    pthread_attr_setschedparam  (&attr_eNB_proc_rx[i], &sched_param_eNB_proc_rx);
    pthread_attr_setschedpolicy (&attr_eNB_proc_rx[i], SCHED_FIFO);

    PHY_vars_eNB_g[0]->proc[i].instance_cnt_tx=-1;
    PHY_vars_eNB_g[0]->proc[i].instance_cnt_rx=-1;
knopp's avatar
 
knopp committed
973
    PHY_vars_eNB_g[0]->proc[i].subframe=i;
knopp's avatar
 
knopp committed
974 975 976 977 978 979
    pthread_mutex_init(&PHY_vars_eNB_g[0]->proc[i].mutex_tx,NULL);
    pthread_mutex_init(&PHY_vars_eNB_g[0]->proc[i].mutex_rx,NULL);
    pthread_cond_init(&PHY_vars_eNB_g[0]->proc[i].cond_tx,NULL);
    pthread_cond_init(&PHY_vars_eNB_g[0]->proc[i].cond_rx,NULL);
    pthread_create(&PHY_vars_eNB_g[0]->proc[i].pthread_tx,NULL,eNB_thread_tx,(void*)&PHY_vars_eNB_g[0]->proc[i]);
    pthread_create(&PHY_vars_eNB_g[0]->proc[i].pthread_rx,NULL,eNB_thread_rx,(void*)&PHY_vars_eNB_g[0]->proc[i]);
knopp's avatar
 
knopp committed
980 981 982 983 984 985
  }
}

void kill_eNB_proc() {

  int i;
knopp's avatar
 
knopp committed
986
  int *status_tx,*status_rx;
knopp's avatar
 
knopp committed
987 988

  for (i=0;i<10;i++) {
knopp's avatar
 
knopp committed
989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011

#ifdef DEBUG_THREADS
    printf("Killing TX thread %d\n",i);
#endif
    PHY_vars_eNB_g[0]->proc[i].instance_cnt_tx=0; 
    pthread_cond_signal(&PHY_vars_eNB_g[0]->proc[i].cond_tx);
#ifdef DEBUG_THREADS
    printf("Joining eNB TX thread %d...",i);
#endif
    pthread_join(PHY_vars_eNB_g[0]->proc[i].pthread_tx,(void**)status_tx);
#ifdef DEBUG_THREADS
    if (status_tx) printf("status %d...",*status_tx);
#endif
#ifdef DEBUG_THREADS
    printf("Killing RX thread %d\n",i);
#endif
    PHY_vars_eNB_g[0]->proc[i].instance_cnt_rx=0; 
    pthread_cond_signal(&PHY_vars_eNB_g[0]->proc[i].cond_rx);
#ifdef DEBUG_THREADS
    printf("Joining eNB RX thread %d...",i);
#endif
    pthread_join(PHY_vars_eNB_g[0]->proc[i].pthread_rx,(void**)status_rx);
#ifdef DEBUG_THREADS 
knopp's avatar
 
knopp committed
1012
    if (status_rx) printf("status %d...",*status_rx);
knopp's avatar
 
knopp committed
1013 1014 1015 1016 1017
#endif
    pthread_mutex_destroy(&PHY_vars_eNB_g[0]->proc[i].mutex_tx);
    pthread_mutex_destroy(&PHY_vars_eNB_g[0]->proc[i].mutex_rx);
    pthread_cond_destroy(&PHY_vars_eNB_g[0]->proc[i].cond_tx);
    pthread_cond_destroy(&PHY_vars_eNB_g[0]->proc[i].cond_rx);
knopp's avatar
 
knopp committed
1018 1019 1020 1021
  }
}


knopp's avatar
 
knopp committed
1022 1023


knopp's avatar
 
knopp committed
1024 1025
  
/* This is the main eNB thread. */
knopp's avatar
 
knopp committed
1026 1027
int eNB_thread_status;

knopp's avatar
 
knopp committed
1028

1029 1030 1031 1032 1033
static void *eNB_thread(void *arg)
{
#ifdef RTAI
  RT_TASK *task;
#endif
knopp's avatar
 
knopp committed
1034
  unsigned char slot=0;//,last_slot, next_slot;
1035 1036 1037 1038 1039
  int hw_slot,frame=0;
  int diff;
  int delay_cnt;
  RTIME time_in, time_diff;
  int mbox_target=0,mbox_current=0;
knopp's avatar
 
knopp committed
1040 1041 1042
  int i;//
  int ret;
  //  int tx_offset;
knopp's avatar
 
knopp committed
1043
  int sf;
knopp's avatar
 
knopp committed
1044
#ifndef USRP
knopp's avatar
 
knopp committed
1045
  volatile unsigned int *DAQ_MBOX = openair0_daq_cnt();
knopp's avatar
 
knopp committed
1046 1047 1048 1049
#else
  int rx_cnt = 0;
  int tx_cnt = tx_delay;
  hw_subframe = 0;
knopp's avatar
 
knopp committed
1050
#endif
1051 1052
#if defined(ENABLE_ITTI)
  /* Wait for eNB application initialization to be complete (eNB registration to MME) */
1053
  wait_system_ready ("Waiting for eNB application to be ready %s\r", &start_eNB);
1054 1055
#endif

1056
#ifdef RTAI
knopp's avatar
 
knopp committed
1057
  task = rt_task_init_schmod(nam2num("TASK0"), 0, 0, 0, SCHED_FIFO, 0xF);
1058 1059 1060 1061
#endif

  if (!oai_exit) {
#ifdef RTAI
knopp's avatar
 
knopp committed
1062 1063 1064 1065
    LOG_D(HW,"[SCHED][eNB] Started eNB thread (id %p) on CPU %d\n",task,rtai_cpuid());
#else
    LOG_I(HW,"[SCHED][eNB] Started eNB thread on CPU %d\n",
	  sched_getcpu());
1066 1067 1068
#endif

#ifdef HARD_RT
1069
    rt_make_hard_real_time();
1070 1071
#endif

1072
    mlockall(MCL_CURRENT | MCL_FUTURE);
1073

1074 1075 1076 1077
    timing_info.time_min = 100000000ULL;
    timing_info.time_max = 0;
    timing_info.time_avg = 0;
    timing_info.n_samples = 0;
1078

knopp's avatar
 
knopp committed
1079
    while (!oai_exit) {
knopp's avatar
 
knopp committed
1080 1081

#ifndef USRP
knopp's avatar
 
knopp committed
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112
      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) {
	  exit_fun("[HW][eNB] missed slot");
	}
	if (slot==20){
	  slot=0;
	  frame++;
	}
	continue;
      }
      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);
      
knopp's avatar
 
knopp committed
1113
      vcd_signal_dumper_dump_variable_by_name(VCD_SIGNAL_DUMPER_VARIABLES_DAQ_MBOX, *DAQ_MBOX);
knopp's avatar
 
knopp committed
1114 1115 1116 1117 1118 1119 1120 1121 1122 1123
      vcd_signal_dumper_dump_variable_by_name(VCD_SIGNAL_DUMPER_VARIABLES_DIFF, diff);
      
      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);
	vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_RT_SLEEP,1);
	ret = rt_sleep_ns(diff*DAQ_PERIOD);
	vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_RT_SLEEP,0);
knopp's avatar
 
knopp committed
1124
	vcd_signal_dumper_dump_variable_by_name(VCD_SIGNAL_DUMPER_VARIABLES_DAQ_MBOX, *DAQ_MBOX);
knopp's avatar
 
knopp committed
1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135
	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);
	  exit_fun("[HW][eNB] HW stopped");
	}
	mbox_current = ((volatile unsigned int *)DAQ_MBOX)[0];
	if ((mbox_current>=135) && (mbox_target<15)) //handle the frame wrap-arround
knopp's avatar
 
knopp committed
1136
	  diff = 150-mbox_current+mbox_target;
knopp's avatar
 
knopp committed
1137
	else if ((mbox_current<15) && (mbox_target>=135))
knopp's avatar
 
knopp committed
1138
	  diff = -150+mbox_target-mbox_current;
knopp's avatar
 
knopp committed
1139
	else
knopp's avatar
 
knopp committed
1140
	  diff = mbox_target - mbox_current;
knopp's avatar
 
knopp committed
1141
      }
knopp's avatar
 
knopp committed
1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162

#else  // USRP
      while (rx_cnt < sf_bounds[hw_subframe]) {
	openair0.trx_read_func(&openair0, &timestamp, &rxdata[rx_cnt*samples_per_packets], samples_per_packets);

	openair0.trx_write_func(&openair0, (timestamp+samples_per_packets*tx_delay-tx_forward_nsamps), &txdata[tx_cnt*samples_per_packets], samples_per_packets, 1);

	rx_cnt++;
	tx_cnt++;
      }

#ifndef RTAI
      //pthread_mutex_lock(&tti_mutex);
#endif
      hw_subframe++;
      slot+=2;
      if(hw_subframe==10)
        hw_subframe = 0;

#endif // USRP
     
knopp's avatar
 
knopp committed
1163
      if (oai_exit) break;
1164

knopp's avatar
 
knopp committed
1165
      if (frame>5)  {
knopp's avatar
 
knopp committed
1166

knopp's avatar
 
knopp committed
1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
	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;
	}
	
	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;
	  }
	*/
	//}
	
	if (multi_thread == 0) {
	  phy_procedures_eNB_lte (((slot+1)%20)>>1, PHY_vars_eNB_g[0], 0, no_relay,NULL);
	  do_OFDM_mod(((slot+1)%20)>>1,PHY_vars_eNB_g[0]);
	}
	else { // multi-thread > 0
	  if ((slot&1) == 0) {
	    sf = ((slot>>1)+1)%10;
	    //		    LOG_I(PHY,"[eNB] Multithread slot %d (IC %d)\n",slot,PHY_vars_eNB_g[0]->proc[sf].instance_cnt);
	    
	    if (pthread_mutex_lock(&PHY_vars_eNB_g[0]->proc[sf].mutex_tx) != 0) {
	      LOG_E(PHY,"[eNB] ERROR pthread_mutex_lock for eNB TX thread %d (IC %d)\n",sf,PHY_vars_eNB_g[0]->proc[sf].instance_cnt_tx);   
knopp's avatar
 
knopp committed
1202
	    }
knopp's avatar
 
knopp committed
1203 1204 1205 1206 1207 1208 1209
	    else {
	      //		      LOG_I(PHY,"[eNB] Waking up eNB process %d (IC %d)\n",sf,PHY_vars_eNB_g[0]->proc[sf].instance_cnt); 
	      PHY_vars_eNB_g[0]->proc[sf].instance_cnt_tx++;
	      pthread_mutex_unlock(&PHY_vars_eNB_g[0]->proc[sf].mutex_tx);
	      if (PHY_vars_eNB_g[0]->proc[sf].instance_cnt_tx == 0) {
		if (pthread_cond_signal(&PHY_vars_eNB_g[0]->proc[sf].cond_tx) != 0) {
		  LOG_E(PHY,"[eNB] ERROR pthread_cond_signal for eNB TX thread %d\n",sf);
knopp's avatar
 
knopp committed
1210
		}
knopp's avatar
 
knopp committed
1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226
	      }
	      else {
		LOG_W(PHY,"[eNB] Frame %d, eNB TX thread %d busy!!\n",PHY_vars_eNB_g[0]->proc[sf].frame_tx,sf);
	      }
	    }
	    
	    if (pthread_mutex_lock(&PHY_vars_eNB_g[0]->proc[sf].mutex_rx) != 0) {
	      LOG_E(PHY,"[eNB] ERROR pthread_mutex_lock for eNB RX thread %d (IC %d)\n",sf,PHY_vars_eNB_g[0]->proc[sf].instance_cnt_rx);   
	    }
	    else {
	      //		      LOG_I(PHY,"[eNB] Waking up eNB process %d (IC %d)\n",sf,PHY_vars_eNB_g[0]->proc[sf].instance_cnt); 
	      PHY_vars_eNB_g[0]->proc[sf].instance_cnt_rx++;
	      pthread_mutex_unlock(&PHY_vars_eNB_g[0]->proc[sf].mutex_rx);
	      if (PHY_vars_eNB_g[0]->proc[sf].instance_cnt_rx == 0) {
		if (pthread_cond_signal(&PHY_vars_eNB_g[0]->proc[sf].cond_rx) != 0) {
		  LOG_E(PHY,"[eNB] ERROR pthread_cond_signal for eNB RX thread %d\n",sf);
knopp's avatar
 
knopp committed
1227 1228
		}
	      }
knopp's avatar
 
knopp committed
1229 1230 1231
	      else {
		LOG_W(PHY,"[eNB] Frame %d, eNB RX thread %d busy!!\n",PHY_vars_eNB_g[0]->proc[sf].frame_rx,sf);
	      }
knopp's avatar
 
knopp committed
1232
	    }
knopp's avatar
 
knopp committed
1233 1234 1235 1236
	    
	  }
	}
      }
knopp's avatar
 
knopp committed
1237
#ifndef USRP
knopp's avatar
 
knopp committed
1238
      slot++;
knopp's avatar
 
knopp committed
1239 1240 1241 1242 1243 1244
#else
      if(rx_cnt == max_cnt) {
	rx_cnt = 0;
      } 
#endif     

knopp's avatar
 
knopp committed
1245 1246 1247 1248
      if (slot==20) {
	slot=0;
	frame++;
      }
1249
#if defined(ENABLE_ITTI)
knopp's avatar
 
knopp committed
1250
      itti_update_lte_time(frame, slot);
1251
#endif
knopp's avatar
 
knopp committed
1252 1253 1254 1255 1256 1257
    }
  }
#ifdef DEBUG_THREADS
  printf("eNB_thread: finished, ran %d times.\n",frame);
#endif
  
1258
#ifdef HARD_RT
knopp's avatar
 
knopp committed
1259
  rt_make_soft_real_time();
1260 1261
#endif

knopp's avatar
 
knopp committed
1262 1263 1264 1265 1266

#ifdef DEBUG_THREADS
  printf("Exiting eNB_thread ...");
#endif
  // clean task
1267
#ifdef RTAI
knopp's avatar
 
knopp committed
1268 1269 1270 1271
  rt_task_delete(task);
#else
  eNB_thread_status = 0;
  pthread_exit(&eNB_thread_status);
1272
#endif
knopp's avatar
 
knopp committed
1273 1274 1275 1276 1277
#ifdef DEBUG_THREADS
  printf("eNB_thread deleted. returning\n");
#endif
  return 0;
}
1278

knopp's avatar