lte-ue.c 54.9 KB
Newer Older
1
/*******************************************************************************
2
    OpenAirInterface
3 4 5 6 7 8 9 10 11 12 13 14 15 16
    Copyright(c) 1999 - 2014 Eurecom

    OpenAirInterface is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.


    OpenAirInterface is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
17 18
    along with OpenAirInterface.The full GNU General Public License is
    included in this distribution in the file called "COPYING". If not,
19 20 21 22 23
    see <http://www.gnu.org/licenses/>.

   Contact Information
   OpenAirInterface Admin: openair_admin@eurecom.fr
   OpenAirInterface Tech : openair_tech@eurecom.fr
24
   OpenAirInterface Dev  : openair4g-devel@lists.eurecom.fr
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 55
   Address      : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE

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

/*! \file lte-ue.c
 * \brief threads and support functions for real-time LTE UE target
 * \author R. Knopp, F. Kaltenberger, Navid Nikaein
 * \date 2015
 * \version 0.1
 * \company Eurecom
 * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr, navid.nikaein@eurecom.fr
 * \note
 * \warning
 */
#define _GNU_SOURCE
#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 <linux/sched.h>
#include <signal.h>
#include <execinfo.h>
#include <getopt.h>
#include <syscall.h>
56
#include <sys/sysinfo.h>
57 58 59 60 61 62

#include "rt_wrapper.h"
#include "assertions.h"
#include "PHY/types.h"

#include "PHY/defs.h"
knopp's avatar
knopp committed
63
#ifdef OPENAIR2
64 65
#include "LAYER2/MAC/defs.h"
#include "RRC/LITE/extern.h"
knopp's avatar
knopp committed
66
#endif
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
#include "PHY_INTERFACE/extern.h"

#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

#include "../../ARCH/COMMON/common_lib.h"

#include "PHY/extern.h"
#include "SCHED/extern.h"
#include "LAYER2/MAC/extern.h"
#include "LAYER2/MAC/proto.h"

#include "UTIL/LOG/log_extern.h"
#include "UTIL/OTG/otg_tx.h"
#include "UTIL/OTG/otg_externs.h"
#include "UTIL/MATH/oml.h"
#include "UTIL/LOG/vcd_signal_dumper.h"
#include "UTIL/OPT/opt.h"

#define FRAME_PERIOD    100000000ULL
#define DAQ_PERIOD      66667ULL

typedef enum {
  pss=0,
  pbch=1,
  si=2
} sync_mode_t;

knopp's avatar
knopp committed
95
void init_UE_threads(int nb_inst);
96
void *UE_thread(void *arg);
knopp's avatar
knopp committed
97
void init_UE(int nb_inst);
98 99 100 101 102

extern pthread_cond_t sync_cond;
extern pthread_mutex_t sync_mutex;
extern int sync_var;

103

104 105
extern openair0_config_t openair0_cfg[MAX_CARDS];
extern uint32_t          downlink_frequency[MAX_NUM_CCs][4];
106
extern int32_t           uplink_frequency_offset[MAX_NUM_CCs][4];
107 108 109 110 111
extern int oai_exit;

extern int32_t **rxdata;
extern int32_t **txdata;

112 113
//extern unsigned int tx_forward_nsamps;
//extern int tx_delay;
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139

extern int rx_input_level_dBm;
extern uint8_t exit_missed_slots;
extern uint64_t num_missed_slots; // counter for the number of missed slots

extern void exit_fun(const char* s);

#define KHz (1000UL)
#define MHz (1000 * KHz)

typedef struct eutra_band_s {
  int16_t band;
  uint32_t ul_min;
  uint32_t ul_max;
  uint32_t dl_min;
  uint32_t dl_max;
  lte_frame_type_t frame_type;
} eutra_band_t;

typedef struct band_info_s {
  int nbands;
  eutra_band_t band_info[100];
} band_info_t;

band_info_t bands_to_scan;

140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
static const eutra_band_t eutra_bands[] = {
  { 1, 1920    * MHz, 1980    * MHz, 2110    * MHz, 2170    * MHz, FDD},
  { 2, 1850    * MHz, 1910    * MHz, 1930    * MHz, 1990    * MHz, FDD},
  { 3, 1710    * MHz, 1785    * MHz, 1805    * MHz, 1880    * MHz, FDD},
  { 4, 1710    * MHz, 1755    * MHz, 2110    * MHz, 2155    * MHz, FDD},
  { 5,  824    * MHz,  849    * MHz,  869    * MHz,  894    * MHz, FDD},
  { 6,  830    * MHz,  840    * MHz,  875    * MHz,  885    * MHz, FDD},
  { 7, 2500    * MHz, 2570    * MHz, 2620    * MHz, 2690    * MHz, FDD},
  { 8,  880    * MHz,  915    * MHz,  925    * MHz,  960    * MHz, FDD},
  { 9, 1749900 * KHz, 1784900 * KHz, 1844900 * KHz, 1879900 * KHz, FDD},
  {10, 1710    * MHz, 1770    * MHz, 2110    * MHz, 2170    * MHz, FDD},
  {11, 1427900 * KHz, 1452900 * KHz, 1475900 * KHz, 1500900 * KHz, FDD},
  {12,  698    * MHz,  716    * MHz,  728    * MHz,  746    * MHz, FDD},
  {13,  777    * MHz,  787    * MHz,  746    * MHz,  756    * MHz, FDD},
  {14,  788    * MHz,  798    * MHz,  758    * MHz,  768    * MHz, FDD},
  {17,  704    * MHz,  716    * MHz,  734    * MHz,  746    * MHz, FDD},
  {20,  832    * MHz,  862    * MHz,  791    * MHz,  821    * MHz, FDD},
157
  {22, 3510    * MHz, 3590    * MHz, 3410    * MHz, 3490    * MHz, FDD},
158 159 160 161 162 163 164 165 166 167 168 169 170 171
  {33, 1900    * MHz, 1920    * MHz, 1900    * MHz, 1920    * MHz, TDD},
  {34, 2010    * MHz, 2025    * MHz, 2010    * MHz, 2025    * MHz, TDD},
  {35, 1850    * MHz, 1910    * MHz, 1850    * MHz, 1910    * MHz, TDD},
  {36, 1930    * MHz, 1990    * MHz, 1930    * MHz, 1990    * MHz, TDD},
  {37, 1910    * MHz, 1930    * MHz, 1910    * MHz, 1930    * MHz, TDD},
  {38, 2570    * MHz, 2620    * MHz, 2570    * MHz, 2630    * MHz, TDD},
  {39, 1880    * MHz, 1920    * MHz, 1880    * MHz, 1920    * MHz, TDD},
  {40, 2300    * MHz, 2400    * MHz, 2300    * MHz, 2400    * MHz, TDD},
  {41, 2496    * MHz, 2690    * MHz, 2496    * MHz, 2690    * MHz, TDD},
  {42, 3400    * MHz, 3600    * MHz, 3400    * MHz, 3600    * MHz, TDD},
  {43, 3600    * MHz, 3800    * MHz, 3600    * MHz, 3800    * MHz, TDD},
  {44, 703    * MHz, 803    * MHz, 703    * MHz, 803    * MHz, TDD},
};

172 173 174 175
pthread_t                       main_ue_thread;
pthread_attr_t                  attr_UE_thread;
struct sched_param              sched_param_UE_thread;

