lte-ue.c 52 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"
Raymond Knopp's avatar
 
Raymond Knopp committed
63
#ifdef OPENAIR2
64 65
#include "LAYER2/MAC/defs.h"
#include "RRC/LITE/extern.h"
Raymond Knopp's avatar
 
Raymond 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;

95 96 97
void init_UE_threads(void);
void *UE_thread(void *arg);
void init_UE(void);
98 99 100 101 102 103 104

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

extern openair0_config_t openair0_cfg[MAX_CARDS];
extern uint32_t          downlink_frequency[MAX_NUM_CCs][4];
105
extern int32_t           uplink_frequency_offset[MAX_NUM_CCs][4];
106 107 108 109 110 111 112 113
extern openair0_rf_map rf_map[MAX_NUM_CCs];

extern openair0_device openair0;
extern int oai_exit;

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

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

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;

142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
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},
159
  {22, 3510    * MHz, 3590    * MHz, 3410    * MHz, 3490    * MHz, FDD},
160 161 162 163 164 165 166 167 168 169 170 171 172 173
  {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},
};

174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
pthread_t                       main_ue_thread;
pthread_attr_t                  attr_UE_thread;
struct sched_param              sched_param_UE_thread;

void init_UE() {

  int error_code;
  
  printf("Intializing UE Threads ...\n");
  init_UE_threads();
  sleep(1);
  error_code = pthread_create(&main_ue_thread, &attr_UE_thread, 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( main_ue_thread, "main UE" );
  }

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

206 207
/*!
 * \brief This is the UE synchronize thread.
208
 * It performs band scanning and synchonization.
209 210 211
 * \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.
 */
212 213
static void *UE_thread_synch(void *arg)
{
214 215 216
  static int UE_thread_synch_retval;
  int i, hw_slot_offset;
  PHY_VARS_UE *UE = (PHY_VARS_UE*) arg;
217 218
  int current_band = 0;
  int current_offset = 0;
219
  sync_mode_t sync_mode = pbch;
220
  int card;
221 222
  int ind;
  int found;
223
  int freq_offset=0;
224 225 226 227 228

  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
229
#ifndef DEADLINE_SCHEDULER
230 231 232 233 234 235 236 237 238
  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);

239 240
  #ifdef CPU_AFFINITY
  if (get_nprocs() >2)
241
  {
242 243 244 245 246 247 248 249 250
    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");
    }
251
  }
252 253
  #endif