knopp's avatar
knopp committed
176
void init_UE(int nb_inst) {
177 178

  int error_code;
knopp's avatar
knopp committed
179 180
  int inst;
  PHY_VARS_UE *UE;
knopp's avatar
knopp committed
181
  int ret;
knopp's avatar
knopp committed
182 183 184 185 186 187

  for (inst=0;inst<nb_inst;inst++) {
    printf("Intializing UE Threads for instance %d ...\n",inst);
    init_UE_threads(inst);
    sleep(1);
    UE = PHY_vars_UE_g[inst][0];
knopp's avatar
knopp committed
188 189 190

    ret = openair0_device_load(&(UE->rfdevice), &openair0_cfg[0]);
    UE->rfdevice.host_type = BBU_HOST;
knopp's avatar
knopp committed
191
    //    UE->rfdevice.type      = NONE_DEV;
knopp's avatar
knopp committed
192 193 194 195 196 197 198 199 200
    error_code = pthread_create(&UE->proc.pthread_ue, &UE->proc.attr_ue, UE_thread, NULL);
    
    if (error_code!= 0) {
      LOG_D(HW,"[lte-softmodem.c] Could not allocate UE_thread, error %d\n",error_code);
      return;
    } else {
      LOG_D(HW, "[lte-softmodem.c] Allocate UE_thread successful\n" );
      pthread_setname_np( UE->proc.pthread_ue, "main UE" );
    }
201 202 203 204 205 206 207 208 209 210 211 212 213
  }

  printf("UE threads created\n");
#ifdef USE_MME
  
  while (start_UE == 0) {
    sleep(1);
  }
  
#endif
  
}

214 215
/*!
 * \brief This is the UE synchronize thread.
216
 * It performs band scanning and synchonization.
217 218 219
 * \param arg is a pointer to a \ref PHY_VARS_UE structure.
 * \returns a pointer to an int. The storage is not on the heap and must not be freed.
 */
220 221
static void *UE_thread_synch(void *arg)
{
222 223 224
  static int UE_thread_synch_retval;
  int i, hw_slot_offset;
  PHY_VARS_UE *UE = (PHY_VARS_UE*) arg;
225 226
  int current_band = 0;
  int current_offset = 0;
227
  sync_mode_t sync_mode = pbch;
228
  int card;
229 230
  int ind;
  int found;
231
  int freq_offset=0;
232 233 234 235 236

  UE->is_synchronized = 0;
  printf("UE_thread_sync in with PHY_vars_UE %p\n",arg);
  printf("waiting for sync (UE_thread_synch) \n");

laurent's avatar
laurent committed
237
#ifndef DEADLINE_SCHEDULER
238 239 240 241 242 243 244 245 246
  int policy, s, j;
  struct sched_param sparam;
  char cpu_affinity[1024];
  cpu_set_t cpuset;

  /* Set affinity mask to include CPUs 1 to MAX_CPUS */
  /* CPU 0 is reserved for UHD threads */
  CPU_ZERO(&cpuset);

247 248
  #ifdef CPU_AFFINITY
  if (get_nprocs() >2)
249
  {
250 251 252 253 254 255 256 257 258
    for (j = 1; j < get_nprocs(); j++)
      CPU_SET(j, &cpuset);

    s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
    if (s != 0)
    {
      perror( "pthread_setaffinity_np");
      exit_fun("Error setting processor affinity");
    }
259
  }
260 261
  #endif

262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
  /* Check the actual affinity mask assigned to the thread */

  s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
  if (s != 0)
  {
    perror( "pthread_getaffinity_np");
    exit_fun("Error getting processor affinity ");
  }
  memset(cpu_affinity, 0 , sizeof(cpu_affinity));
  for (j = 0; j < CPU_SETSIZE; j++)
  if (CPU_ISSET(j, &cpuset))
  {  
     char temp[1024];
     sprintf(temp, " CPU_%d ", j);    
     strcat(cpu_affinity, temp);
  }

  memset(&sparam, 0 , sizeof (sparam));
  sparam.sched_priority = sched_get_priority_max(SCHED_FIFO)-1;
  policy = SCHED_FIFO ; 
  
  s = pthread_setschedparam(pthread_self(), policy, &sparam);
  if (s != 0)
     {
     perror("pthread_setschedparam : ");
     exit_fun("Error setting thread priority");
     }
  s = pthread_getschedparam(pthread_self(), &policy, &sparam);
  if (s != 0)
   {
     perror("pthread_getschedparam : ");
     exit_fun("Error getting thread priority");

   }

  LOG_I( HW, "[SCHED][UE] Started UE synch thread on CPU %d TID %ld , sched_policy = %s, priority = %d, CPU Affinity = %s \n", (int)sched_getcpu(), gettid(),
                   (policy == SCHED_FIFO)  ? "SCHED_FIFO" :
                   (policy == SCHED_RR)    ? "SCHED_RR" :
                   (policy == SCHED_OTHER) ? "SCHED_OTHER" :
                   "???",
                   (int) sparam.sched_priority, cpu_affinity);

#endif


307

308

309
  printf("starting UE synch thread (IC %d)\n",UE->proc.instance_cnt_synch);
310 311
  ind = 0;
  found = 0;
312 313


314 315
  if (UE->UE_scan == 0) {
    do  {
316
      current_band = eutra_bands[ind].band;
knopp's avatar
knopp committed
317
      printf( "Scanning band %d, dl_min %"PRIu32", ul_min %"PRIu32"\n", current_band, eutra_bands[ind].dl_min,eutra_bands[ind].ul_min);
318

319
      if ((eutra_bands[ind].dl_min <= downlink_frequency[0][0]) && (eutra_bands[ind].dl_max >= downlink_frequency[0][0])) {
320 321 322 323 324 325 326
        for (card=0; card<MAX_NUM_CCs; card++)
          for (i=0; i<4; i++)
            uplink_frequency_offset[card][i] = eutra_bands[ind].ul_min - eutra_bands[ind].dl_min;

        found = 1;
        break;
      }
327

328
      ind++;
329 330
    } while (ind < sizeof(eutra_bands) / sizeof(eutra_bands[0]));
  
331 332
    if (found == 0) {
      exit_fun("Can't find EUTRA band for frequency");
333
      return &UE_thread_synch_retval;
334
    }
335

336 337


338

339 340


knopp's avatar
knopp committed
341
    LOG_I( PHY, "[SCHED][UE] Check absolute frequency DL %"PRIu32", UL %"PRIu32" (oai_exit %d)\n", downlink_frequency[0][0], downlink_frequency[0][0]+uplink_frequency_offset[0][0],oai_exit );
342 343 344 345 346

    for (i=0;i<openair0_cfg[0].rx_num_channels;i++) {
      openair0_cfg[0].rx_freq[i] = downlink_frequency[0][i];
      openair0_cfg[0].tx_freq[i] = downlink_frequency[0][i]+uplink_frequency_offset[0][i];
      openair0_cfg[0].autocal[i] = 1;
347 348 349 350
      if (uplink_frequency_offset[0][i] != 0) // 
	openair0_cfg[0].duplex_mode = duplex_mode_FDD;
      else //FDD
	openair0_cfg[0].duplex_mode = duplex_mode_TDD;
351 352
    }

353
    sync_mode = pbch;
354

355
  } else if  (UE->UE_scan == 1) {
356
    current_band=0;
357

358
    for (card=0; card<MAX_CARDS; card++) {
359
      for (i=0; i<openair0_cfg[card].rx_num_channels; i++) {
360 361 362 363 364
        downlink_frequency[card][i] = bands_to_scan.band_info[0].dl_min;
        uplink_frequency_offset[card][i] = bands_to_scan.band_info[0].ul_min-bands_to_scan.band_info[0].dl_min;

        openair0_cfg[card].rx_freq[i] = downlink_frequency[card][i];
        openair0_cfg[card].tx_freq[i] = downlink_frequency[card][i]+uplink_frequency_offset[card][i];
365
        openair0_cfg[card].rx_gain[i] = UE->rx_total_gain_dB;
366
        printf( "UE synch: setting RX gain (%d,%d) to %f\n", card, i, openair0_cfg[card].rx_gain[i] );
367
      }
368 369 370
    }

  }
371

knopp's avatar
knopp committed
372

373 374 375 376 377 378 379 380 381
  pthread_mutex_lock(&sync_mutex);
  printf("Locked sync_mutex, waiting (UE_sync_thread)\n");

  while (sync_var<0)
    pthread_cond_wait(&sync_cond, &sync_mutex);

  pthread_mutex_unlock(&sync_mutex);
  printf("Started device, unlocked sync_mutex (UE_sync_thread)\n");

knopp's avatar
knopp committed
382 383 384 385 386
  if (UE->rfdevice.trx_start_func(&UE->rfdevice) != 0 ) { 
    LOG_E(HW,"Could not start the device\n");
    oai_exit=1;
  }

387
  while (oai_exit==0) {
388

389
    if (pthread_mutex_lock(&UE->proc.mutex_synch) != 0) {
390
      LOG_E( PHY, "[SCHED][UE] error locking mutex for UE initial synch thread\n" );
391
      exit_fun("noting to add");
392 393
      return &UE_thread_synch_retval;
    }
394
    
395

396
    while (UE->proc.instance_cnt_synch < 0) {
397
      // the thread waits here most of the time
398
      pthread_cond_wait( &UE->proc.cond_synch, &UE->proc.mutex_synch );
399
    }
400

401
    if (pthread_mutex_unlock(&UE->proc.mutex_synch) != 0) {
402 403 404 405
      LOG_E( PHY, "[SCHED][eNB] error unlocking mutex for UE Initial Synch thread\n" );
      exit_fun("nothing to add");
      return &UE_thread_synch_retval;
    }
406

407
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_SYNCH, 1 );
408 409

    switch (sync_mode) {
410
    case pss:
411 412
      LOG_I(PHY,"[SCHED][UE] Scanning band %d (%d), freq %u\n",bands_to_scan.band_info[current_band].band, current_band,bands_to_scan.band_info[current_band].dl_min+current_offset);
      lte_sync_timefreq(UE,current_band,bands_to_scan.band_info[current_band].dl_min+current_offset);
413 414 415 416 417 418 419
      current_offset += 20000000; // increase by 20 MHz

      if (current_offset > bands_to_scan.band_info[current_band].dl_max-bands_to_scan.band_info[current_band].dl_min) {
        current_band++;
        current_offset=0;
      }

420
      if (current_band==bands_to_scan.nbands) {
421 422
        current_band=0;
        oai_exit=1;
423
      }
424 425 426 427 428 429 430

      for (card=0; card<MAX_CARDS; card++) {
        for (i=0; i<openair0_cfg[card].rx_num_channels; i++) {
          downlink_frequency[card][i] = bands_to_scan.band_info[current_band].dl_min+current_offset;
          uplink_frequency_offset[card][i] = bands_to_scan.band_info[current_band].ul_min-bands_to_scan.band_info[0].dl_min + current_offset;


431 432
          openair0_cfg[card].rx_freq[i] = downlink_frequency[card][i];
          openair0_cfg[card].tx_freq[i] = downlink_frequency[card][i]+uplink_frequency_offset[card][i];
433
          openair0_cfg[card].rx_gain[i] = UE->rx_total_gain_dB;
434
          printf("UE synch: setting RX gain (%d,%d) to %f\n",card,i,openair0_cfg[card].rx_gain[i]);
435
        }
436 437 438

      }

439
      if (UE->UE_scan_carrier) {
440

441 442 443 444
	for (i=0;i<openair0_cfg[0].rx_num_channels;i++)
	  openair0_cfg[0].autocal[i] = 1;

      }
445

446 447 448

      break;
 
449
    case pbch:
450

Rohit Gupta's avatar
Rohit Gupta committed
451
      LOG_I(PHY,"[UE thread Synch] Running Initial Synch (mode %d)\n",UE->mode);
452
      if (initial_sync( UE, UE->mode ) == 0) {
453

454
        hw_slot_offset = (UE->rx_offset<<1) / UE->frame_parms.samples_per_tti;
455 456 457 458 459 460
        LOG_I( HW, "Got synch: hw_slot_offset %d\n", hw_slot_offset );
	if (UE->UE_scan_carrier == 1) {

	  UE->UE_scan_carrier = 0;
	  // rerun with new cell parameters and frequency-offset
	  for (i=0;i<openair0_cfg[0].rx_num_channels;i++) {
461
	    openair0_cfg[0].rx_gain[i] = UE->rx_total_gain_dB;//-USRP_GAIN_OFFSET;
462
	    openair0_cfg[0].rx_freq[i] -= UE->common_vars.freq_offset;
463 464 465 466 467
	    openair0_cfg[0].tx_freq[i] =  openair0_cfg[0].rx_freq[i]+uplink_frequency_offset[0][i];
	    downlink_frequency[0][i] = openair0_cfg[0].rx_freq[i];
	    freq_offset=0;	    
	  }

468
	  // reconfigure for potentially different bandwidth
469
	  switch(UE->frame_parms.N_RB_DL) {
470 471
	  case 6:
	    openair0_cfg[0].sample_rate =1.92e6;
472 473
	    openair0_cfg[0].rx_bw          =.96e6;
	    openair0_cfg[0].tx_bw          =.96e6;
474
	    //            openair0_cfg[0].rx_gain[0] -= 12;
475 476
	    break;
	  case 25:
477 478 479
	    openair0_cfg[0].sample_rate =7.68e6;
	    openair0_cfg[0].rx_bw          =2.5e6;
	    openair0_cfg[0].tx_bw          =2.5e6;
480
	    //            openair0_cfg[0].rx_gain[0] -= 6;
481 482
	    break;
	  case 50:
483 484 485
	    openair0_cfg[0].sample_rate =15.36e6;
	    openair0_cfg[0].rx_bw          =5.0e6;
	    openair0_cfg[0].tx_bw          =5.0e6;
486
	    //            openair0_cfg[0].rx_gain[0] -= 3;
487 488 489
	    break;
	  case 100:
	    openair0_cfg[0].sample_rate=30.72e6;
490 491
	    openair0_cfg[0].rx_bw=10.0e6;
	    openair0_cfg[0].tx_bw=10.0e6;
492
	    //            openair0_cfg[0].rx_gain[0] -= 0;
493 494
	    break;
	  }
495

Rohit Gupta's avatar
Rohit Gupta committed
496
	  UE->rfdevice.trx_set_freq_func(&UE->rfdevice,&openair0_cfg[0],0);
knopp's avatar
knopp committed
497 498
	  //UE->rfdevice.trx_set_gains_func(&openair0,&openair0_cfg[0]);
	  UE->rfdevice.trx_stop_func(&UE->rfdevice);	  
499
	  sleep(1);
500
	  init_frame_parms(&UE->frame_parms,1);
knopp's avatar
knopp committed
501
	  if (UE->rfdevice.trx_start_func(&UE->rfdevice) != 0 ) { 
502 503 504
	    LOG_E(HW,"Could not start the device\n");
	    oai_exit=1;
	  }
505 506 507
	}
	else {
	  UE->is_synchronized = 1;
508

509 510
	  if( UE->mode == rx_dump_frame ){
	    FILE *fd;
511
	    if ((UE->proc.proc_rxtx[0].frame_rx&1) == 0) {  // this guarantees SIB1 is present 
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529
	      if ((fd = fopen("rxsig_frame0.dat","w")) != NULL) {
		fwrite((void*)&UE->common_vars.rxdata[0][0],
		       sizeof(int32_t),
		       10*UE->frame_parms.samples_per_tti,
		       fd);
		LOG_I(PHY,"Dummping Frame ... bye bye \n");
		fclose(fd);
		exit(0);
	      }
	      else {
		LOG_E(PHY,"Cannot open file for writing\n");
		exit(0);
	      }
	    }
	    else {
	      UE->is_synchronized = 0;
	    }
	  }
530
	}
531 532 533
      } else {
        // initial sync failed
        // calculate new offset and try again
534 535 536 537 538 539 540 541 542 543
	if (UE->UE_scan_carrier == 1) {
	  if (freq_offset >= 0) {
	    freq_offset += 100;
	    freq_offset *= -1;
	  } else {
	    freq_offset *= -1;
	  }
	
	  if (abs(freq_offset) > 7500) {
	    LOG_I( PHY, "[initial_sync] No cell synchronization found, abandoning\n" );
544
	    FILE *fd;
545
	    if ((fd = fopen("rxsig_frame0.dat","w"))!=NULL) {
546
	      fwrite((void*)&UE->common_vars.rxdata[0][0],
547
		     sizeof(int32_t),
548
		     10*UE->frame_parms.samples_per_tti,
549 550 551 552 553
		     fd);
	      LOG_I(PHY,"Dummping Frame ... bye bye \n");
	      fclose(fd);
	      exit(0);
	    }
554 555 556 557 558 559 560 561 562
	    mac_xface->macphy_exit("No cell synchronization found, abandoning");
	    return &UE_thread_synch_retval; // not reached
	  }
	}
	else {
	  
	}
        LOG_I( PHY, "[initial_sync] trying carrier off %d Hz, rxgain %d (DL %u, UL %u)\n", 
	       freq_offset,
563
               UE->rx_total_gain_dB,
564 565
               downlink_frequency[0][0]+freq_offset,
               downlink_frequency[0][0]+uplink_frequency_offset[0][0]+freq_offset );
566 567 568

        for (card=0; card<MAX_CARDS; card++) {
          for (i=0; i<openair0_cfg[card].rx_num_channels; i++) {
569 570
            openair0_cfg[card].rx_freq[i] = downlink_frequency[card][i]+freq_offset;
            openair0_cfg[card].tx_freq[i] = downlink_frequency[card][i]+uplink_frequency_offset[card][i]+freq_offset;
571

572

573
	    
574 575 576 577

            openair0_cfg[card].rx_gain[i] = UE->rx_total_gain_dB;//-USRP_GAIN_OFFSET;
	    
	    
578 579
          }
        }
knopp's avatar
knopp committed
580
	//	UE->rfdevice.trx_set_freq_func(&openair0,&openair0_cfg[0],0);
581

582
	if (UE->UE_scan_carrier==1) {
583 584 585
	  for (i=0;i<openair0_cfg[0].rx_num_channels;i++) {
	    //	    openair0_cfg[0].autocal[i] = 1;
	  }
586 587
	}
      }// initial_sync=0
588

589
      break;
590

591 592 593 594
    case si:
    default:
      break;
    }
595

596

597
    if (pthread_mutex_lock(&UE->proc.mutex_synch) != 0) {
598 599 600 601
      LOG_E( PHY, "[SCHED][UE] error locking mutex for UE synch\n" );
      exit_fun("noting to add");
      return &UE_thread_synch_retval;
    }
602

603
    // indicate readiness
604
    UE->proc.instance_cnt_synch--;
605

606
    if (pthread_mutex_unlock(&UE->proc.mutex_synch) != 0) {
607 608 609
      LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE synch\n" );
      exit_fun("noting to add");
      return &UE_thread_synch_retval;
610
    }
611

612
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_SYNCH, 0 );
613
  }  // while !oai_exit