254 255 256 257 258 259 260 261 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
  /* 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


299 300
  pthread_mutex_lock(&sync_mutex);
  printf("Locked sync_mutex, waiting (UE_sync_thread)\n");
301

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

305 306 307
  pthread_mutex_unlock(&sync_mutex);
  printf("unlocked sync_mutex (UE_sync_thread)\n");

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


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

318
      if ((eutra_bands[ind].dl_min <= downlink_frequency[0][0]) && (eutra_bands[ind].dl_max >= downlink_frequency[0][0])) {
319 320 321 322 323 324 325
        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;
      }
326

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

335 336


337

338 339


Raymond Knopp's avatar
 
Raymond Knopp committed
340
    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 );
341 342 343 344 345 346 347

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

348
    sync_mode = pbch;
349

350
  } else if  (UE->UE_scan == 1) {
351
    current_band=0;
352

353
    for (card=0; card<MAX_CARDS; card++) {
354
      for (i=0; i<openair0_cfg[card].rx_num_channels; i++) {
355 356 357 358 359
        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];
360
#ifdef OAI_USRP
361
        openair0_cfg[card].rx_gain[i] = UE->rx_total_gain_dB;//-USRP_GAIN_OFFSET;
362

363
#if 0 // UHD 3.8	
364
        switch(UE->frame_parms.N_RB_DL) {
365 366 367 368 369 370 371 372 373 374 375 376
        case 6:
          openair0_cfg[card].rx_gain[i] -= 12;
          break;

        case 25:
          openair0_cfg[card].rx_gain[i] -= 6;
          break;

        case 50:
          openair0_cfg[card].rx_gain[i] -= 3;
          break;

377 378 379 380
        case 100:
          openair0_cfg[card].rx_gain[i] -= 0;
          break;

381
        default:
382
          printf( "Unknown number of RBs %d\n", UE->frame_parms.N_RB_DL );
383 384
          break;
        }
385
#endif
386
        printf( "UE synch: setting RX gain (%d,%d) to %f\n", card, i, openair0_cfg[card].rx_gain[i] );
387 388
#endif
      }
389 390 391
    }

  }
392 393

  while (oai_exit==0) {
394

395
    if (pthread_mutex_lock(&UE->mutex_synch) != 0) {
396
      LOG_E( PHY, "[SCHED][UE] error locking mutex for UE initial synch thread\n" );
397
      exit_fun("noting to add");
398 399
      return &UE_thread_synch_retval;
    }
400
    
401

402
    while (UE->instance_cnt_synch < 0) {
403
      // the thread waits here most of the time
404 405
      pthread_cond_wait( &UE->cond_synch, &UE->mutex_synch );
    }
406

407 408 409 410 411
    if (pthread_mutex_unlock(&UE->mutex_synch) != 0) {
      LOG_E( PHY, "[SCHED][eNB] error unlocking mutex for UE Initial Synch thread\n" );
      exit_fun("nothing to add");
      return &UE_thread_synch_retval;
    }
412

413
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SYNCH, 1 );
414 415

    switch (sync_mode) {
416
    case pss:
417 418
      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);
419 420 421 422 423 424 425
      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;
      }

426
      if (current_band==bands_to_scan.nbands) {
427 428
        current_band=0;
        oai_exit=1;
429
      }
430 431 432 433 434 435 436

      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;


437 438
          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];
439
#ifdef OAI_USRP
440
          openair0_cfg[card].rx_gain[i] = UE->rx_total_gain_dB;//-USRP_GAIN_OFFSET;  // 65 calibrated for USRP B210 @ 2.6 GHz
441 442

#if 0 // UHD 3.8	  
443
          switch(UE->frame_parms.N_RB_DL) {
444 445 446 447 448 449 450 451 452 453 454 455
          case 6:
            openair0_cfg[card].rx_gain[i] -= 12;
            break;

          case 25:
            openair0_cfg[card].rx_gain[i] -= 6;
            break;

          case 50:
            openair0_cfg[card].rx_gain[i] -= 3;
            break;

456 457 458 459
          case 100:
            openair0_cfg[card].rx_gain[i] -= 0;
            break;

460
          default:
461
            printf("Unknown number of RBs %d\n",UE->frame_parms.N_RB_DL);
462 463
            break;
          }
464
#endif	  
465 466

          printf("UE synch: setting RX gain (%d,%d) to %f\n",card,i,openair0_cfg[card].rx_gain[i]);
467
#endif
468

469
        }
470 471 472

      }

473
      if (UE->UE_scan_carrier) {
474

475 476 477 478
	for (i=0;i<openair0_cfg[0].rx_num_channels;i++)
	  openair0_cfg[0].autocal[i] = 1;

      }
479

480 481 482

      break;
 
483
    case pbch:
484

485
      LOG_I(PHY,"[UE thread Synch] Running Initial Synch\n");
486
      if (initial_sync( UE, UE->mode ) == 0) {
487

488
        hw_slot_offset = (UE->rx_offset<<1) / UE->frame_parms.samples_per_tti;
489 490 491 492 493 494
        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++) {
495
	    openair0_cfg[0].rx_gain[i] = UE->rx_total_gain_dB;//-USRP_GAIN_OFFSET;
496
	    openair0_cfg[0].rx_freq[i] -= UE->common_vars.freq_offset;
497 498 499 500 501
	    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;	    
	  }

502
	  // reconfigure for potentially different bandwidth
503
	  switch(UE->frame_parms.N_RB_DL) {
504 505
	  case 6:
	    openair0_cfg[0].sample_rate =1.92e6;
506 507
	    openair0_cfg[0].rx_bw          =.96e6;
	    openair0_cfg[0].tx_bw          =.96e6;
508
	    //            openair0_cfg[0].rx_gain[0] -= 12;
509 510
	    break;
	  case 25:
511 512 513
	    openair0_cfg[0].sample_rate =7.68e6;
	    openair0_cfg[0].rx_bw          =2.5e6;
	    openair0_cfg[0].tx_bw          =2.5e6;
514
	    //            openair0_cfg[0].rx_gain[0] -= 6;
515 516
	    break;
	  case 50:
517 518 519
	    openair0_cfg[0].sample_rate =15.36e6;
	    openair0_cfg[0].rx_bw          =5.0e6;
	    openair0_cfg[0].tx_bw          =5.0e6;
520
	    //            openair0_cfg[0].rx_gain[0] -= 3;
521 522 523
	    break;
	  case 100:
	    openair0_cfg[0].sample_rate=30.72e6;
524 525
	    openair0_cfg[0].rx_bw=10.0e6;
	    openair0_cfg[0].tx_bw=10.0e6;
526
	    //            openair0_cfg[0].rx_gain[0] -= 0;
527 528
	    break;
	  }
529

530
	  openair0.trx_set_freq_func(&openair0,&openair0_cfg[0],0);
531 532
	  //openair0.trx_set_gains_func(&openair0,&openair0_cfg[0]);
	  //openair0.trx_stop_func(0);	  
533
	  sleep(1);
534
	  init_frame_parms(&UE->frame_parms,1);
535 536 537
	}
	else {
	  UE->is_synchronized = 1;
538 539

	 if( UE->mode == rx_dump_frame ){
540 541
	   FILE *fd;
	   if ((UE->frame_rx&1) == 0) {  // this guarantees SIB1 is present 
Cedric Roux's avatar
Cedric Roux committed
542
	     if ((fd = fopen("rxsig_frame0.dat","w")) != NULL) {
543
	       fwrite((void*)&UE->common_vars.rxdata[0][0],
544
		      sizeof(int32_t),
545
		      10*UE->frame_parms.samples_per_tti,
546 547 548 549 550 551 552 553 554 555 556 557 558
		      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;
	   }
559
	 }
560
	 
561

562

563 564 565
	  UE->slot_rx = 0;
	  UE->slot_tx = 4;
	}
566 567 568
      } else {
        // initial sync failed
        // calculate new offset and try again
569 570 571 572 573 574 575 576 577 578
	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" );
579
	    FILE *fd;
580
	    if ((fd = fopen("rxsig_frame0.dat","w"))!=NULL) {
581
	      fwrite((void*)&UE->common_vars.rxdata[0][0],
582
		     sizeof(int32_t),
583
		     10*UE->frame_parms.samples_per_tti,
584 585 586 587 588
		     fd);
	      LOG_I(PHY,"Dummping Frame ... bye bye \n");
	      fclose(fd);
	      exit(0);
	    }
589 590 591 592 593 594 595 596 597
	    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,
598
               UE->rx_total_gain_dB,
599 600
               downlink_frequency[0][0]+freq_offset,
               downlink_frequency[0][0]+uplink_frequency_offset[0][0]+freq_offset );
601 602 603

        for (card=0; card<MAX_CARDS; card++) {
          for (i=0; i<openair0_cfg[card].rx_num_channels; i++) {
604 605
            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;
606

607 608
	    openair0.trx_set_freq_func(&openair0,&openair0_cfg[0],0);
	    
609 610 611 612

            openair0_cfg[card].rx_gain[i] = UE->rx_total_gain_dB;//-USRP_GAIN_OFFSET;
	    
	    
613 614
          }
        }
615 616 617 618 619 620
	if (UE->UE_scan_carrier==1) {
	  for (i=0;i<openair0_cfg[0].rx_num_channels;i++)
	    openair0_cfg[0].autocal[i] = 1;
	  
	}
      }// initial_sync=0
621

622
      break;
623

624 625 626 627
    case si:
    default:
      break;
    }
628

629
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SYNCH, 0 );
Raymond Knopp's avatar
 
Raymond Knopp committed
630

631 632


633
    if (pthread_mutex_lock(&UE->mutex_synch) != 0) {
634 635 636 637
      LOG_E( PHY, "[SCHED][UE] error locking mutex for UE synch\n" );
      exit_fun("noting to add");
      return &UE_thread_synch_retval;
    }
638

639
    // indicate readiness
640 641 642 643 644 645
    UE->instance_cnt_synch--;

    if (pthread_mutex_unlock(&UE->mutex_synch) != 0) {
      LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE synch\n" );
      exit_fun("noting to add");
      return &UE_thread_synch_retval;
646
    }
647

648
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SYNCH, 0 );
649
  }  // while !oai_exit
650

651
  return &UE_thread_synch_retval;
652 653
}

654 655 656 657 658 659
/*!
 * \brief This is the UE transmit thread.
 * This thread performs the phy_procedures_UE_TX() on every transmit slot.
 * \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.
 */