614

615
  return &UE_thread_synch_retval;
616 617
}

618

619

620
/*!
621
 * \brief This is the UE thread for RX subframe n and TX subframe n+4.
622
 * This thread performs the phy_procedures_UE_RX() on every received slot.
623
 * then, if TX is enabled it performs TX for n+4. 
624 625 626
 * \param arg is a pointer to a \ref PHY_VARS_UE structure.
 * \returns a pointer to an int. The storage is not on the heap and must not be freed.
 */
627

628
static void *UE_thread_rxn_txnp4(void *arg)
629
{
knopp's avatar
knopp committed
630
  static int UE_thread_rxtx_retval;
631
  UE_rxtx_proc_t *proc = (UE_rxtx_proc_t *)arg;
632
  int ret;
633 634
  PHY_VARS_UE *UE=PHY_vars_UE_g[0][proc->CC_id];
  proc->instance_cnt_rxtx=-1;
635

636

laurent's avatar
laurent committed
637
#ifdef DEADLINE_SCHEDULER
638

639 640 641
  struct sched_attr attr;
  unsigned int flags = 0;

642 643 644
  attr.size = sizeof(attr);
  attr.sched_flags = 0;
  attr.sched_nice = 0;
645
  attr.sched_priority = 0;
646

647
  // This creates a .5ms reservation every 1ms period
648 649 650 651
  attr.sched_policy   = SCHED_DEADLINE;
  attr.sched_runtime  = 900000;  // each rx thread requires 1ms to finish its job
  attr.sched_deadline = 1000000; // each rx thread will finish within 1ms
  attr.sched_period   = 1000000; // each rx thread has a period of 1ms from the starting point
652 653

  if (sched_setattr(0, &attr, flags) < 0 ) {
knopp's avatar
knopp committed
654 655
    perror("[SCHED] UE_thread_rxtx : sched_setattr failed\n");
    return &UE_thread_rxtx_retval;
656 657
  }

658
#else
659 660 661 662 663 664 665 666 667
  int policy, s, j;
  struct sched_param sparam;
  char cpu_affinity[1024];
  cpu_set_t cpuset;

  /* Set affinity mask to include CPUs 1 to MAX_CPUS */
  /* CPU 0 is reserved for UHD threads */
  CPU_ZERO(&cpuset);

668 669
  #ifdef CPU_AFFINITY
  if (get_nprocs() >2)
670
  {
671 672 673 674 675 676 677 678 679
    for (j = 1; j < get_nprocs(); j++)
      CPU_SET(j, &cpuset);

    s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
    if (s != 0)
    {
      perror( "pthread_setaffinity_np");
      exit_fun("Error setting processor affinity");
    }
680
  }
681 682
  #endif

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 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
  /* Check the actual affinity mask assigned to the thread */

  s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
  if (s != 0)
  {
    perror( "pthread_getaffinity_np");
    exit_fun("Error getting processor affinity ");
  }
  memset(cpu_affinity, 0 , sizeof(cpu_affinity));
  for (j = 0; j < CPU_SETSIZE; j++)
  if (CPU_ISSET(j, &cpuset))
  {  
     char temp[1024];
     sprintf(temp, " CPU_%d ", j);    
     strcat(cpu_affinity, temp);
  }

  memset(&sparam, 0 , sizeof (sparam));
  sparam.sched_priority = sched_get_priority_max(SCHED_FIFO)-1;
  policy = SCHED_FIFO ; 
  
  s = pthread_setschedparam(pthread_self(), policy, &sparam);
  if (s != 0)
     {
     perror("pthread_setschedparam : ");
     exit_fun("Error setting thread priority");
     }
  s = pthread_getschedparam(pthread_self(), &policy, &sparam);
  if (s != 0)
   {
     perror("pthread_getschedparam : ");
     exit_fun("Error getting thread priority");

   }

  LOG_I( HW, "[SCHED][UE] Started UE RX thread on CPU %d TID %ld , sched_policy = %s, priority = %d, CPU Affinity = %s \n", (int)sched_getcpu(), gettid(),
                   (policy == SCHED_FIFO)  ? "SCHED_FIFO" :
                   (policy == SCHED_RR)    ? "SCHED_RR" :
                   (policy == SCHED_OTHER) ? "SCHED_OTHER" :
                   "???",
                   (int) sparam.sched_priority, cpu_affinity);

725

726
#endif
727

728
  // Lock memory from swapping. This is a process wide call (not constraint to this thread).
729
  mlockall(MCL_CURRENT | MCL_FUTURE);
730

731
  printf("waiting for sync (UE_thread_rxn_txnp4)\n");
Florian Kaltenberger's avatar
Florian Kaltenberger committed
732

733
  pthread_mutex_lock(&sync_mutex);
734
  printf("Locked sync_mutex, waiting (UE_thread_rxn_txnp4)\n");
735

736 737
  while (sync_var<0)
    pthread_cond_wait(&sync_cond, &sync_mutex);
738

739
  pthread_mutex_unlock(&sync_mutex);
knopp's avatar
knopp committed
740
  printf("unlocked sync_mutex, waiting (UE_thread_rxtx)\n");
741

742
  printf("Starting UE RXN_TXNP4 thread\n");
743 744

  while (!oai_exit) {
745
    if (pthread_mutex_lock(&proc->mutex_rxtx) != 0) {
knopp's avatar
knopp committed
746
      LOG_E( PHY, "[SCHED][UE] error locking mutex for UE RXTX\n" );
747
      exit_fun("nothing to add");
knopp's avatar
knopp committed
748
      return &UE_thread_rxtx_retval;
749
    }
750

751
    while (proc->instance_cnt_rxtx < 0) {
752
      // most of the time, the thread is waiting here
753
      pthread_cond_wait( &proc->cond_rxtx, &proc->mutex_rxtx );
754 755
    }

756 757
    if (pthread_mutex_unlock(&proc->mutex_rxtx) != 0) {
      LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE RXn_TXnp4\n" );
758
      exit_fun("nothing to add");
knopp's avatar
knopp committed
759
      return &UE_thread_rxtx_retval;
760 761
    }

762 763 764 765 766
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_RXTX0+(proc->subframe_rx&1), 1 );
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX0_UE+(proc->subframe_rx&1), proc->subframe_rx );
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX0_UE+(proc->subframe_tx&1), proc->subframe_tx );
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_UE+(proc->subframe_rx&1), proc->frame_rx );
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_UE+(proc->subframe_tx&1), proc->frame_tx );
767