660 661
static void *UE_thread_tx(void *arg)
{
662
  static int UE_thread_tx_retval;
663
  //int ret;
664 665 666 667 668

  PHY_VARS_UE *UE = (PHY_VARS_UE*)arg;

  UE->instance_cnt_tx=-1;

laurent's avatar
laurent committed
669
#ifdef DEADLINE_SCHEDULER
670

671 672 673
  struct sched_attr attr;
  unsigned int flags = 0;

674 675 676
  attr.size = sizeof(attr);
  attr.sched_flags = 0;
  attr.sched_nice = 0;
677
  attr.sched_priority = 0;
678

679
  /* This creates a 1ms reservation every 10ms period*/
680 681 682 683
  attr.sched_policy   = SCHED_DEADLINE;
  attr.sched_runtime  = 900000;  // each tx thread requires .5ms to finish its job
  attr.sched_deadline = 1000000; // each tx thread will finish within 1ms
  attr.sched_period   = 1000000; // each tx thread has a period of 1ms from the starting point
684

685 686

  if (sched_setattr(0, &attr, flags) < 0 ) {
knopp's avatar
knopp committed
687
    perror("[SCHED] UE_thread_tx thread: sched_setattr failed\n");
688
    return &UE_thread_tx_retval;
689
  }
690

691
#else
692 693 694 695 696 697 698 699 700
  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);

701 702
  #ifdef CPU_AFFINITY
  if (get_nprocs() >2)
703
  {
704 705 706 707 708 709 710 711 712
    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");
    }
713
  }
714
#endif
715

716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
  /* 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 thread TX 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);

758

759
#endif
760

761 762 763 764
  printf("waiting for sync (UE_thread_tx)\n");

  pthread_mutex_lock(&sync_mutex);
  printf("Locked sync_mutex, waiting (UE_thread_tx)\n");
765

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

769 770 771 772 773
  pthread_mutex_unlock(&sync_mutex);
  printf("unlocked sync_mutex, waiting (UE_thread_tx)\n");

  printf("Starting UE TX thread\n");

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

  while (!oai_exit) {

    if (pthread_mutex_lock(&UE->mutex_tx) != 0) {
780
      LOG_E( PHY, "[SCHED][UE] error locking mutex for UE TX\n" );
781
      exit_fun("nothing to add");
782 783
      return &UE_thread_tx_retval;
    }
784

785 786 787
    while (UE->instance_cnt_tx < 0) {
      // most of the time, the thread is waiting here
      pthread_cond_wait( &UE->cond_tx, &UE->mutex_tx );
788
    }
789

790 791 792 793 794
    if (pthread_mutex_unlock(&UE->mutex_tx) != 0) {
      LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE TX\n" );
      exit_fun("nothing to add");
      return &UE_thread_tx_retval;
    }
795
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_TX, 1 );
796

797 798
    if ((subframe_select( &UE->frame_parms, UE->slot_tx>>1 ) == SF_UL) ||
        (UE->frame_parms.frame_type == FDD)) {
799
      phy_procedures_UE_TX( UE, 0, 0, UE->mode, no_relay );
800
    }
801

802
    if ((subframe_select( &UE->frame_parms, UE->slot_tx>>1 ) == SF_S) &&
803 804
        ((UE->slot_tx&1) == 1)) {
      phy_procedures_UE_S_TX( UE, 0, 0, no_relay );
805
    }
806

807 808 809 810 811 812 813 814 815 816 817
    UE->slot_tx += 2;

    if (UE->slot_tx >= 20) {
      UE->slot_tx -= 20;
      UE->frame_tx++;
      VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX_UE, UE->frame_tx );
    }

    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX_UE, UE->slot_tx>>1 );

    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_TX, 0 );
818

819
    if (pthread_mutex_lock(&UE->mutex_tx) != 0) {
820 821 822 823
      LOG_E( PHY, "[SCHED][UE] error locking mutex for UE TX thread\n" );
      exit_fun("nothing to add");
      return &UE_thread_tx_retval;
    }
824

825
    UE->instance_cnt_tx--;
826
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE_INST_CNT_TX, UE->instance_cnt_tx);
827 828 829 830 831

    if (pthread_mutex_unlock(&UE->mutex_tx) != 0) {
      LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE TX thread\n" );
      exit_fun("nothing to add");
      return &UE_thread_tx_retval;
832
    }
833

834
  }
835

836
  return &UE_thread_tx_retval;
837 838
}

839 840 841 842 843 844
/*!
 * \brief This is the UE receive thread.
 * This thread performs the phy_procedures_UE_RX() on every received slot.
 * \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.
 */
845

846
/*
847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865
#ifdef OAI_USRP
void rescale(int16_t *input,int length)
{
#if defined(__x86_64__) || defined(__i386__)
  __m128i *input128 = (__m128i *)input;
#elif defined(__arm__)
  int16x8_t *input128 = (int16x8_t *)input;
#endif
  int i;

  for (i=0; i<length>>2; i++) {
#if defined(__x86_64__) || defined(__i386__)
    input128[i] = _mm_srai_epi16(input128[i],4);
#elif defined(__arm__)
    input128[i] = vshrq_n_s16(input128[i],4);
#endif
  }
}
#endif
866
*/
867

868 869
static void *UE_thread_rx(void *arg)
{
870
  static int UE_thread_rx_retval;
871 872 873
  PHY_VARS_UE *UE = (PHY_VARS_UE*)arg;
  int i;
  int ret;
874

875 876
  UE->instance_cnt_rx=-1;

877

laurent's avatar
laurent committed
878
#ifdef DEADLINE_SCHEDULER
879

880 881 882
  struct sched_attr attr;
  unsigned int flags = 0;

883 884 885
  attr.size = sizeof(attr);
  attr.sched_flags = 0;
  attr.sched_nice = 0;
886
  attr.sched_priority = 0;
887

888
  // This creates a .5ms reservation every 1ms period
889 890 891 892
  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
893 894

  if (sched_setattr(0, &attr, flags) < 0 ) {
knopp's avatar
knopp committed
895
    perror("[SCHED] UE_thread_rx : sched_setattr failed\n");
896
    return &UE_thread_rx_retval;
897 898
  }

899
#else
900 901 902 903 904 905 906 907 908
  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);

909 910
  #ifdef CPU_AFFINITY
  if (get_nprocs() >2)
911
  {
912 913 914 915 916 917 918 919 920
    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");
    }
921
  }
922 923
  #endif

924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965
  /* 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);

966

967
#endif
968

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

972
  printf("waiting for sync (UE_thread_rx)\n");
Florian Kaltenberger's avatar
 
Florian Kaltenberger committed
973

974 975
  pthread_mutex_lock(&sync_mutex);
  printf("Locked sync_mutex, waiting (UE_thread_rx)\n");
976

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

980 981
  pthread_mutex_unlock(&sync_mutex);
  printf("unlocked sync_mutex, waiting (UE_thread_rx)\n");
982

983
  printf("Starting UE RX thread\n");
984 985

  while (!oai_exit) {
986
    if (pthread_mutex_lock(&UE->mutex_rx) != 0) {
987
      LOG_E( PHY, "[SCHED][UE] error locking mutex for UE RX\n" );
988
      exit_fun("nothing to add");
989
      return &UE_thread_rx_retval;
990
    }
991 992

    while (UE->instance_cnt_rx < 0) {
993 994
      // most of the time, the thread is waiting here
      pthread_cond_wait( &UE->cond_rx, &UE->mutex_rx );
995 996 997
    }

    if (pthread_mutex_unlock(&UE->mutex_rx) != 0) {
998
      LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE RX\n" );
999
      exit_fun("nothing to add");
1000
      return &UE_thread_rx_retval;
1001 1002
    }

1003
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_RX, 1 );
1004
    for (i=0; i<2; i++) {
1005 1006
      if ((subframe_select( &UE->frame_parms, UE->slot_rx>>1 ) == SF_DL) ||
          (UE->frame_parms.frame_type == FDD)) {
1007
	/*
1008 1009
#ifdef OAI_USRP
	// this does the adjustments of RX signal amplitude to bring into least 12 significant bits
1010
	int slot_length = UE->frame_parms.samples_per_tti>>1;
1011
	int rx_offset = (UE->slot_rx)*slot_length + UE->rx_offset;
1012
	int frame_length = UE->frame_parms.samples_per_tti*10;
1013 1014 1015 1016 1017 1018 1019
	int aa;
	if (rx_offset > frame_length)
	  rx_offset-=frame_length;


	if (rx_offset >= 0) {
	  if (rx_offset + slot_length < frame_length)
1020 1021
	    for (aa=0;aa<UE->frame_parms.nb_antennas_rx;aa++)
	      rescale((int16_t*)&UE->common_vars.rxdata[aa][rx_offset&(~0x3)],
1022 1023 1024
		      slot_length);
	  else {
	    int diff = rx_offset + slot_length - frame_length;
1025 1026
	    for (aa=0;aa<UE->frame_parms.nb_antennas_rx;aa++){
	      rescale((int16_t*)&UE->common_vars.rxdata[aa][rx_offset&(~0x3)],
1027
		      slot_length-diff);
1028
	      rescale((int16_t*)&UE->common_vars.rxdata[aa][0],
1029 1030 1031 1032 1033
		      diff);
	    }
	  }
	}
	else {
1034 1035
	    for (aa=0;aa<UE->frame_parms.nb_antennas_rx;aa++){
	      rescale((int16_t*)&UE->common_vars.rxdata[aa][(frame_length+rx_offset)&(~0x3)],
1036
		      -rx_offset);
1037
	      rescale((int16_t*)&UE->common_vars.rxdata[aa][0],
1038 1039 1040 1041
		      slot_length+rx_offset);
	    }
	}
#endif
1042
	*/
1043
        phy_procedures_UE_RX( UE, 0, 0, UE->mode, no_relay, NULL );
1044
      }
1045

1046
      if ((subframe_select( &UE->frame_parms, UE->slot_rx>>1 ) == SF_S) &&
1047
          ((UE->slot_rx&1) == 0)) {
1048
	/*
1049 1050
#ifdef OAI_USRP
	// this does the adjustments of RX signal amplitude to bring into least 12 significant bits
1051
	int slot_length = UE->frame_parms.samples_per_tti>>1;
1052
	int rx_offset = (UE->slot_rx)*slot_length + UE->rx_offset;
1053
	int frame_length = UE->frame_parms.samples_per_tti*10;
1054 1055 1056 1057 1058 1059
	if (rx_offset > frame_length)
	  rx_offset-=frame_length;
	int aa;

	if (rx_offset >= 0) {
	  if (rx_offset + slot_length < frame_length)
1060 1061
	    for (aa=0;aa<UE->frame_parms.nb_antennas_rx;aa++)
	      rescale((int16_t*)&UE->common_vars.rxdata[aa][rx_offset&(~0x3)],
1062 1063 1064
		      slot_length);
	  else {
	    int diff = rx_offset + slot_length - frame_length;
1065 1066
	    for (aa=0;aa<UE->frame_parms.nb_antennas_rx;aa++){
	      rescale((int16_t*)&UE->common_vars.rxdata[aa][rx_offset&(~0x3)],
1067
		      slot_length-diff);
1068
	      rescale((int16_t*)&UE->common_vars.rxdata[aa][0],
1069 1070 1071 1072 1073
		      diff);
	    }
	  }
	}
	else {
1074 1075
	  for (aa=0;aa<UE->frame_parms.nb_antennas_rx;aa++){
	    rescale((int16_t*)&UE->common_vars.rxdata[aa][(frame_length+rx_offset)&(~0x3)],
1076
		    -rx_offset);
1077
	    rescale((int16_t*)&UE->common_vars.rxdata[aa][0],
1078 1079 1080 1081
		    slot_length+rx_offset);
	  }
	}
#endif
1082
	*/
1083
        phy_procedures_UE_RX( UE, 0, 0, UE->mode, no_relay, NULL );
1084 1085
      }

1086
      if ((UE->mac_enabled==1) && (i==0)) {
1087 1088 1089
        ret = mac_xface->ue_scheduler(UE->Mod_id,
                                      UE->frame_tx,
                                      UE->slot_rx>>1,
1090
                                      subframe_select(&UE->frame_parms,UE->slot_tx>>1),
1091 1092 1093 1094
                                      0,
                                      0/*FIXME CC_id*/);

        if (ret == CONNECTION_LOST) {
1095
          LOG_E( PHY, "[UE %"PRIu8"] Frame %"PRIu32", subframe %u RRC Connection lost, returning to PRACH\n",
1096
                 UE->Mod_id, UE->frame_rx, UE->slot_tx>>1 );
1097 1098
          UE->UE_mode[0] = PRACH;
        } else if (ret == PHY_RESYNCH) {
1099
          LOG_E( PHY, "[UE %"PRIu8"] Frame %"PRIu32", subframe %u RRC Connection lost, trying to resynch\n",
1100
                 UE->Mod_id, UE->frame_rx, UE->slot_tx>>1 );
1101 1102
          UE->UE_mode[0] = RESYNCH;
        } else if (ret == PHY_HO_PRACH) {
1103
          LOG_I( PHY, "[UE %"PRIu8"] Frame %"PRIu32", subframe %u, return to PRACH and perform a contention-free access\n",
1104
                 UE->Mod_id, UE->frame_rx, UE->slot_tx>>1 );
1105 1106
          UE->UE_mode[0] = PRACH;
        }
1107
      }