768 769 770 771
    if ((subframe_select( &UE->frame_parms, proc->subframe_rx) == SF_DL) ||
	(UE->frame_parms.frame_type == FDD) ||
	(subframe_select( &UE->frame_parms, proc->subframe_rx ) == SF_S)) {
    
772 773
      phy_procedures_UE_RX( UE, proc, 0, 0, UE->mode, no_relay, NULL );
    }
774
    
775
    if (UE->mac_enabled==1) {
776

777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795
      ret = mac_xface->ue_scheduler(UE->Mod_id,
				    proc->frame_tx,
				    proc->subframe_rx,
				    subframe_select(&UE->frame_parms,proc->subframe_tx),
				    0,
				    0/*FIXME CC_id*/);
      
      if (ret == CONNECTION_LOST) {
	LOG_E( PHY, "[UE %"PRIu8"] Frame %"PRIu32", subframe %u RRC Connection lost, returning to PRACH\n",
	       UE->Mod_id, proc->frame_rx, proc->subframe_tx );
	UE->UE_mode[0] = PRACH;
      } else if (ret == PHY_RESYNCH) {
	LOG_E( PHY, "[UE %"PRIu8"] Frame %"PRIu32", subframe %u RRC Connection lost, trying to resynch\n",
	       UE->Mod_id, proc->frame_rx, proc->subframe_tx );
	UE->UE_mode[0] = RESYNCH;
      } else if (ret == PHY_HO_PRACH) {
	LOG_I( PHY, "[UE %"PRIu8"] Frame %"PRIu32", subframe %u, return to PRACH and perform a contention-free access\n",
	       UE->Mod_id, proc->frame_rx, proc->subframe_tx );
	UE->UE_mode[0] = PRACH;
796 797
      }
    }
798 799 800 801 802 803

    if ((subframe_select( &UE->frame_parms, proc->subframe_tx) == SF_UL) ||
	(UE->frame_parms.frame_type == FDD) ||
	(subframe_select( &UE->frame_parms, proc->subframe_tx ) == SF_S)) {

      if (UE->mode != loop_through_memory) {
Rohit Gupta's avatar
Rohit Gupta committed
804
	phy_procedures_UE_TX(UE,proc,0,0,UE->mode,no_relay);
805 806 807
      }
    }

808 809
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_RXTX0+(proc->subframe_rx&1), 0 );

810 811
    
    if (pthread_mutex_lock(&proc->mutex_rxtx) != 0) {
knopp's avatar
knopp committed
812
      LOG_E( PHY, "[SCHED][UE] error locking mutex for UE RXTX\n" );
813
      exit_fun("noting to add");
knopp's avatar
knopp committed
814
      return &UE_thread_rxtx_retval;
815
    }
816 817 818 819 820
    
    proc->instance_cnt_rxtx--;
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE_INST_CNT_RX, proc->instance_cnt_rxtx);
    
    if (pthread_mutex_unlock(&proc->mutex_rxtx) != 0) {
knopp's avatar
knopp committed
821
      LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE RXTX\n" );
822
      exit_fun("noting to add");
knopp's avatar
knopp committed
823
      return &UE_thread_rxtx_retval;
824
    }
gauthier's avatar
gauthier committed
825
  }
826
  
gauthier's avatar
gauthier committed
827
  // thread finished
knopp's avatar
knopp committed
828
  return &UE_thread_rxtx_retval;
Florian Kaltenberger's avatar
Florian Kaltenberger committed
829
}
830

831 832 833



834

835 836 837 838
#define RX_OFF_MAX 10
#define RX_OFF_MIN 5
#define RX_OFF_MID ((RX_OFF_MAX+RX_OFF_MIN)/2)

839 840 841
/*!
 * \brief This is the main UE thread.
 * This thread controls the other three UE threads:
842 843
 * - UE_thread_rxn_txnp4 (even subframes)
 * - UE_thread_rxn_txnp4 (odd subframes)
844 845 846 847
 * - UE_thread_synch
 * \param arg unused
 * \returns a pointer to an int. The storage is not on the heap and must not be freed.
 */
848 849 850 851 852 853