1108 1109 1110

      UE->slot_rx++;

1111 1112
      if (UE->slot_rx == 20) {
        UE->slot_rx = 0;
1113
        UE->frame_rx++;
1114
        VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX_UE, UE->frame_rx );
1115 1116
      }

1117
      VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX_UE, UE->slot_rx>>1 );
1118
    }
1119 1120
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_RX, 0 );

1121
    if (pthread_mutex_lock(&UE->mutex_rx) != 0) {
1122 1123 1124
      LOG_E( PHY, "[SCHED][UE] error locking mutex for UE RX\n" );
      exit_fun("noting to add");
      return &UE_thread_rx_retval;
1125 1126
    }

1127
    UE->instance_cnt_rx--;
1128
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE_INST_CNT_RX, UE->instance_cnt_rx);
1129 1130 1131 1132 1133 1134

    if (pthread_mutex_unlock(&UE->mutex_rx) != 0) {
      LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE RX\n" );
      exit_fun("noting to add");
      return &UE_thread_rx_retval;
    }
1135 1136 1137
  }

  // thread finished
1138
  return &UE_thread_rx_retval;
Florian Kaltenberger's avatar
 
Florian Kaltenberger committed
1139
}
1140

1141 1142 1143



1144

1145 1146 1147 1148
#define RX_OFF_MAX 10
#define RX_OFF_MIN 5
#define RX_OFF_MID ((RX_OFF_MAX+RX_OFF_MIN)/2)

1149 1150 1151 1152 1153 1154 1155 1156 1157
/*!
 * \brief This is the main UE thread.
 * This thread controls the other three UE threads:
 * - UE_thread_rx
 * - UE_thread_tx
 * - UE_thread_synch
 * \param arg unused
 * \returns a pointer to an int. The storage is not on the heap and must not be freed.
 */
1158 1159
void *UE_thread(void *arg)
{
1160 1161 1162
  UNUSED(arg)
  static int UE_thread_retval;
  PHY_VARS_UE *UE = PHY_vars_UE_g[0][0];
1163
  int spp = openair0_cfg[0].samples_per_packet;
1164
  int slot=1, frame=0, hw_subframe=0, rxpos=0, txpos=openair0_cfg[0].tx_scheduling_advance;
1165 1166 1167 1168 1169
#ifdef __AVX2__
  int dummy[2][spp] __attribute__((aligned(32)));
#else
  int dummy[2][spp] __attribute__((aligned(16)));
#endif
1170
  int dummy_dump = 0;
1171 1172
  int tx_enabled = 0;
  int start_rx_stream = 0;
1173 1174
  int rx_off_diff = 0;
  int rx_correction_timer = 0;
1175
  int first_rx = 0;
1176
  RTIME T0;
1177
  unsigned int rxs;
1178 1179 1180

  openair0_timestamp timestamp;

1181 1182 1183 1184
#ifdef NAS_UE
  MessageDef *message_p;
#endif

laurent's avatar
laurent committed
1185
#ifdef DEADLINE_SCHEDULER
1186

1187 1188 1189
  struct sched_attr attr;
  unsigned int flags = 0;

1190 1191 1192
  attr.size = sizeof(attr);
  attr.sched_flags = 0;
  attr.sched_nice = 0;
1193
  attr.sched_priority = 0;//sched_get_priority_max(SCHED_DEADLINE);
1194

1195 1196
  // This creates a .5 ms  reservation
  attr.sched_policy = SCHED_DEADLINE;
1197 1198 1199
  attr.sched_runtime  = 100000;
  attr.sched_deadline = 500000;
  attr.sched_period   = 500000;
1200 1201

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

1209 1210 1211 1212
#else
  struct sched_param sp;
  sp.sched_priority = sched_get_priority_max(SCHED_FIFO);
  pthread_setschedparam(pthread_self(),SCHED_FIFO,&sp);
1213 1214
#endif

1215
  // Lock memory from swapping. This is a process wide call (not constraint to this thread).
1216 1217 1218 1219 1220
  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");
1221

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

1225 1226 1227 1228 1229
  pthread_mutex_unlock(&sync_mutex);
  printf("unlocked sync_mutex, waiting (UE_thread)\n");

  printf("starting UE thread\n");

1230 1231 1232 1233 1234
#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

1235 1236
  T0 = rt_get_time_ns();
  first_rx = 1;
1237
  rxpos=0;
1238

1239
  while (!oai_exit) {
1240 1241
    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 );
1242
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_DUMMY_DUMP, dummy_dump );
1243

1244

1245
    while (rxpos < (1+hw_subframe)*UE->frame_parms.samples_per_tti) {
1246
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 );
1247

1248 1249
#ifndef USRP_DEBUG

1250
      DevAssert( UE->frame_parms.nb_antennas_rx <= 2 );
1251
      void* rxp[2];
1252

1253
      for (int i=0; i<UE->frame_parms.nb_antennas_rx; i++)
1254
        rxp[i] = (dummy_dump==0) ? (void*)&rxdata[i][rxpos] : (void*)dummy[i];
1255 1256 1257 1258
      
      /*      if (dummy_dump == 0)
	      printf("writing %d samples to %d (first_rx %d)\n",spp - ((first_rx==1) ? rx_off_diff : 0),rxpos,first_rx);*/
      
1259 1260 1261 1262 1263
      if (UE->mode != loop_through_memory) {
	rxs = openair0.trx_read_func(&openair0,
				     &timestamp,
				     rxp,
				     spp - ((first_rx==1) ? rx_off_diff : 0),
1264
				     UE->frame_parms.nb_antennas_rx);
1265 1266

	if (rxs != (spp- ((first_rx==1) ? rx_off_diff : 0))) {
1267 1268 1269 1270 1271
	  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;
	  }
1272
	}
1273
      }
1274

1275
      if (rx_off_diff !=0)
1276
	LOG_D(PHY,"frame %d, rx_offset %d, rx_off_diff %d\n",UE->frame_rx,UE->rx_offset,rx_off_diff);
1277

1278
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );
1279

1280
      // Transmit TX buffer based on timestamp from RX
1281
      if ((tx_enabled==1) && (UE->mode!=loop_through_memory)) {
1282
        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 );
1283

1284
        DevAssert( UE->frame_parms.nb_antennas_tx <= 2 );
1285
        void* txp[2];
1286

1287
        for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++)
1288 1289 1290
          txp[i] = (void*)&txdata[i][txpos];

        openair0.trx_write_func(&openair0,
Raymond Knopp's avatar
Raymond Knopp committed
1291
                                (timestamp+openair0_cfg[0].tx_scheduling_advance-openair0_cfg[0].tx_sample_advance),
1292
                                txp,
1293
				spp - ((first_rx==1) ? rx_off_diff : 0),
1294
                                UE->frame_parms.nb_antennas_tx,
1295 1296
                                1);

1297
        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 );
1298
      }
1299 1300
      else if (UE->mode == loop_through_memory)
	rt_sleep_ns(1000000);
1301
#else
1302
      // define USRP_DEBUG is active
1303 1304
      rt_sleep_ns(1000000);
#endif
1305

1306 1307 1308
      rx_off_diff = 0;
      first_rx = 0;

1309 1310 1311
      rxpos += spp;
      txpos += spp;

1312 1313
      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;
1314
    }
1315

1316 1317
    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;
1318

1319 1320
    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 );
1321

1322
      if (start_rx_stream == 1) {
1323
	LOG_D(PHY,"Locking mutex_rx (IC %d)\n",UE->instance_cnt_rx);
1324
        if (pthread_mutex_lock(&UE->mutex_rx) != 0) {
1325
          LOG_E( PHY, "[SCHED][UE] error locking mutex for UE RX thread\n" );
1326
          exit_fun("nothing to add");
1327 1328
          return &UE_thread_retval;
        }
1329

1330
        int instance_cnt_rx = ++UE->instance_cnt_rx;
1331

1332
	LOG_D(PHY,"Unlocking mutex_rx (IC %d)\n",instance_cnt_rx);
1333 1334 1335 1336 1337
        if (pthread_mutex_unlock(&UE->mutex_rx) != 0) {
          LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE RX thread\n" );
          exit_fun("nothing to add");
          return &UE_thread_retval;
        }
1338

1339 1340 1341
	VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE_INST_CNT_RX, instance_cnt_rx);


1342
        if (instance_cnt_rx == 0) {
1343
	  LOG_D(HW,"signalling rx thread to wake up, hw_frame %d, hw_subframe %d (time %lli)\n", frame, hw_subframe, rt_get_time_ns()-T0 );
1344 1345 1346 1347 1348
          if (pthread_cond_signal(&UE->cond_rx) != 0) {
            LOG_E( PHY, "[SCHED][UE] ERROR pthread_cond_signal for UE RX thread\n" );
            exit_fun("nothing to add");
            return &UE_thread_retval;
          }
1349
	  
1350
	  LOG_D(HW,"signalled rx thread to wake up, hw_frame %d, hw_subframe %d (time %lli)\n", frame, hw_subframe, rt_get_time_ns()-T0 );
1351 1352 1353 1354
	  if (UE->mode == loop_through_memory) {
	    printf("Processing subframe %d",UE->slot_rx>>1);
	    getchar();
	  }
1355

1356 1357 1358
          if (UE->mode == rx_calib_ue) {
            if (frame == 10) {
              LOG_D(PHY,
1359
                    "[SCHED][UE] Found cell with N_RB_DL %"PRIu8", PHICH CONFIG (%d,%d), Nid_cell %"PRIu16", NB_ANTENNAS_TX %"PRIu8", frequency offset "PRIi32" Hz, RSSI (digital) %hu dB, measured Gain %d dB, total_rx_gain %"PRIu32" dB, USRP rx gain %f dB\n",
1360 1361 1362 1363 1364 1365 1366 1367
                    UE->frame_parms.N_RB_DL,
                    UE->frame_parms.phich_config_common.phich_duration,
                    UE->frame_parms.phich_config_common.phich_resource,
                    UE->frame_parms.Nid_cell,
                    UE->frame_parms.nb_antennas_tx_eNB,
                    UE->common_vars.freq_offset,
                    UE->measurements.rx_power_avg_dB[0],
                    UE->measurements.rx_power_avg_dB[0] - rx_input_level_dBm,
1368 1369
                    UE->rx_total_gain_dB,
                    openair0_cfg[0].rx_gain[0]
1370
                   );
1371 1372
              exit_fun("[HW][UE] UE in RX calibration mode, exiting");
              return &UE_thread_retval;
1373 1374
            }
          }
1375
        } else {
1376
          LOG_E( PHY, "[SCHED][UE] UE RX thread busy (IC %d)!!\n", instance_cnt_rx);
1377
	  if (instance_cnt_rx > 2) {
1378 1379 1380
	    exit_fun("instance_cnt_rx > 1");
	    return &UE_thread_retval;
	  }
1381 1382
        }

1383 1384
       
        if ((tx_enabled==1)&&(UE->mode != loop_through_memory)) {
1385 1386 1387 1388 1389 1390 1391

	  if (pthread_mutex_lock(&UE->mutex_tx) != 0) {
	    LOG_E( PHY, "[SCHED][UE] error locking mutex for UE TX thread\n" );
	    exit_fun("nothing to add");
	    return &UE_thread_retval;
	  }

1392

1393 1394 1395 1396 1397 1398 1399
          int instance_cnt_tx = ++UE->instance_cnt_tx;

          if (pthread_mutex_unlock(&UE->mutex_tx) != 0) {
            LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE TX thread\n" );
            exit_fun("nothing to add");
            return &UE_thread_retval;
          }
1400 1401
	  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE_INST_CNT_TX, instance_cnt_tx);

1402 1403 1404 1405

          if (instance_cnt_tx == 0) {
            if (pthread_cond_signal(&UE->cond_tx) != 0) {
              LOG_E( PHY, "[SCHED][UE] ERROR pthread_cond_signal for UE TX thread\n" );
1406
              exit_fun("nothing to add");
1407
              return &UE_thread_retval;
1408
            }
1409
	    LOG_D(HW,"signalled tx thread to wake up, hw_frame %d, hw_subframe %d (time %lli)\n", frame, hw_subframe, rt_get_time_ns()-T0 );
1410

1411
          } else {
1412
            LOG_E( PHY, "[SCHED][UE] UE TX thread busy (IC %d)!!\n" );
1413
	    if (instance_cnt_tx>2) {
1414 1415 1416
	      exit_fun("instance_cnt_tx > 1");
	      return &UE_thread_retval;
	    }
1417 1418
          }
        }