void *UE_thread(void *arg) {

  static int UE_thread_retval;
  PHY_VARS_UE *UE = PHY_vars_UE_g[0][0];
  //  int tx_enabled = 0;
Rohit Gupta's avatar
Rohit Gupta committed
854
  unsigned int rxs,txs;
855 856
  int dummy_rx[UE->frame_parms.nb_antennas_rx][UE->frame_parms.samples_per_tti] __attribute__((aligned(32)));
  openair0_timestamp timestamp,timestamp1;
Rohit Gupta's avatar
Rohit Gupta committed
857
  void* rxp[2], *txp[2];
858 859 860 861 862

#ifdef NAS_UE
  MessageDef *message_p;
#endif

863
  int start_rx_stream = 0;
864 865
  int rx_off_diff = 0;
  int rx_correction_timer = 0;
Rohit Gupta's avatar
Rohit Gupta committed
866
  int i;
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 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
#ifdef DEADLINE_SCHEDULER

  struct sched_attr attr;
  unsigned int flags = 0;

  attr.size = sizeof(attr);
  attr.sched_flags = 0;
  attr.sched_nice = 0;
  attr.sched_priority = 0;//sched_get_priority_max(SCHED_DEADLINE);

  // This creates a .5 ms  reservation
  attr.sched_policy = SCHED_DEADLINE;
  attr.sched_runtime  = 100000;
  attr.sched_deadline = 500000;
  attr.sched_period   = 500000;

  if (sched_setattr(0, &attr, flags) < 0 ) {
    perror("[SCHED] main eNB thread: sched_setattr failed\n");
    exit_fun("Nothing to add");
    return &UE_thread_retval;
  }
  LOG_I(HW,"[SCHED][eNB] eNB main deadline thread %lu started on CPU %d\n",
        (unsigned long)gettid(), sched_getcpu());

#else
  struct sched_param sp;
  sp.sched_priority = sched_get_priority_max(SCHED_FIFO);
  pthread_setschedparam(pthread_self(),SCHED_FIFO,&sp);
#endif

  // Lock memory from swapping. This is a process wide call (not constraint to this thread).
  mlockall(MCL_CURRENT | MCL_FUTURE);

  printf("waiting for sync (UE_thread)\n");
  pthread_mutex_lock(&sync_mutex);
  printf("Locked sync_mutex, waiting (UE_thread)\n");

  while (sync_var<0)
    pthread_cond_wait(&sync_cond, &sync_mutex);

  pthread_mutex_unlock(&sync_mutex);
  printf("unlocked sync_mutex, waiting (UE_thread)\n");

  printf("starting UE thread\n");

#ifdef NAS_UE
  message_p = itti_alloc_new_message(TASK_NAS_UE, INITIALIZE_MESSAGE);
  itti_send_msg_to_task (TASK_NAS_UE, INSTANCE_DEFAULT, message_p);
#endif 

  while (!oai_exit) {
    
    if (UE->is_synchronized == 0) {
      
922
      if (pthread_mutex_lock(&UE->proc.mutex_synch) != 0) {
923 924 925 926 927
	LOG_E( PHY, "[SCHED][UE] verror locking mutex for UE initial synch thread\n" );
	exit_fun("nothing to add");
	return &UE_thread_retval;
      }
      
928
      int instance_cnt_synch = UE->proc.instance_cnt_synch;
929
      
930
      if (pthread_mutex_unlock(&UE->proc.mutex_synch) != 0) {
931 932 933 934 935 936 937 938 939 940 941
	LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE initial synch thread\n" );
	exit_fun("nothing to add");
	return &UE_thread_retval;
      }
      
      if (instance_cnt_synch < 0) {  // we can invoke the synch
	// grab 10 ms of signal and wakeup synch thread
	for (int i=0; i<UE->frame_parms.nb_antennas_rx; i++)
	  rxp[i] = (void*)&rxdata[i][0];
      
	if (UE->mode != loop_through_memory) {
knopp's avatar
knopp committed
942 943 944 945 946
	  rxs = UE->rfdevice.trx_read_func(&UE->rfdevice,
					   &timestamp,
					   rxp,
					   UE->frame_parms.samples_per_tti*10,
					   UE->frame_parms.nb_antennas_rx);
knopp's avatar
knopp committed
947 948 949 950 951 952

	  
	  if (rxs!=UE->frame_parms.samples_per_tti*10) {
	    exit_fun("problem in rx");
	    return &UE_thread_retval;
	  }
953
	}
knopp's avatar
knopp committed
954

955
	instance_cnt_synch = ++UE->proc.instance_cnt_synch;
956
	if (instance_cnt_synch == 0) {
957
	  if (pthread_cond_signal(&UE->proc.cond_synch) != 0) {
958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973
	    LOG_E( PHY, "[SCHED][UE] ERROR pthread_cond_signal for UE sync thread\n" );
	    exit_fun("nothing to add");
	    return &UE_thread_retval;
	  }
	} else {
	  LOG_E( PHY, "[SCHED][UE] UE sync thread busy!!\n" );
	  exit_fun("nothing to add");
	  return &UE_thread_retval;
	}
      } // 
      else {
	// grab 10 ms of signal into dummy buffer

	if (UE->mode != loop_through_memory) {
	  for (int i=0; i<UE->frame_parms.nb_antennas_rx; i++)
	    rxp[i] = (void*)&dummy_rx[i][0];
974
	  for (int sf=0;sf<10;sf++) {
975
	    //	    printf("Reading dummy sf %d\n",sf);
knopp's avatar
knopp committed
976 977 978 979 980
	    rxs = UE->rfdevice.trx_read_func(&UE->rfdevice,
					     &timestamp,
					     rxp,
					     UE->frame_parms.samples_per_tti,
					     UE->frame_parms.nb_antennas_rx);
knopp's avatar
knopp committed
981 982 983 984 985 986

	    if (rxs!=UE->frame_parms.samples_per_tti){
	      exit_fun("problem in rx");
	      return &UE_thread_retval;
	    }

987
	  }
988 989 990
	}
      }
      
991
    } // UE->is_synchronized==0
992
    else {
993 994 995
      if (start_rx_stream==0) {
	start_rx_stream=1;
	if (UE->mode != loop_through_memory) {
996 997

	  if (UE->no_timing_correction==0) {
Rohit Gupta's avatar
Rohit Gupta committed
998
	    LOG_I(PHY,"Resynchronizing RX by %d samples (mode = %d)\n",UE->rx_offset,UE->mode);
999 1000 1001 1002 1003 1004 1005 1006 1007
	    rxs = UE->rfdevice.trx_read_func(&UE->rfdevice,
					     &timestamp,
					     (void**)rxdata,
					     UE->rx_offset,
					     UE->frame_parms.nb_antennas_rx);
	    if (rxs != UE->rx_offset) {
	      exit_fun("problem in rx");
	      return &UE_thread_retval;
	    }
1008 1009
	  }
	  UE->rx_offset=0;
1010 1011 1012 1013
	  UE->proc.proc_rxtx[0].frame_rx++;
	  UE->proc.proc_rxtx[1].frame_rx++;

	  // read in first symbol
knopp's avatar
knopp committed
1014 1015 1016 1017 1018
	  rxs = UE->rfdevice.trx_read_func(&UE->rfdevice,
					   &timestamp,
					   (void**)rxdata,
					   UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0,
					   UE->frame_parms.nb_antennas_rx);
1019 1020 1021 1022 1023 1024 1025 1026 1027 1028
	  slot_fep(UE,
		   0,
		   0,
		   0,
		   0,
		   0);
	  if (rxs != UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0) {
	    exit_fun("problem in rx");
	    return &UE_thread_retval;
	  }
1029 1030 1031
	} //UE->mode != loop_through_memory
	else
	  rt_sleep_ns(1000000);
1032

1033
      }// start_rx_stream==0
1034 1035 1036
      else {
	UE->proc.proc_rxtx[0].frame_rx++;
	UE->proc.proc_rxtx[1].frame_rx++;
Rohit Gupta's avatar
Rohit Gupta committed
1037
	
1038
	for (int sf=0;sf<10;sf++) {
Rohit Gupta's avatar
Rohit Gupta committed
1039
	  for (i=0; i<UE->frame_parms.nb_antennas_rx; i++) 
1040 1041
	    rxp[i] = (void*)&rxdata[i][UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0+(sf*UE->frame_parms.samples_per_tti)];
	  // grab signal for subframe
1042
	  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 );
1043 1044
	  if (UE->mode != loop_through_memory) {
	    if (sf<9) {
knopp's avatar
knopp committed
1045 1046 1047 1048 1049
	      rxs = UE->rfdevice.trx_read_func(&UE->rfdevice,
					       &timestamp,
					       rxp,
					       UE->frame_parms.samples_per_tti,
					       UE->frame_parms.nb_antennas_rx);
Rohit Gupta's avatar
Rohit Gupta committed
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067
	      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 );
	      // prepare tx buffer pointers
	      
	      for (i=0; i<UE->frame_parms.nb_antennas_tx; i++)
		txp[i] = (void*)&UE->common_vars.txdata[i][((sf+2)%10)*UE->frame_parms.samples_per_tti];
	      
	      txs = UE->rfdevice.trx_write_func(&UE->rfdevice,
						timestamp+
						(2*UE->frame_parms.samples_per_tti) -
						UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0 -
						openair0_cfg[0].tx_sample_advance,
						txp,
						UE->frame_parms.samples_per_tti,
						UE->frame_parms.nb_antennas_tx,
						1);
	      
	      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 );

1068
	    }
Rohit Gupta's avatar
Rohit Gupta committed
1069
	    
1070
	    else {
knopp's avatar
knopp committed
1071 1072 1073 1074 1075
	      rxs = UE->rfdevice.trx_read_func(&UE->rfdevice,
					       &timestamp,
					       rxp,
					       UE->frame_parms.samples_per_tti-UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0,
					       UE->frame_parms.nb_antennas_rx);
Rohit Gupta's avatar
Rohit Gupta committed
1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093
	      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 );
	      // prepare tx buffer pointers
	      
	      for (i=0; i<UE->frame_parms.nb_antennas_tx; i++)
		txp[i] = (void*)&UE->common_vars.txdata[i][((sf+2)%10)*UE->frame_parms.samples_per_tti];
	      
	      txs = UE->rfdevice.trx_write_func(&UE->rfdevice,
						timestamp+
						(2*UE->frame_parms.samples_per_tti) -
						UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0 -
						openair0_cfg[0].tx_sample_advance,
						txp,
						UE->frame_parms.samples_per_tti - rx_off_diff,
						UE->frame_parms.nb_antennas_tx,
						1);
	      
	      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 );

1094
	      // read in first symbol of next frame and adjust for timing drift
knopp's avatar
knopp committed
1095
	      rxs = UE->rfdevice.trx_read_func(&UE->rfdevice,
Rohit Gupta's avatar
Rohit Gupta committed
1096 1097 1098 1099
					       &timestamp1,
					       (void**)rxdata,
					       UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0 - rx_off_diff,
					       UE->frame_parms.nb_antennas_rx);
1100 1101 1102
	      rx_off_diff = 0;
	    }
	  }