1419

1420
      }
1421 1422 1423
    } else {
      // we are not yet synchronized
      if ((hw_subframe == 9) && (dummy_dump == 0)) {
1424 1425
        // Wake up initial synch thread
        if (pthread_mutex_lock(&UE->mutex_synch) != 0) {
1426
          LOG_E( PHY, "[SCHED][UE] error locking mutex for UE initial synch thread\n" );
1427
          exit_fun("nothing to add");
1428 1429
          return &UE_thread_retval;
        }
1430

1431
        int instance_cnt_synch = ++UE->instance_cnt_synch;
1432

1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443
        if (pthread_mutex_unlock(&UE->mutex_synch) != 0) {
          LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE initial synch thread\n" );
          exit_fun("nothing to add");
          return &UE_thread_retval;
        }

        dummy_dump = 1;

        if (instance_cnt_synch == 0) {
          if (pthread_cond_signal(&UE->cond_synch) != 0) {
            LOG_E( PHY, "[SCHED][UE] ERROR pthread_cond_signal for UE sync thread\n" );
1444
            exit_fun("nothing to add");
1445
            return &UE_thread_retval;
1446
          }
1447 1448 1449 1450
        } else {
          LOG_E( PHY, "[SCHED][UE] UE sync thread busy!!\n" );
          exit_fun("nothing to add");
          return &UE_thread_retval;
1451
        }
1452 1453
      }
    }
1454

1455 1456
    hw_subframe++;
    slot+=2;
1457

1458
    if (hw_subframe==10) {
1459 1460 1461 1462
      hw_subframe = 0;
      first_rx = 1;
      frame++;
      slot = 1;
1463

1464 1465 1466
      int fail = pthread_mutex_lock(&UE->mutex_synch);
      int instance_cnt_synch = UE->instance_cnt_synch;
      fail = fail || pthread_mutex_unlock(&UE->mutex_synch);
1467

1468 1469 1470 1471 1472 1473 1474 1475
      if (fail) {
        LOG_E( PHY, "[SCHED][UE] error (un-)locking mutex for UE synch\n" );
        exit_fun("noting to add");
        return &UE_thread_retval;
      }

      if (instance_cnt_synch < 0) {
        // the UE_thread_synch is ready
1476 1477
        if (UE->is_synchronized == 1) {
          rx_off_diff = 0;
1478
          LTE_DL_FRAME_PARMS *frame_parms = &UE->frame_parms; // for macro FRAME_LENGTH_COMPLEX_SAMPLES
1479

1480
	  //	  LOG_I(PHY,"UE->rx_offset %d\n",UE->rx_offset);
1481
          if ((UE->rx_offset > RX_OFF_MAX) && (start_rx_stream == 0)) {
1482 1483 1484
            start_rx_stream=1;
            frame=0;
            // dump ahead in time to start of frame
1485 1486

#ifndef USRP_DEBUG
1487
	    if (UE->mode != loop_through_memory) {
1488
	      LOG_I(PHY,"Resynchronizing RX by %d samples\n",UE->rx_offset);
1489 1490 1491 1492
	      rxs = openair0.trx_read_func(&openair0,
					   &timestamp,
					   (void**)rxdata,
					   UE->rx_offset,
1493
					   UE->frame_parms.nb_antennas_rx);
1494 1495 1496 1497 1498 1499
	      if (rxs != UE->rx_offset) {
		exit_fun("problem in rx");
		return &UE_thread_retval;
	      }
	      UE->rx_offset=0;
	      tx_enabled = 1;
1500
	    }
1501 1502
	    else
	      rt_sleep_ns(1000000);
1503
#else
1504
            rt_sleep_ns(10000000);
1505
#endif
1506

1507 1508 1509 1510
          } else if ((UE->rx_offset<(FRAME_LENGTH_COMPLEX_SAMPLES/2)) &&
		     (UE->rx_offset > RX_OFF_MIN) && 
		     (start_rx_stream==1) && 
		     (rx_correction_timer == 0)) {
1511
            rx_off_diff = -UE->rx_offset + RX_OFF_MIN;
1512
	    LOG_D(PHY,"UE->rx_offset %d > %d, diff %d\n",UE->rx_offset,RX_OFF_MIN,rx_off_diff);
1513
            rx_correction_timer = 5;
1514 1515 1516 1517 1518
          } else if ((UE->rx_offset>(FRAME_LENGTH_COMPLEX_SAMPLES/2)) && 
		     (UE->rx_offset < (FRAME_LENGTH_COMPLEX_SAMPLES-RX_OFF_MIN)) &&
		     (start_rx_stream==1) && 
		     (rx_correction_timer == 0)) {   // moving to the left so drop rx_off_diff samples
            rx_off_diff = FRAME_LENGTH_COMPLEX_SAMPLES - RX_OFF_MIN - UE->rx_offset;
1519
	    LOG_D(PHY,"UE->rx_offset %d < %d, diff %d\n",UE->rx_offset,FRAME_LENGTH_COMPLEX_SAMPLES-RX_OFF_MIN,rx_off_diff);
1520

1521 1522 1523 1524 1525 1526 1527 1528
            rx_correction_timer = 5;
          }

          if (rx_correction_timer>0)
            rx_correction_timer--;
        }

        dummy_dump=0;
1529 1530
      }
    }
1531

1532 1533 1534 1535
#if defined(ENABLE_ITTI)
    itti_update_lte_time(frame, slot);
#endif
  }
1536

1537
  return &UE_thread_retval;
1538 1539 1540 1541
}



1542 1543 1544 1545 1546 1547 1548 1549
/*!
 * \brief Initialize the UE theads.
 * Creates the UE threads:
 * - UE_thread_tx
 * - UE_thread_rx
 * - UE_thread_synch
 * and the locking between them.
 */
1550 1551
void init_UE_threads(void)
{
1552
  PHY_VARS_UE *UE = PHY_vars_UE_g[0][0];
1553

1554 1555 1556 1557 1558 1559 1560 1561
  pthread_attr_init (&attr_UE_thread);
  pthread_attr_setstacksize(&attr_UE_thread,8192);//5*PTHREAD_STACK_MIN);

#ifndef LOWLATENCY
  sched_param_UE_thread.sched_priority = sched_get_priority_max(SCHED_FIFO);
  pthread_attr_setschedparam(&attr_UE_thread,&sched_param_UE_thread);
#endif

1562 1563 1564 1565
  // the threads are not yet active, therefore access is allowed without locking
  UE->instance_cnt_tx = -1;
  UE->instance_cnt_rx = -1;
  UE->instance_cnt_synch = -1;
1566 1567 1568 1569 1570 1571 1572
  pthread_mutex_init(&UE->mutex_tx,NULL);
  pthread_mutex_init(&UE->mutex_rx,NULL);
  pthread_mutex_init(&UE->mutex_synch,NULL);
  pthread_cond_init(&UE->cond_tx,NULL);
  pthread_cond_init(&UE->cond_rx,NULL);
  pthread_cond_init(&UE->cond_synch,NULL);
  pthread_create(&UE->thread_tx,NULL,UE_thread_tx,(void*)UE);
1573
  pthread_setname_np( UE->thread_tx, "UE_thread_tx" );
1574
  pthread_create(&UE->thread_rx,NULL,UE_thread_rx,(void*)UE);
1575 1576 1577
  pthread_setname_np( UE->thread_rx, "UE_thread_rx" );
  pthread_create(&UE->thread_synch,NULL,UE_thread_synch,(void*)UE);
  pthread_setname_np( UE->thread_synch, "UE_thread_synch" );
1578 1579 1580 1581 1582
  UE->frame_tx = 0;
  UE->frame_rx = 0;
}


Raymond Knopp's avatar
 
Raymond Knopp committed
1583
#ifdef OPENAIR2
1584 1585
void fill_ue_band_info(void)
{
1586 1587 1588 1589 1590 1591

  UE_EUTRA_Capability_t *UE_EUTRA_Capability = UE_rrc_inst[0].UECap->UE_EUTRA_Capability;
  int i,j;

  bands_to_scan.nbands = UE_EUTRA_Capability->rf_Parameters.supportedBandListEUTRA.list.count;

1592 1593 1594
  for (i=0; i<bands_to_scan.nbands; i++) {

    for (j=0; j<sizeof (eutra_bands) / sizeof (eutra_bands[0]); j++)
1595
      if (eutra_bands[j].band == UE_EUTRA_Capability->rf_Parameters.supportedBandListEUTRA.list.array[i]->bandEUTRA) {
1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608
        memcpy(&bands_to_scan.band_info[i],
               &eutra_bands[j],
               sizeof(eutra_band_t));

        printf("Band %d (%lu) : DL %u..%u Hz, UL %u..%u Hz, Duplex %s \n",
               bands_to_scan.band_info[i].band,
               UE_EUTRA_Capability->rf_Parameters.supportedBandListEUTRA.list.array[i]->bandEUTRA,
               bands_to_scan.band_info[i].dl_min,
               bands_to_scan.band_info[i].dl_max,
               bands_to_scan.band_info[i].ul_min,
               bands_to_scan.band_info[i].ul_max,
               (bands_to_scan.band_info[i].frame_type==FDD) ? "FDD" : "TDD");
        break;
1609 1610 1611
      }
  }
}
Raymond Knopp's avatar
 
Raymond Knopp committed
1612
#endif
1613 1614 1615 1616 1617 1618

int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, openair0_config_t *openair0_cfg, openair0_rf_map rf_map[MAX_NUM_CCs])
{

  int i, CC_id;
  LTE_DL_FRAME_PARMS *frame_parms;
1619
  
1620
  for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
1621
  if (phy_vars_ue[CC_id]) {
1622
  frame_parms = &(phy_vars_ue[CC_id]->frame_parms);
1623 1624 1625 1626
  } else {
    printf("phy_vars_UE[%d] not initialized\n", CC_id);
    return(-1);
  }
1627

1628
  /*
1629 1630 1631 1632 1633 1634 1635 1636
  if (frame_parms->frame_type == TDD) {
    if (frame_parms->N_RB_DL == 100)
      N_TA_offset = 624;
    else if (frame_parms->N_RB_DL == 50)
      N_TA_offset = 624/2;
    else if (frame_parms->N_RB_DL == 25)
      N_TA_offset = 624/4;
  }
1637
  */
1638

1639
    // replace RX signal buffers with mmaped HW versions
1640 1641 1642 1643 1644
  rxdata = (int32_t**)malloc16( frame_parms->nb_antennas_rx*sizeof(int32_t*) );
  txdata = (int32_t**)malloc16( frame_parms->nb_antennas_tx*sizeof(int32_t*) );

  for (i=0; i<frame_parms->nb_antennas_rx; i++) {
    printf( "Mapping UE CC_id %d, rx_ant %d, freq %u on card %d, chain %d\n", CC_id, i, downlink_frequency[CC_id][i], rf_map[CC_id].card, rf_map[CC_id].chain+i );
1645
    free( phy_vars_ue[CC_id]->common_vars.rxdata[i] );
1646
    rxdata[i] = (int32_t*)malloc16_clear( 307200*sizeof(int32_t) );
1647
    phy_vars_ue[CC_id]->common_vars.rxdata[i] = rxdata[i]; // what about the "-N_TA_offset" ? // N_TA offset for TDD
1648 1649 1650 1651
  }
  
  for (i=0; i<frame_parms->nb_antennas_tx; i++) {
    printf( "Mapping UE CC_id %d, tx_ant %d, freq %u on card %d, chain %d\n", CC_id, i, downlink_frequency[CC_id][i], rf_map[CC_id].card, rf_map[CC_id].chain+i );
1652
    free( phy_vars_ue[CC_id]->common_vars.txdata[i] );
1653
    txdata[i] = (int32_t*)malloc16_clear( 307200*sizeof(int32_t) );
1654
    phy_vars_ue[CC_id]->common_vars.txdata[i] = txdata[i];
1655 1656
  }
  
1657 1658
  // rxdata[x] points now to the same memory region as phy_vars_ue[CC_id]->common_vars.rxdata[x]
  // txdata[x] points now to the same memory region as phy_vars_ue[CC_id]->common_vars.txdata[x]
1659 1660
  // be careful when releasing memory!
  // because no "release_ue_buffers"-function is available, at least rxdata and txdata memory will leak (only some bytes)
1661

1662
  }
1663

1664
  return 0;
1665
}