1103
	  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );
1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116
	  // operate on thread sf mod 2
	  UE_rxtx_proc_t *proc = &UE->proc.proc_rxtx[sf&1];

	  // lock mutex
	  if (pthread_mutex_lock(&proc->mutex_rxtx) != 0) {
	    LOG_E( PHY, "[SCHED][UE] error locking mutex for UE RX\n" );
	    exit_fun("nothing to add");
	    return &UE_thread_retval;
	  }
	  // increment instance count and change proc subframe/frame variables
	  int instance_cnt_rxtx = ++proc->instance_cnt_rxtx;
	  proc->subframe_rx=sf;
	  proc->subframe_tx=(sf+4)%10;
1117
	  proc->frame_tx = proc->frame_rx + ((proc->subframe_rx>5)?1:0);
1118 1119
	  proc->timestamp_tx = timestamp+(4*UE->frame_parms.samples_per_tti)-UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0;

knopp's avatar
knopp committed
1120
	  /*
1121 1122 1123 1124
	  if (sf != (timestamp/UE->frame_parms.samples_per_tti)%10) {
	    LOG_E(PHY,"steady-state UE_thread error : frame_rx %d, subframe_rx %d, frame_tx %d, subframe_tx %d, rx subframe %d\n",proc->frame_rx,proc->subframe_rx,proc->frame_tx,proc->subframe_tx,(timestamp/UE->frame_parms.samples_per_tti)%10);
	    exit(-1);
	  }
knopp's avatar
knopp committed
1125
	  */
1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165
	  if (pthread_mutex_unlock(&proc->mutex_rxtx) != 0) {
	    LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE RX\n" );
	    exit_fun("nothing to add");
	    return &UE_thread_retval;
	  }


	  if (instance_cnt_rxtx == 0) {
	    if (pthread_cond_signal(&proc->cond_rxtx) != 0) {
	      LOG_E( PHY, "[SCHED][UE] ERROR pthread_cond_signal for UE RX thread\n" );
	      exit_fun("nothing to add");
	      return &UE_thread_retval;
	    }
	  } else {
	    LOG_E( PHY, "[SCHED][UE] UE RX thread busy (IC %d)!!\n", instance_cnt_rxtx);
	    if (instance_cnt_rxtx > 2) {
	      sleep(1);
	      exit_fun("instance_cnt_rxtx > 2");
	      return &UE_thread_retval;
	    }
	  }
	  if (UE->mode == loop_through_memory) {
	    printf("Processing subframe %d",proc->subframe_rx);
	    getchar();
	  }
	}// for sf=0..10
	if ((UE->rx_offset<(5*UE->frame_parms.samples_per_tti)) &&
	    (UE->rx_offset > RX_OFF_MIN) && 
	    (rx_correction_timer == 0)) {
	  rx_off_diff = -UE->rx_offset + RX_OFF_MIN;
	  LOG_D(PHY,"UE->rx_offset %d > %d, diff %d\n",UE->rx_offset,RX_OFF_MIN,rx_off_diff);
	  rx_correction_timer = 5;
	} else if ((UE->rx_offset>(5*UE->frame_parms.samples_per_tti)) && 
		   (UE->rx_offset < ((10*UE->frame_parms.samples_per_tti)-RX_OFF_MIN)) &&
		   (rx_correction_timer == 0)) {   // moving to the left so drop rx_off_diff samples
	  rx_off_diff = 10*UE->frame_parms.samples_per_tti - RX_OFF_MIN - UE->rx_offset;
	  LOG_D(PHY,"UE->rx_offset %d < %d, diff %d\n",UE->rx_offset,10*UE->frame_parms.samples_per_tti-RX_OFF_MIN,rx_off_diff);
	  
	  rx_correction_timer = 5;
	}
1166
	
1167 1168 1169
	if (rx_correction_timer>0)
	  rx_correction_timer--;
      } // start_rx_stream==1
1170 1171
    } // UE->is_synchronized==1
      
1172 1173 1174 1175 1176
  } // while !oai_exit
} // UE_thread

/*
void *UE_thread_old(void *arg)
1177
{
1178 1179 1180
  UNUSED(arg)
  static int UE_thread_retval;
  PHY_VARS_UE *UE = PHY_vars_UE_g[0][0];
1181
  int spp = openair0_cfg[0].samples_per_packet;
1182
  int slot=1, frame=0, hw_subframe=0, rxpos=0, txpos=openair0_cfg[0].tx_scheduling_advance;
1183 1184 1185 1186 1187
#ifdef __AVX2__
  int dummy[2][spp] __attribute__((aligned(32)));
#else
  int dummy[2][spp] __attribute__((aligned(16)));
#endif
1188
  int dummy_dump = 0;
1189 1190
  int tx_enabled = 0;
  int start_rx_stream = 0;
1191 1192
  int rx_off_diff = 0;
  int rx_correction_timer = 0;
1193
  int first_rx = 0;
1194
  RTIME T0;
1195
  unsigned int rxs;
1196
  void* rxp[2];
1197 1198 1199

  openair0_timestamp timestamp;

1200 1201 1202 1203
#ifdef NAS_UE
  MessageDef *message_p;
#endif

laurent's avatar
laurent committed
1204
#ifdef DEADLINE_SCHEDULER
1205

1206 1207 1208
  struct sched_attr attr;
  unsigned int flags = 0;

1209 1210 1211
  attr.size = sizeof(attr);
  attr.sched_flags = 0;
  attr.sched_nice = 0;
1212
  attr.sched_priority = 0;//sched_get_priority_max(SCHED_DEADLINE);
1213

1214 1215
  // This creates a .5 ms  reservation
  attr.sched_policy = SCHED_DEADLINE;
1216 1217 1218
  attr.sched_runtime  = 100000;
  attr.sched_deadline = 500000;
  attr.sched_period   = 500000;
1219 1220

  if (sched_setattr(0, &attr, flags) < 0 ) {
1221 1222
    perror("[SCHED] main eNB thread: sched_setattr failed\n");
    exit_fun("Nothing to add");
1223
    return &UE_thread_retval;
1224
  }
1225 1226 1227
  LOG_I(HW,"[SCHED][eNB] eNB main deadline thread %lu started on CPU %d\n",
        (unsigned long)gettid(), sched_getcpu());

1228 1229 1230 1231
#else
  struct sched_param sp;
  sp.sched_priority = sched_get_priority_max(SCHED_FIFO);
  pthread_setschedparam(pthread_self(),SCHED_FIFO,&sp);
1232 1233
#endif

1234
  // Lock memory from swapping. This is a process wide call (not constraint to this thread).
1235 1236 1237 1238 1239
  mlockall(MCL_CURRENT | MCL_FUTURE);

  printf("waiting for sync (UE_thread)\n");
  pthread_mutex_lock(&sync_mutex);
  printf("Locked sync_mutex, waiting (UE_thread)\n");
1240

1241 1242
  while (sync_var<0)
    pthread_cond_wait(&sync_cond, &sync_mutex);
1243

1244 1245 1246 1247 1248
  pthread_mutex_unlock(&sync_mutex);
  printf("unlocked sync_mutex, waiting (UE_thread)\n");

  printf("starting UE thread\n");

1249 1250 1251 1252 1253
#ifdef NAS_UE
  message_p = itti_alloc_new_message(TASK_NAS_UE, INITIALIZE_MESSAGE);
  itti_send_msg_to_task (TASK_NAS_UE, INSTANCE_DEFAULT, message_p);
#endif

1254 1255
  T0 = rt_get_time_ns();
  first_rx = 1;
1256
  rxpos=0;
1257

1258
  while (!oai_exit) {
1259 1260
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_HW_SUBFRAME, hw_subframe );
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_HW_FRAME, frame );
1261
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_DUMMY_DUMP, dummy_dump );
1262

1263

1264
    while (rxpos < (1+hw_subframe)*UE->frame_parms.samples_per_tti) {
1265
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 );
1266

1267 1268
#ifndef USRP_DEBUG

1269
      DevAssert( UE->frame_parms.nb_antennas_rx <= 2 );
1270
      void* rxp[2];
1271

1272
      for (int i=0; i<UE->frame_parms.nb_antennas_rx; i++)
1273
        rxp[i] = (dummy_dump==0) ? (void*)&rxdata[i][rxpos] : (void*)dummy[i];
1274
      
1275
    
1276
      if (UE->mode != loop_through_memory) {
knopp's avatar
knopp committed
1277
	rxs = UE->rfdevice.trx_read_func(&UE->rfdevice,
1278 1279 1280
				     &timestamp,
				     rxp,
				     spp - ((first_rx==1) ? rx_off_diff : 0),
1281
				     UE->frame_parms.nb_antennas_rx);
1282 1283

	if (rxs != (spp- ((first_rx==1) ? rx_off_diff : 0))) {
1284 1285 1286 1287 1288
	  printf("rx error: asked %d got %d ",spp - ((first_rx==1) ? rx_off_diff : 0),rxs);
	  if (UE->is_synchronized == 1) {
	    exit_fun("problem in rx");
	    return &UE_thread_retval;
	  }
1289
	}
1290
      }
1291

1292
      if (rx_off_diff !=0)
1293
	LOG_D(PHY,"frame %d, rx_offset %d, rx_off_diff %d\n",UE->frame_rx,UE->rx_offset,rx_off_diff);
1294

1295
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );
1296

1297
      // Transmit TX buffer based on timestamp from RX
1298
      if ((tx_enabled==1) && (UE->mode!=loop_through_memory)) {
1299
        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 );
1300

1301
        DevAssert( UE->frame_parms.nb_antennas_tx <= 2 );
1302
        void* txp[2];
1303

1304
        for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++)
1305 1306
          txp[i] = (void*)&txdata[i][txpos];

knopp's avatar
knopp committed
1307
        UE->rfdevice.trx_write_func(&openair0,
Raymond Knopp's avatar
Raymond Knopp committed
1308
                                (timestamp+openair0_cfg[0].tx_scheduling_advance-openair0_cfg[0].tx_sample_advance),
1309
                                txp,
1310
				spp - ((first_rx==1) ? rx_off_diff : 0),
1311
                                UE->frame_parms.nb_antennas_tx,
1312 1313
                                1);

1314
        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 );
1315
      }
1316 1317
      else if (UE->mode == loop_through_memory)
	rt_sleep_ns(1000000);
1318
#else
1319
      // define USRP_DEBUG is active
1320 1321
      rt_sleep_ns(1000000);
#endif
1322

1323 1324 1325
      rx_off_diff = 0;
      first_rx = 0;

1326 1327 1328
      rxpos += spp;
      txpos += spp;

1329 1330
      if (txpos >= 10*PHY_vars_UE_g[0][0]->frame_parms.samples_per_tti)
        txpos -= 10*PHY_vars_UE_g[0][0]->frame_parms.samples_per_tti;
1331
    }
1332

1333 1334
    if (rxpos >= 10*PHY_vars_UE_g[0][0]->frame_parms.samples_per_tti)
      rxpos -= 10*PHY_vars_UE_g[0][0]->frame_parms.samples_per_tti;
1335

1336 1337
    if (UE->is_synchronized == 1)  {
      LOG_D( HW, "UE_thread: hw_frame %d, hw_subframe %d (time %lli)\n", frame, hw_subframe, rt_get_time_ns()-T0 );